@truedat/dq 4.49.4 → 4.49.7

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,11 @@
1
1
  # Changelog
2
2
 
3
+ ## [4.49.6] 2022-10-08
4
+
5
+ ### Fixed
6
+
7
+ - [TD-4945] User with permission can save or published on edition
8
+
3
9
  ## [4.48.13] 2022-26-07
4
10
 
5
11
  ### Fixed
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@truedat/dq",
3
- "version": "4.49.4",
3
+ "version": "4.49.7",
4
4
  "description": "Truedat Web Data Quality Module",
5
5
  "sideEffects": false,
6
6
  "jsnext:main": "src/index.js",
@@ -93,8 +93,8 @@
93
93
  },
94
94
  "dependencies": {
95
95
  "@apollo/client": "^3.6.4",
96
- "@truedat/core": "4.49.4",
97
- "@truedat/df": "4.49.4",
96
+ "@truedat/core": "4.49.7",
97
+ "@truedat/df": "4.49.7",
98
98
  "graphql": "^15.5.3",
99
99
  "path-to-regexp": "^1.7.0",
100
100
  "prop-types": "^15.8.1",
@@ -114,5 +114,5 @@
114
114
  "react-dom": ">= 16.8.6 < 17",
115
115
  "semantic-ui-react": ">= 0.88.2 < 2.1"
116
116
  },
117
- "gitHead": "31a5acbf9468f20ff8bdd29c6692adfc2636b460"
117
+ "gitHead": "e57a27c689a1e18026fe5b8a02d9414d5ea70337"
118
118
  }
