@truedat/dq 4.38.3 → 4.38.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,13 @@
1
1
  # Changelog
2
2
 
3
+ ## [4.38.7] 2022-02-22
4
+
5
+ ### Added
6
+
7
+ - [TD-4437]
8
+ - Access denied alert message on rule results upload
9
+ - Hide rule results button if there is no manage_rule_results permission
10
+
3
11
  ## [4.37.6] 2022-02-06
4
12
 
5
13
  ### Fix
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@truedat/dq",
3
- "version": "4.38.3",
3
+ "version": "4.38.7",
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.38.3",
34
+ "@truedat/test": "4.38.7",
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.38.3",
86
- "@truedat/df": "4.38.3",
85
+ "@truedat/core": "4.38.7",
86
+ "@truedat/df": "4.38.7",
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": "0ad3a7fe5d8d09b9c5e6e7007d8298748f6677fe"
106
+ "gitHead": "840c799ecdd6b8440112ac803119482e688142ed"
107
107
  }
@@ -8,6 +8,9 @@ import RuleImplementationsLoader from "./RuleImplementationsLoader";
8
8
  const TemplatesLoader = React.lazy(() =>
9
9
  import("@truedat/df/templates/components/TemplatesLoader")
10
10
  );
11
+ const UserDomainsLoader = React.lazy(() =>
12
+ import("@truedat/auth/users/components/UserDomainsLoader")
13
+ );
11
14
  const UserSearchFiltersLoader = React.lazy(() =>
12
15
  import("@truedat/dd/components/UserSearchFiltersLoader")
13
16
  );
@@ -21,6 +24,7 @@ const ImplementationsRoutes = () => (
21
24
  <ImplementationFiltersLoader />
22
25
  <TemplatesLoader scope="qe" />
23
26
  <UserSearchFiltersLoader scope="rule_implementation" />
27
+ <UserDomainsLoader permissions={["manage_rule_results"]} />
24
28
  <RuleImplementations exact />
25
29
  </>
26
30
  )}
@@ -1,4 +1,5 @@
1
- import React from "react";
1
+ import _ from "lodash/fp";
2
+ import React, { useEffect, useState } from "react";
2
3
  import PropTypes from "prop-types";
3
4
  import { connect } from "react-redux";
4
5
  import { Dropdown } from "semantic-ui-react";
@@ -6,18 +7,31 @@ import { useIntl } from "react-intl";
6
7
  import { UploadModal } from "@truedat/core/components";
7
8
  import { uploadResults } from "../routines";
8
9
 
9
- export const RuleResultsUpload = ({ uploadResults, loading }) => {
10
+ export const RuleResultsUpload = ({ uploadResults, loading, userDomains }) => {
10
11
  const { formatMessage } = useIntl();
12
+ const [permissionFound, setPermissionFound] = useState(false);
13
+
14
+ useEffect(() => {
15
+ setPermissionFound(
16
+ !_.flow(
17
+ _.find({ permission: "manage_rule_results" }),
18
+ _.path("domains"),
19
+ _.isEmpty
20
+ )(userDomains)
21
+ );
22
+ }, [userDomains]);
11
23
 
12
24
  return (
13
25
  <UploadModal
14
26
  icon="upload"
15
27
  trigger={
16
- <Dropdown.Item
17
- icon="upload"
18
- text={formatMessage({ id: "ruleResults.actions.upload.tooltip" })}
19
- disabled={loading}
20
- />
28
+ permissionFound ? (
29
+ <Dropdown.Item
30
+ icon="upload"
31
+ text={formatMessage({ id: "ruleResults.actions.upload.tooltip" })}
32
+ disabled={loading}
33
+ />
34
+ ) : null
21
35
  }
22
36
  header={formatMessage({
23
37
  id: "ruleResults.actions.upload.confirmation.header",
@@ -38,10 +52,14 @@ export const RuleResultsUpload = ({ uploadResults, loading }) => {
38
52
  RuleResultsUpload.propTypes = {
39
53
  uploadResults: PropTypes.func,
40
54
  loading: PropTypes.bool,
55
+ userDomains: PropTypes.array,
41
56
  };
42
57
 
43
- const mapStateToProps = ({ uploadingResults }) => ({
44
- loading: uploadingResults,
45
- });
58
+ const mapStateToProps = (state) => {
59
+ return {
60
+ loading: state.uploadingResults,
61
+ userDomains: state.userDomains,
62
+ };
63
+ };
46
64
 
47
65
  export default connect(mapStateToProps, { uploadResults })(RuleResultsUpload);
@@ -1,18 +1,73 @@
1
- import _ from "lodash/fp";
2
1
  import React from "react";
3
- import { shallow } from "enzyme";
4
2
  import { intl } from "@truedat/test/intl-stub";
3
+ import { IntlProvider } from "react-intl";
4
+ import { render } from "@truedat/test/render";
5
+ import { shallow } from "enzyme";
5
6
  import { RuleResultsUpload } from "../RuleResultsUpload";
6
7
 
7
- jest.spyOn(React, "useContext").mockImplementation(() => intl);
8
+ afterEach(() => {
9
+ jest.clearAllMocks();
10
+ });
8
11
 
9
12
  describe("<RuleResultsUpload />", () => {
13
+ const renderOpts = {
14
+ messages: {
15
+ en: {
16
+ "ruleResults.actions.upload.tooltip": "Upload rule results",
17
+ "ruleResults.actions.upload.confirmation.header": "Upload rule results",
18
+ "uploadModal.actions.upload.confirmation.content": "Drag an drop file or click to select file",
19
+ "ruleResults.actions.upload.confirmation.header": "Upload rule results",
20
+ },
21
+ },
22
+ };
23
+
10
24
  it("matches the latest snapshot", () => {
25
+ const spy = jest.spyOn(React, "useContext").mockImplementation(() => intl);
11
26
  const props = {
12
27
  uploadResults: jest.fn(),
13
28
  loading: false,
14
29
  };
15
30
  const wrapper = shallow(<RuleResultsUpload {...props} />);
16
31
  expect(wrapper).toMatchSnapshot();
32
+ spy.mockRestore();
33
+ });
34
+
35
+ it("Renders upload rule results menu item if there is a domain with manage_rule_results permission", () => {
36
+ const props = {
37
+ uploadResults: jest.fn(),
38
+ loading: false,
39
+ userDomains: [
40
+ {
41
+ domains: [
42
+ {
43
+ external_id: "Truedat",
44
+ id: 2,
45
+ name: "Truedat",
46
+ },
47
+ ],
48
+ permission: "manage_rule_results",
49
+ },
50
+ ],
51
+ };
52
+ const { getByText } = render(<RuleResultsUpload {...props} />, renderOpts);
53
+
54
+ const element = getByText("Upload rule results");
55
+ expect(element).toBeInTheDocument()
56
+ });
57
+
58
+ it("Does not render upload rule results menu item if there is no domain with manage_rule_results permission", () => {
59
+ const props = {
60
+ uploadResults: jest.fn(),
61
+ loading: false,
62
+ userDomains: [],
63
+ };
64
+
65
+ const { queryByText } = render(
66
+ <RuleResultsUpload {...props} />,
67
+ renderOpts
68
+ );
69
+
70
+ const element = queryByText("Upload rule results");
71
+ expect(element).toBeNull();
17
72
  });
18
73
  });
@@ -7,12 +7,6 @@ exports[`<RuleResultsUpload /> matches the latest snapshot 1`] = `
7
7
  header="ruleResults.actions.upload.confirmation.header"
8
8
  icon="upload"
9
9
  param="rule_results"
10
- trigger={
11
- <DropdownItem
12
- disabled={false}
13
- icon="upload"
14
- text="ruleResults.actions.upload.tooltip"
15
- />
16
- }
10
+ trigger={null}
17
11
  />
18
12
  `;
@@ -104,7 +104,17 @@ const dqMessage = (state = initialState, { type, payload }) => {
104
104
  text: "",
105
105
  };
106
106
  case uploadResults.FAILURE:
107
- if (payload.status != 500) {
107
+ if (payload.status === 403) {
108
+ return {
109
+ error: true,
110
+ header: `ruleResults.upload.failed.header`,
111
+ messages: [
112
+ { id: "alert.status.403.header" },
113
+ { id: "permission.manage_rule_results" },
114
+ ],
115
+ icon: "attention",
116
+ };
117
+ } else if (payload.status != 500) {
108
118
  return {
109
119
  error: true,
110
120
  header: "ruleResults.upload.failed.header",