@@ -248,12 +248,12 @@ export const NewRuleImplementation = ({
248
248
  createRuleImplementation,
249
249
  updateRuleImplementation,
250
250
  edition = false,
251
- rule,
252
251
  ruleImplementationProps,
253
252
  structuresFields,
254
253
  structuresSiblings,
255
254
  operators,
256
255
  implementationType = "",
256
+ rule,
257
257
  }) => {
258
258
  const precalculatedDataset = _.flow(
259
259
  _.propOr([{}], "dataset"),
@@ -315,6 +315,9 @@ export const NewRuleImplementation = ({
315
315
  result_type: ruleImplementationProps.result_type,
316
316
  minimum: ruleImplementationProps.minimum,
317
317
  goal: ruleImplementationProps.goal,
318
+ rule: ruleImplementationProps.rule_id
319
+ ? ruleImplementationProps.rule
320
+ : null,
318
321
  rule_id: ruleImplementationProps.rule_id,
319
322
  domain_id: ruleImplementationProps.domain_id,
320
323
  status: ruleImplementationProps.status,
@@ -341,6 +344,9 @@ export const NewRuleImplementation = ({
341
344
  result_type: "percentage",
342
345
  minimum: null,
343
346
  goal: null,
347
+ rule_id: _.propOr(null, "id")(rule),
348
+ domain_id: _.propOr(null, "domain_id")(rule),
349
+ rule: rule,
344
350
  }
345
351
  );
346
352
 
@@ -477,7 +483,7 @@ export const NewRuleImplementation = ({
477
483
  implementation_type: ruleImplementation.implementationType,
478
484
  df_name: ruleImplementation?.dfName,
479
485
  df_content: ruleImplementation?.dfContent,
480
- rule_id: rule ? rule.id : ruleImplementation.rule_id,
486
+ rule_id: ruleImplementation.rule_id,
481
487
  raw_content: { ...raw_content },
482
488
  result_type: ruleImplementation.result_type,
483
489
  minimum: ruleImplementation.minimum,
@@ -495,7 +501,7 @@ export const NewRuleImplementation = ({
495
501
  implementation_type: ruleImplementation.implementationType,
496
502
  df_name: ruleImplementation?.dfName,
497
503
  df_content: ruleImplementation?.dfContent,
498
- rule_id: rule ? rule.id : ruleImplementation.rule_id,
504
+ rule_id: ruleImplementation.rule_id,
499
505
  result_type: ruleImplementation.result_type,
500
506
  minimum: ruleImplementation.minimum,
501
507
  goal: ruleImplementation.goal,
@@ -577,7 +583,6 @@ NewRuleImplementation.propTypes = {
577
583
  edition: PropTypes.bool,
578
584
  implementationType: PropTypes.string,
579
585
  operators: PropTypes.object,
580
- rule: PropTypes.object,
581
586
  ruleImplementationProps: PropTypes.object,
582
587
  structuresFields: PropTypes.object,
583
588
  structuresSiblings: PropTypes.object,
@@ -126,18 +126,18 @@ export const RuleRoutes = ({
126
126
  exact
127
127
  path={RULE_IMPLEMENTATION_NEW}
128
128
  render={() =>
129
- structuresAliasesLoading || systemsLoading ? null : (
129
+ structuresAliasesLoading || systemsLoading ? null : ruleLoaded ? (
130
130
  <NewRuleImplementation />
131
- )
131
+ ) : null
132
132
  }
133
133
  />
134
134
  <Route
135
135
  exact
136
136
  path={RULE_IMPLEMENTATION_NEW_RAW}
137
137
  render={() =>
138
- structuresAliasesLoading || systemsLoading ? null : (
138
+ structuresAliasesLoading || systemsLoading ? null : ruleLoaded ? (
139
139
  <NewRuleImplementation implementationType="raw" />
140
- )
140
+ ) : null
141
141
  }
142
142
  />
143
143
  </>
@@ -2,6 +2,7 @@ import _ from "lodash/fp";
2
2
  import React from "react";
3
3
  import { waitFor, within } from "@testing-library/react";
4
4
  import { render } from "@truedat/test/render";
5
+ import { DOMAIN_QUERY, DOMAINS_QUERY } from "@truedat/core/api/queries";
5
6
  import { multipleTemplatesMock } from "@truedat/test/mocks";
6
7
  import userEvent from "@testing-library/user-event";
7
8
  import defaultMessages from "@truedat/test/messages";
@@ -14,11 +15,40 @@ import {
14
15
  ruleImplementationLoaderActions,
15
16
  } from "./__fixtures__/newRuleImplementationHelper";
16
17
 
18
+ const domainActions = ["publishImplementation", "manageSegments"];
19
+ const domains = [
20
+ { id: "2", name: "Truedat", parentId: "", actions: domainActions },
21
+ ];
22
+ const requestVariables = {
23
+ action: "manageRulelessImplementations",
24
+ domainActions: domainActions,
25
+ };
26
+ const domainsMock = {
27
+ request: { query: DOMAINS_QUERY, variables: requestVariables },
28
+ result: { data: { domains: domains } },
29
+ };
30
+ const domainMock = {
31
+ request: {
32
+ query: DOMAIN_QUERY,
33
+ variables: { id: 2, actions: ["publishImplementation", "manageSegments"] },
34
+ },
35
+ result: { data: { domain: { id: "2", actions: domainActions } } },
36
+ };
37
+
38
+ const messages = {
39
+ en: { ...defaultMessages.en },
40
+ };
41
+
17
42
  describe("<NewRuleImplementation />", () => {
18
43
  const createRuleImplementation = jest.fn();
19
44
  const updateRuleImplementation = jest.fn();
20
45
 
21
- const ruleImplementationProps = { id: 1, name: "nn", executable: true };
46
+ const ruleImplementationProps = {
47
+ id: 1,
48
+ name: "nn",
49
+ executable: true,
50
+ result_type: "goal",
51
+ };
22
52
 
23
53
  const props = {
24
54
  ruleImplementationProps,
@@ -31,8 +61,11 @@ describe("<NewRuleImplementation />", () => {
31
61
  scope: "ri",
32
62
  domainIds: null,
33
63
  }),
64
+ domainsMock,
65
+ domainMock,
34
66
  ],
35
67
  state: { ruleImplementationCreating: false },
68
+ messages,
36
69
  fallback: "lazy",
37
70
  };
38
71
 
@@ -50,10 +83,8 @@ describe("<NewRuleImplementation />", () => {
50
83
  });
51
84
 
52
85
  it("calculate aliases when not informed", async () => {
53
- const applyTemplate = jest.fn();
54
86
  const props = {
55
87
  ...newRuleImplementationProps,
56
- applyTemplate: applyTemplate,
57
88
  };
58
89
  const { container, queryByText } = render(
59
90
  <NewRuleImplementationComponent {...props} />,
@@ -76,6 +107,8 @@ describe("<NewRuleImplementation> NewRuleImplementation doSubmit", () => {
76
107
  scope: "ri",
77
108
  domainIds: [2],
78
109
  }),
110
+ domainsMock,
111
+ domainMock,
79
112
  ],
80
113
  messages: {
81
114
  en: {
@@ -113,9 +146,9 @@ describe("<NewRuleImplementation> NewRuleImplementation doSubmit", () => {
113
146
  minimum: 80,
114
147
  populations: [],
115
148
  result_type: "percentage",
116
- rule_id: undefined,
149
+ rule_id: null,
117
150
  segments: [],
118
- status: undefined,
151
+ status: "draft",
119
152
  };
120
153
 
121
154
  it("doSubmit: is empty operator", async () => {
@@ -195,6 +228,13 @@ describe("<NewRuleImplementation> NewRuleImplementation doSubmit", () => {
195
228
  within(selectedOperator).queryByText(/is empty/)
196
229
  ).toBeInTheDocument();
197
230
 
231
+ // Segments
232
+
233
+ await waitFor(() => {
234
+ expect(getByRole("button", { name: "Next" })).toBeEnabled();
235
+ });
236
+ userEvent.click(await getByRole("button", { name: "Next" }));
237
+
198
238
  await waitFor(() => {
199
239
  expect(getByRole("button", { name: "Save" })).toBeEnabled();
200
240
  });
@@ -326,6 +366,13 @@ describe("<NewRuleImplementation> NewRuleImplementation doSubmit", () => {
326
366
  []
327
367
  );
328
368
 
369
+ // Segments
370
+
371
+ await waitFor(() => {
372
+ expect(getByRole("button", { name: "Next" })).toBeEnabled();
373
+ });
374
+ userEvent.click(await getByRole("button", { name: "Next" }));
375
+
329
376
  await waitFor(() => {
330
377
  expect(getByRole("button", { name: "Save" })).toBeEnabled();
331
378
  });
@@ -198,6 +198,12 @@ export const newRuleImplementationProps = {
198
198
  },
199
199
  ],
200
200
  rule_id: 631,
201
+ rule: {
202
+ active: true,
203
+ name: "rule_new_engine_dq_postgresql",
204
+ df_name: "dq_default_template",
205
+ df_content: {},
206
+ },
201
207
  validations: [
202
208
  {
203
209
  operator: {
@@ -246,6 +252,7 @@ export const newRuleImplementationProps = {
246
252
  minimum: 20,
247
253
  goal: 10,
248
254
  raw_content: {},
255
+ domain_id: 2,
249
256
  },
250
257
  ruleImplementationRaw: {},
251
258
  sources: [],
@@ -989,7 +989,6 @@ export const ruleImplementationLoaderGlobalState = {
989
989
  ruleImplementationOperators,
990
990
  structuresFields,
991
991
  structuresSiblings,
992
- domains: [{ id: 2, name: "domain1" }],
993
992
  };
994
993
 
995
994
  export const ruleImplementationLoaderActions = {
@@ -29,6 +29,7 @@ exports[`<NewRuleImplementation /> calculate aliases when not informed 1`] = `
29
29
  >
30
30
  <div
31
31
  class="column"
32
+ style="visibility: visible;"
32
33
  >
33
34
  <div
34
35
  class="stretched center aligned row"
@@ -41,7 +42,7 @@ exports[`<NewRuleImplementation /> calculate aliases when not informed 1`] = `
41
42
  >
42
43
  <i
43
44
  aria-hidden="true"
44
- class="info icon"
45
+ class="black info icon"
45
46
  />
46
47
  <div
47
48
  class="content"
@@ -58,7 +59,7 @@ exports[`<NewRuleImplementation /> calculate aliases when not informed 1`] = `
58
59
  >
59
60
  <i
60
61
  aria-hidden="true"
61
- class="database icon"
62
+ class="black database icon"
62
63
  />
63
64
  <div
64
65
  class="content"
@@ -75,7 +76,7 @@ exports[`<NewRuleImplementation /> calculate aliases when not informed 1`] = `
75
76
  >
76
77
  <i
77
78
  aria-hidden="true"
78
- class="user icon"
79
+ class="black user icon"
79
80
  />
80
81
  <div
81
82
  class="content"
@@ -92,7 +93,7 @@ exports[`<NewRuleImplementation /> calculate aliases when not informed 1`] = `
92
93
  >
93
94
  <i
94
95
  aria-hidden="true"
95
- class="setting icon"
96
+ class="black setting icon"
96
97
  />
97
98
  <div
98
99
  class="content"
@@ -104,6 +105,23 @@ exports[`<NewRuleImplementation /> calculate aliases when not informed 1`] = `
104
105
  </div>
105
106
  </div>
106
107
  </div>
108
+ <div
109
+ class="step"
110
+ >
111
+ <i
112
+ aria-hidden="true"
113
+ class="black grid layout icon"
114
+ />
115
+ <div
116
+ class="content"
117
+ >
118
+ <div
119
+ class="title"
120
+ >
121
+ Segments
122
+ </div>
123
+ </div>
124
+ </div>
107
125
  </div>
108
126
  <div
109
127
  class="ui fitted hidden divider"
@@ -305,81 +323,6 @@ exports[`<NewRuleImplementation /> calculate aliases when not informed 1`] = `
305
323
  </div>
306
324
  </div>
307
325
  </div>
308
- <div
309
- class="required field"
310
- >
311
- <label>
312
- Template
313
- <div
314
- class="ui left pointing label"
315
- >
316
- Empty required field
317
- </div>
318
- </label>
319
- <div
320
- class="field"
321
- >
322
- <div
323
- aria-busy="false"
324
- aria-expanded="false"
325
- class="ui search selection dropdown"
326
- name="template"
327
- role="combobox"
328
- >
329
- <input
330
- aria-autocomplete="list"
331
- autocomplete="off"
332
- class="search"
333
- tabindex="0"
334
- type="text"
335
- value=""
336
- />
337
- <div
338
- aria-atomic="true"
339
- aria-live="polite"
340
- class="divider default text"
341
- role="alert"
342
- >
343
- Select a template...
344
- </div>
345
- <i
346
- aria-hidden="true"
347
- class="dropdown icon"
348
- />
349
- <div
350
- class="menu transition"
351
- role="listbox"
352
- >
353
- <div
354
- aria-checked="false"
355
- aria-selected="true"
356
- class="selected item"
357
- role="option"
358
- style="pointer-events: all;"
359
- >
360
- <span
361
- class="text"
362
- >
363
- template1
364
- </span>
365
- </div>
366
- <div
367
- aria-checked="false"
368
- aria-selected="false"
369
- class="item"
370
- role="option"
371
- style="pointer-events: all;"
372
- >
373
- <span
374
- class="text"
375
- >
376
- template2
377
- </span>
378
- </div>
379
- </div>
380
- </div>
381
- </div>
382
- </div>
383
326
  </form>
384
327
  </div>
385
328
  <div
@@ -877,6 +820,7 @@ exports[`<NewRuleImplementation /> matches the latest snapshot 1`] = `
877
820
  >
878
821
  <div
879
822
  class="column"
823
+ style="visibility: visible;"
880
824
  >
881
825
  <div
882
826
  class="stretched center aligned row"
@@ -889,7 +833,7 @@ exports[`<NewRuleImplementation /> matches the latest snapshot 1`] = `
889
833
  >
890
834
  <i
891
835
  aria-hidden="true"
892
- class="info icon"
836
+ class="black info icon"
893
837
  />
894
838
  <div
895
839
  class="content"
@@ -906,7 +850,7 @@ exports[`<NewRuleImplementation /> matches the latest snapshot 1`] = `
906
850
  >
907
851
  <i
908
852
  aria-hidden="true"
909
- class="database icon"
853
+ class="black database icon"
910
854
  />
911
855
  <div
912
856
  class="content"
@@ -923,7 +867,7 @@ exports[`<NewRuleImplementation /> matches the latest snapshot 1`] = `
923
867
  >
924
868
  <i
925
869
  aria-hidden="true"
926
- class="user icon"
870
+ class="black user icon"
927
871
  />
928
872
  <div
929
873
  class="content"
@@ -940,7 +884,7 @@ exports[`<NewRuleImplementation /> matches the latest snapshot 1`] = `
940
884
  >
941
885
  <i
942
886
  aria-hidden="true"
943
- class="setting icon"
887
+ class="black setting icon"
944
888
  />
945
889
  <div
946
890
  class="content"
@@ -952,6 +896,23 @@ exports[`<NewRuleImplementation /> matches the latest snapshot 1`] = `
952
896
  </div>
953
897
  </div>
954
898
  </div>
899
+ <div
900
+ class="disabled step"
901
+ >
902
+ <i
903
+ aria-hidden="true"
904
+ class="grey grid layout icon"
905
+ />
906
+ <div
907
+ class="content"
908
+ >
909
+ <div
910
+ class="title"
911
+ >
912
+ Segments
913
+ </div>
914
+ </div>
915
+ </div>
955
916
  </div>
956
917
  <div
957
918
  class="ui fitted hidden divider"
@@ -1010,52 +971,59 @@ exports[`<NewRuleImplementation /> matches the latest snapshot 1`] = `
1010
971
  </div>
1011
972
  </div>
1012
973
  <div
1013
- class="field"
974
+ class="required field"
1014
975
  >
976
+ <label>
977
+ Domain
978
+ </label>
1015
979
  <div
1016
- class="required field"
980
+ class="field"
1017
981
  >
1018
- <label>
1019
- Domain
1020
- </label>
1021
982
  <div
1022
- class="field"
983
+ aria-expanded="false"
984
+ aria-multiselectable="false"
985
+ class="ui floating dropdown"
986
+ role="listbox"
987
+ tabindex="0"
1023
988
  >
989
+ <label>
990
+ Select a domain...
991
+ </label>
992
+ <i
993
+ aria-hidden="true"
994
+ class="dropdown icon"
995
+ />
1024
996
  <div
1025
- aria-expanded="false"
1026
- class="ui fluid search selection dropdown"
1027
- name="domain"
1028
- role="combobox"
997
+ class="menu transition"
1029
998
  >
1030
- <input
1031
- aria-autocomplete="list"
1032
- autocomplete="off"
1033
- class="search"
1034
- tabindex="0"
1035
- type="text"
1036
- value=""
1037
- />
1038
999
  <div
1039
- aria-atomic="true"
1040
- aria-live="polite"
1041
- class="divider default text"
1042
- role="alert"
1000
+ class="ui left icon input search"
1043
1001
  >
1044
- Select a domain...
1002
+ <input
1003
+ type="text"
1004
+ />
1005
+ <i
1006
+ aria-hidden="true"
1007
+ class="search icon"
1008
+ />
1045
1009
  </div>
1046
- <i
1047
- aria-hidden="true"
1048
- class="dropdown icon"
1049
- />
1050
1010
  <div
1051
- aria-multiselectable="false"
1052
- class="menu transition"
1053
- role="listbox"
1011
+ class="scrolling menu transition"
1054
1012
  >
1055
1013
  <div
1056
- class="message"
1014
+ aria-selected="false"
1015
+ class="item"
1016
+ role="option"
1057
1017
  >
1058
- No results found.
1018
+ <div
1019
+ style="margin-left: 0px;"
1020
+ >
1021
+ <i
1022
+ aria-hidden="true"
1023
+ class="icon"
1024
+ />
1025
+ Truedat
1026
+ </div>
1059
1027
  </div>
1060
1028
  </div>
1061
1029
  </div>
@@ -1,25 +1,32 @@
1
1
  import _ from "lodash/fp";
2
2
  import React from "react";
3
- import { connect } from "react-redux";
4
3
  import PropTypes from "prop-types";
5
4
  import { useIntl, FormattedMessage } from "react-intl";
5
+ import { useQuery } from "@apollo/client";
6
+ import { DOMAIN_QUERY } from "@truedat/core/api/queries";
6
7
  import { Form, Icon, Popup } from "semantic-ui-react";
8
+ import { DomainSelector } from "@truedat/core/components";
7
9
  import LimitsForm from "./LimitsForm";
8
10
 
9
- const DomainDropdownSelector = React.lazy(() =>
10
- import("@truedat/bg/taxonomy/components/DomainDropdownSelector")
11
- );
12
-
13
11
  const SelectableDynamicForm = React.lazy(() =>
14
12
  import("@truedat/df/components/SelectableDynamicForm")
15
13
  );
16
14
 
15
+ const DomainActionsLoader = ({ id, actions, onLoad }) => {
16
+ useQuery(DOMAIN_QUERY, {
17
+ fetchPolicy: "cache-and-network",
18
+ variables: { id, actions },
19
+ onCompleted: onLoad,
20
+ });
21
+ return null;
22
+ };
23
+
17
24
  export const InformationForm = ({
18
25
  setImplementationKey,
19
26
  onChange,
20
27
  ruleImplementation,
21
28
  setIsValid,
22
- rule,
29
+ onDomainsLoad,
23
30
  }) => {
24
31
  const { formatMessage } = useIntl();
25
32
 
@@ -28,7 +35,9 @@ export const InformationForm = ({
28
35
 
29
36
  setIsValid(_.isEmpty(valid));
30
37
  };
31
- const domainId = ruleImplementation?.domain_id || rule?.domain_id;
38
+ const domainId = ruleImplementation?.domain_id;
39
+ const domainActions = ["publishImplementation", "manageSegments"];
40
+
32
41
  return (
33
42
  <>
34
43
  <Form.Radio
@@ -66,14 +75,30 @@ export const InformationForm = ({
66
75
  />
67
76
  </Form.Field>
68
77
 
69
- {_.isEmpty(rule) && !ruleImplementation?.rule_id ? (
70
- <Form.Field>
71
- <DomainDropdownSelector
78
+ {_.isNil(ruleImplementation?.rule_id) ? (
79
+ <Form.Field required={true}>
80
+ <label>
81
+ <FormattedMessage id="quality.domain" />
82
+ </label>
83
+ <DomainSelector
84
+ action={
85
+ ruleImplementation.rule_id
86
+ ? "manageImplementations"
87
+ : "manageRulelessImplementations"
88
+ }
72
89
  value={ruleImplementation.domain_id}
90
+ domainActions={domainActions}
91
+ onLoad={(data) => onDomainsLoad(data.domains)}
73
92
  onChange={(_e, { value }) => onChange("domain_id", value)}
74
93
  />
75
94
  </Form.Field>
76
- ) : null}
95
+ ) : (
96
+ <DomainActionsLoader
97
+ id={domainId}
98
+ actions={domainActions}
99
+ onLoad={(data) => onDomainsLoad([data.domain])}
100
+ />
101
+ )}
77
102
  <LimitsForm onChange={onChange} ruleImplementation={ruleImplementation} />
78
103
  <SelectableDynamicForm
79
104
  scope="ri"
@@ -90,12 +115,10 @@ export const InformationForm = ({
90
115
 
91
116
  InformationForm.propTypes = {
92
117
  onChange: PropTypes.func,
93
- rule: PropTypes.object,
94
118
  ruleImplementation: PropTypes.object,
95
119
  setImplementationKey: PropTypes.func,
96
120
  setIsValid: PropTypes.func,
121
+ onDomainsLoad: PropTypes.func,
97
122
  };
98
123
 
99
- const mapStateToProps = ({ rule }) => ({ rule });
100
-
101
- export default connect(mapStateToProps)(InformationForm);
124
+ export default InformationForm;