@truedat/df 4.49.9 → 4.50.3

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,12 @@
1
1
  # Changelog
2
2
 
3
+ ## [4.50.3] 2022-08-29
4
+
5
+ ### Changed
6
+
7
+ - [TD-5091] Dynamic `domain` fields are now integer ids instead of embedded
8
+ documents
9
+
3
10
  ## [4.48.5] 2022-07-11
4
11
 
5
12
  ### Changed
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@truedat/df",
3
- "version": "4.49.9",
3
+ "version": "4.50.3",
4
4
  "description": "Truedat Web Data Quality Module",
5
5
  "sideEffects": false,
6
6
  "jsnext:main": "src/index.js",
@@ -87,8 +87,8 @@
87
87
  ]
88
88
  },
89
89
  "dependencies": {
90
- "@truedat/auth": "4.49.9",
91
- "@truedat/core": "4.49.9",
90
+ "@truedat/auth": "4.50.3",
91
+ "@truedat/core": "4.50.3",
92
92
  "path-to-regexp": "^1.7.0",
93
93
  "prop-types": "^15.8.1",
94
94
  "react-color": "^2.17.3",
@@ -106,5 +106,5 @@
106
106
  "react-dom": ">= 16.8.6 < 17",
107
107
  "semantic-ui-react": ">= 0.88.2 < 2.1"
108
108
  },
109
- "gitHead": "45bbf362a6bc6a075d779997b373bd0935cef100"
109
+ "gitHead": "ecf9302d2b22a74d3339a85398788a68e086c428"
110
110
  }
@@ -0,0 +1,19 @@
1
+ import { gql } from "@apollo/client";
2
+
3
+ export const DOMAINS_QUERY = gql`
4
+ query Domains($action: String!) {
5
+ domains(action: $action) {
6
+ id
7
+ name
8
+ }
9
+ }
10
+ `;
11
+
12
+ export const DOMAIN_PREVIEW_QUERY = gql`
13
+ query DomainPreviewQuery($ids: [ID!]!) {
14
+ domains(ids: $ids) {
15
+ id
16
+ name
17
+ }
18
+ }
19
+ `;
@@ -3,6 +3,7 @@ import React from "react";
3
3
  import PropTypes from "prop-types";
4
4
  import { FormattedMessage } from "react-intl";
5
5
  import { Icon, List, Container } from "semantic-ui-react";
6
+ import DomainPreview from "./widgets/DomainPreview";
6
7
  import SystemPreview from "./widgets/SystemPreview";
7
8
  import FieldViewerValue from "./FieldViewerValue";
8
9
  import "../styles/fieldGroupDetail.less";
@@ -30,6 +31,8 @@ export const DynamicFieldValue = ({
30
31
  ) : (
31
32
  <Icon name="minus" color="grey" />
32
33
  )
34
+ ) : type == "domain" ? (
35
+ <DomainPreview domainIds={_.castArray(value)} />
33
36
  ) : _.isArray(value) ? (
34
37
  type == "table" ? (
35
38
  <FieldViewerValue type={type} value={value} values={values} />
@@ -3,6 +3,7 @@ import React, { useState, useEffect } from "react";
3
3
  import PropTypes from "prop-types";
4
4
  import { FormattedMessage } from "react-intl";
5
5
  import { Icon, List, Button, Container } from "semantic-ui-react";
6
+ import DomainPreview from "./widgets/DomainPreview";
6
7
  import SystemPreview from "./widgets/SystemPreview";
7
8
  import DynamicField from "./widgets/DynamicField";
8
9
  import FieldViewerValue from "./FieldViewerValue";
@@ -91,6 +92,8 @@ export const EditableDynamicFieldValue = (props) => {
91
92
  ) : (
92
93
  <Icon name="minus" color="grey" />
93
94
  )
95
+ ) : type == "domain" ? (
96
+ <DomainPreview domainIds={_.castArray(value)} />
94
97
  ) : _.isArray(value) ? (
95
98
  type == "table" ? (
96
99
  <FieldViewerValue type={type} value={value} values={values} />
@@ -3,7 +3,6 @@ import PropTypes from "prop-types";
3
3
  import { useIntl } from "react-intl";
4
4
  import { Icon, Label, Table } from "semantic-ui-react";
5
5
  import { SafeLink, RichTextEditor } from "@truedat/core/components";
6
- import DomainPreview from "./widgets/DomainPreview";
7
6
  import FieldGroupCopy from "./FieldGroupCopy";
8
7
  import ImagePreview from "./widgets/ImagePreview";
9
8
  import SystemPreview from "./widgets/SystemPreview";
@@ -66,16 +65,13 @@ export const FieldViewerValue = ({
66
65
  return <ImagePreview value={value} />;
67
66
  case "system":
68
67
  return <SystemPreview value={value} />;
69
- case "domain":
70
- return <DomainPreview value={value} />;
71
68
  case "copy":
72
69
  return <FieldGroupCopy value={value} />;
73
70
  case "user_group":
74
71
  const [type, name] = value.split(":");
75
72
  return multiple ? (
76
73
  <Label>
77
- <Icon name={type} />
78
- {name}
74
+ <Icon name={type} /> {name}
79
75
  </Label>
80
76
  ) : (
81
77
  <>
@@ -1,5 +1,6 @@
1
1
  import _ from "lodash/fp";
2
2
  import React, { useState } from "react";
3
+ import PropTypes from "prop-types";
3
4
  import { TemplateSelector } from "@truedat/core/components";
4
5
  import { applyTemplate, validateContent } from "@truedat/df/utils";
5
6
  import DynamicForm from "./DynamicForm";
@@ -13,12 +14,14 @@ export default function SelectableDynamicForm({
13
14
  name,
14
15
  onChange,
15
16
  onNameChange,
17
+ placeholder,
18
+ hideLabel,
16
19
  }) {
17
20
  const [template, setTemplate] = useState();
18
21
  const domain = _.size(domainIds) > 0 ? { id: _.head(domainIds) } : null;
19
22
 
20
- const handleChange = (content) => {
21
- onChange({ content, valid: validateContent(template)(content) });
23
+ const handleChange = (content, currentTemplate = template) => {
24
+ onChange({ content, valid: validateContent(currentTemplate)(content) });
22
25
  };
23
26
 
24
27
  const handleLoad = ({ templates }) => {
@@ -30,13 +33,19 @@ export default function SelectableDynamicForm({
30
33
  if (template?.name !== name) {
31
34
  onNameChange(template?.name);
32
35
  }
33
- handleChange(template ? applyTemplate(template)(content, domain?.id) : {});
36
+ handleChange(
37
+ template ? applyTemplate(template)(content, domain?.id) : {},
38
+ template
39
+ );
34
40
  setTemplate(template);
35
41
  };
36
42
 
37
43
  const handleSelected = (_e, { template }) => {
38
44
  onNameChange(template?.name);
39
- handleChange(template ? applyTemplate(template)(content, domain?.id) : {});
45
+ handleChange(
46
+ template ? applyTemplate(template)(content, domain?.id) : {},
47
+ template
48
+ );
40
49
  setTemplate(template);
41
50
  };
42
51
 
@@ -49,6 +58,8 @@ export default function SelectableDynamicForm({
49
58
  selectedValue={template?.id}
50
59
  onChange={handleSelected}
51
60
  onLoad={handleLoad}
61
+ placeholder={placeholder}
62
+ hideLabel={hideLabel}
52
63
  />
53
64
  {template ? (
54
65
  <>
@@ -64,3 +75,16 @@ export default function SelectableDynamicForm({
64
75
  </>
65
76
  );
66
77
  }
78
+
79
+ SelectableDynamicForm.propTypes = {
80
+ domainIds: PropTypes.array,
81
+ scope: PropTypes.string,
82
+ required: PropTypes.bool,
83
+ content: PropTypes.object,
84
+ header: PropTypes.node,
85
+ name: PropTypes.string,
86
+ onChange: PropTypes.func,
87
+ onNameChange: PropTypes.func,
88
+ placeholder: PropTypes.string,
89
+ hideLabel: PropTypes.bool,
90
+ };
@@ -21,10 +21,6 @@ describe("<FieldViewerValue />", () => {
21
21
  value: { id: 1, name: "name" },
22
22
  type: "system",
23
23
  },
24
- {
25
- value: { id: 1, name: "name" },
26
- type: "domain",
27
- },
28
24
  {
29
25
  value: "copy",
30
26
  type: "copy",
@@ -36,20 +36,6 @@ exports[`<FieldViewerValue /> matches the latest snapshot with type: datetime 1`
36
36
  </div>
37
37
  `;
38
38
 
39
- exports[`<FieldViewerValue /> matches the latest snapshot with type: domain 1`] = `
40
- <div>
41
- <div
42
- class="ui label"
43
- >
44
- <a
45
- href="/domains/1"
46
- >
47
- name
48
- </a>
49
- </div>
50
- </div>
51
- `;
52
-
53
39
  exports[`<FieldViewerValue /> matches the latest snapshot with type: image 1`] = `
54
40
  <div>
55
41
  <img
@@ -1,55 +1,54 @@
1
1
  import _ from "lodash/fp";
2
- import React from "react";
2
+ import React, { useState } from "react";
3
3
  import PropTypes from "prop-types";
4
- import { connect } from "react-redux";
5
- import { getDomainSelectorOptions } from "@truedat/bg/selectors";
6
-
7
- const DomainDropdownSelector = React.lazy(() =>
8
- import("@truedat/bg/taxonomy/components/DomainDropdownSelector")
9
- );
10
-
11
- const DomainMenuSelector = React.lazy(() =>
12
- import("@truedat/bg/taxonomy/components/DomainMenuSelector")
13
- );
14
-
15
- const templateValue = (value, options) => {
16
- if (_.isNil(value)) return value;
17
- if (_.isArray(value)) return _.map((id) => _.find({ id })(options))(value);
18
- return _.find({ id: value })(options);
19
- };
20
-
21
- const widgetValue = (value) => {
22
- if (_.isNil(value)) return value;
23
- if (_.isArray(value)) return _.map("id")(value);
24
- return value.id;
4
+ import { Form } from "semantic-ui-react";
5
+ import { DomainSelector } from "@truedat/core/components";
6
+
7
+ const toIntegerId = _.cond([
8
+ [_.isInteger, _.identity],
9
+ [_.eq(""), _.constant(null)],
10
+ [_.isString, _.toInteger],
11
+ [_.conformsTo({ id: _.isInteger }), _.prop("id")],
12
+ [_.conformsTo({ id: _.isString }), _.flow(_.prop("id"), _.toInteger)],
13
+ [_.stubTrue, _.constant(null)],
14
+ ]);
15
+
16
+ const idOrIds = _.cond([
17
+ [_.isArray, _.flow(_.map(toIntegerId), _.reject(_.isNil))],
18
+ [_.stubTrue, toIntegerId],
19
+ ]);
20
+
21
+ const actionsByScope = {
22
+ cx: "manageSource",
23
+ ca: "manageConfiguration",
24
+ bg: "manageConcept",
25
+ dd: "manageNotes",
26
+ dq: "manageRule",
27
+ ie: "manageIngest",
25
28
  };
26
29
 
27
30
  export const DomainDropdown = ({
28
- field: { name, cardinality, value },
31
+ field: { name, cardinality, value: currentValue },
29
32
  onChange,
30
- domainOptions,
33
+ scope,
31
34
  }) => {
32
- const handleChange = (e, data) => {
33
- const value = { name, value: templateValue(data.value, domainOptions) };
34
- onChange(e, value);
35
- };
35
+ const [loading, setLoading] = useState(true);
36
+ const handleLoad = () => setLoading(false);
37
+ const handleChange = (e, { value }) =>
38
+ onChange(e, { name, value: idOrIds(value) });
39
+ const multiple = _.includes(cardinality)(["+", "*"]);
40
+ const action = _.prop(scope)(actionsByScope);
36
41
  return (
37
42
  <>
38
- {_.includes(cardinality)(["1", "?"]) && (
39
- <DomainDropdownSelector
40
- domainOptions={domainOptions}
41
- hideLabel
42
- onChange={handleChange}
43
- value={widgetValue(value)}
44
- />
45
- )}
46
- {_.includes(cardinality)(["+", "*"]) && (
47
- <DomainMenuSelector
48
- domainOptions={domainOptions}
49
- onChange={handleChange}
50
- value={widgetValue(value)}
51
- />
52
- )}
43
+ {loading ? <Form.Input loading /> : null}
44
+ <DomainSelector
45
+ action={action}
46
+ multiple={multiple}
47
+ onChange={handleChange}
48
+ onLoad={handleLoad}
49
+ value={idOrIds(currentValue)}
50
+ labels
51
+ />
53
52
  </>
54
53
  );
55
54
  };
@@ -57,11 +56,7 @@ export const DomainDropdown = ({
57
56
  DomainDropdown.propTypes = {
58
57
  field: PropTypes.object,
59
58
  onChange: PropTypes.func,
60
- domainOptions: PropTypes.array,
59
+ scope: PropTypes.string,
61
60
  };
62
61
 
63
- const mapStateToProps = (state) => ({
64
- domainOptions: getDomainSelectorOptions(state),
65
- });
66
-
67
- export default connect(mapStateToProps)(DomainDropdown);
62
+ export default DomainDropdown;
@@ -1,27 +1,37 @@
1
1
  import _ from "lodash/fp";
2
2
  import React from "react";
3
3
  import PropTypes from "prop-types";
4
+ import { useQuery } from "@apollo/client";
4
5
  import { linkTo } from "@truedat/core/routes";
5
6
  import { Label } from "semantic-ui-react";
6
7
  import { Link } from "react-router-dom";
8
+ import { DOMAIN_PREVIEW_QUERY } from "../../api/queries";
7
9
 
8
- export const DomainPreview = ({ value }) => {
9
- const domains = _.isArray(value) ? value : [value];
10
- return (
11
- <>
12
- {_.map.convert({ cap: false })((domain, i) => (
13
- <Label key={i}>
14
- <Link to={linkTo.DOMAIN({ id: _.prop("id")(domain) })}>
15
- {_.prop("name")(domain)}
16
- </Link>
17
- </Label>
18
- ))(domains)}
19
- </>
10
+ export const DomainPreview = ({ domains }) =>
11
+ _.map(({ id, name }) => (
12
+ <Label key={id}>
13
+ <Link to={linkTo.DOMAIN({ id })}>{name}</Link>
14
+ </Label>
15
+ ))(domains);
16
+
17
+ DomainPreview.propTypes = {
18
+ domains: PropTypes.arrayOf(PropTypes.object).isRequired,
19
+ };
20
+
21
+ export const DomainPreviewLoader = ({ domainIds }) => {
22
+ const { loading, error, data } = useQuery(DOMAIN_PREVIEW_QUERY, {
23
+ variables: { ids: domainIds },
24
+ });
25
+ if (error) return null;
26
+ return loading ? (
27
+ <Label>...</Label>
28
+ ) : (
29
+ <DomainPreview domains={data.domains} />
20
30
  );
21
31
  };
22
32
 
23
- DomainPreview.propTypes = {
24
- value: PropTypes.oneOfType([PropTypes.object, PropTypes.array])
33
+ DomainPreviewLoader.propTypes = {
34
+ domainIds: PropTypes.arrayOf(PropTypes.number).isRequired,
25
35
  };
26
36
 
27
- export default DomainPreview;
37
+ export default DomainPreviewLoader;
@@ -1,36 +1,15 @@
1
- import _ from "lodash/fp";
2
1
  import React from "react";
3
2
  import PropTypes from "prop-types";
4
3
 
5
- const permissions = {
6
- cx: ["manage_data_sources", "show"],
7
- ca: ["manage_configurations", "show"],
8
- bg: ["update_business_concept", "show"],
9
- dd: ["update_data_structure", "show"],
10
- dq: ["manage_quality_rule", "show"],
11
- ie: ["update_ingest", "show"]
12
- };
13
4
  const SystemsLoader = React.lazy(() =>
14
5
  import("@truedat/dd/components/SystemsLoader")
15
6
  );
16
- const DomainsLoader = React.lazy(() =>
17
- import("@truedat/bg/taxonomy/components/DomainsLoader")
18
- );
19
7
 
20
- const getPermissions = scope => _.prop(scope)(permissions);
21
-
22
- export const DropdownDataLoader = ({ scope, type }) => (
23
- <>
24
- {type === "system" && <SystemsLoader />}
25
- {type === "domain" && (
26
- <DomainsLoader actions={getPermissions(scope)} filter="all" />
27
- )}
28
- </>
29
- );
8
+ export const DropdownDataLoader = ({ type }) =>
9
+ type === "system" ? <SystemsLoader /> : null;
30
10
 
31
11
  DropdownDataLoader.propTypes = {
32
- scope: PropTypes.string,
33
- type: PropTypes.string
12
+ type: PropTypes.string,
34
13
  };
35
14
 
36
15
  export default DropdownDataLoader;
@@ -10,24 +10,24 @@ import StandardDropdown from "./StandardDropdown";
10
10
  export const DropdownField = ({ field, loading, onChange, scope }) => {
11
11
  const type = field.type;
12
12
  return (
13
- <>
14
- <DropdownDataLoader scope={scope} type={type} />
15
- <Dimmer.Dimmable dimmed={loading}>
16
- {type === "domain" ? (
17
- <DomainDropdown field={field} onChange={onChange} />
18
- ) : (
13
+ <Dimmer.Dimmable dimmed={loading}>
14
+ {type === "domain" ? (
15
+ <DomainDropdown field={field} onChange={onChange} scope={scope} />
16
+ ) : (
17
+ <>
18
+ <DropdownDataLoader type={type} />
19
19
  <StandardDropdown field={field} onChange={onChange} />
20
- )}
21
- <Dimmer active={loading} inverted>
22
- <Loader />
23
- </Dimmer>
24
- </Dimmer.Dimmable>
25
- </>
20
+ </>
21
+ )}
22
+ <Dimmer active={loading} inverted>
23
+ <Loader />
24
+ </Dimmer>
25
+ </Dimmer.Dimmable>
26
26
  );
27
27
  };
28
28
 
29
29
  DropdownField.propTypes = {
30
- field: PropTypes.object,
30
+ field: PropTypes.object.isRequired,
31
31
  loading: PropTypes.bool,
32
32
  onChange: PropTypes.func,
33
33
  scope: PropTypes.string,
@@ -6,7 +6,7 @@ import { DomainPreview } from "../DomainPreview";
6
6
  // see https://github.com/airbnb/enzyme/issues/2176#issuecomment-532361526
7
7
 
8
8
  describe("<DomainPreview />", () => {
9
- const props = { value: { id: 1, external_id: "external_id" } };
9
+ const props = { domains: [{ id: 1, external_id: "external_id" }] };
10
10
 
11
11
  it("matches the latest snapshot when value is object", () => {
12
12
  const wrapper = shallow(<DomainPreview {...props} />);
@@ -15,10 +15,10 @@ describe("<DomainPreview />", () => {
15
15
 
16
16
  it("matches the latest snapshot when value is array", () => {
17
17
  const props = {
18
- value: [
18
+ domains: [
19
19
  { id: 1, external_id: "external_id", name: "name" },
20
- { id: 2, external_id: "external_id1", name: "name1" }
21
- ]
20
+ { id: 2, external_id: "external_id1", name: "name1" },
21
+ ],
22
22
  };
23
23
  const wrapper = shallow(<DomainPreview {...props} />);
24
24
  expect(wrapper).toMatchSnapshot();
@@ -3,31 +3,13 @@ import { shallow } from "enzyme";
3
3
  import { DropdownDataLoader } from "../DropdownDataLoader";
4
4
 
5
5
  describe("<DropdownDataLoader />", () => {
6
- const scope = "bg";
7
- const type = "domain";
8
6
  const props = {
9
- scope,
10
- type
7
+ scope: "dd",
8
+ type: "system",
11
9
  };
12
10
 
13
- it("matches the latest snapshot when type domain", () => {
14
- const wrapper = shallow(<DropdownDataLoader {...props} />);
15
- expect(wrapper).toMatchSnapshot();
16
- });
17
-
18
11
  it("matches the latest snapshot when type system", () => {
19
- const wrapper = shallow(
20
- <DropdownDataLoader {...{ ...props, type: "system" }} />
21
- );
22
- expect(wrapper).toMatchSnapshot();
23
- });
24
-
25
- it("calls loader with proper props when type is domain", () => {
26
12
  const wrapper = shallow(<DropdownDataLoader {...props} />);
27
- expect(wrapper.find("lazy").prop("filter")).toBe("all");
28
- expect(wrapper.find("lazy").prop("actions")).toEqual([
29
- "update_business_concept",
30
- "show"
31
- ]);
13
+ expect(wrapper).toMatchSnapshot();
32
14
  });
33
15
  });
@@ -1,12 +1,13 @@
1
1
  import _ from "lodash/fp";
2
2
  import React from "react";
3
- import { shallow } from "enzyme";
4
- import { intl } from "@truedat/test/intl-stub";
3
+ import { render } from "@truedat/test/render";
4
+ import { DOMAINS_QUERY } from "@truedat/core/api/queries";
5
+ import defaultMessages from "@truedat/test/messages";
6
+ import { waitFor } from "@testing-library/react";
5
7
  import { DropdownField } from "../DropdownField";
6
8
 
7
9
  // workaround for enzyme issue with React.useContext
8
10
  // see https://github.com/airbnb/enzyme/issues/2176#issuecomment-532361526
9
- jest.spyOn(React, "useContext").mockImplementation(() => intl);
10
11
 
11
12
  describe("<DropdownField />", () => {
12
13
  const label = "label";
@@ -27,83 +28,47 @@ describe("<DropdownField />", () => {
27
28
  options,
28
29
  onChange,
29
30
  scope,
31
+ loading: false,
30
32
  };
31
33
 
32
- it("matches the latest snapshot", () => {
33
- const wrapper = shallow(<DropdownField {...props} />);
34
- expect(wrapper).toMatchSnapshot();
35
- });
36
-
37
- it("matches the latest snapshot when type system", () => {
38
- const field = { ...fieldData, type: "system" };
39
- const wrapper = shallow(<DropdownField {...{ ...props, field }} />);
40
- expect(wrapper).toMatchSnapshot();
41
- });
34
+ const domains = [{ id: "2", name: "Truedat", parentId: "", actions: [] }];
35
+ const domainsMock = {
36
+ request: { query: DOMAINS_QUERY, variables: {} },
37
+ result: { data: { domains: domains } },
38
+ };
42
39
 
43
- it("matches the latest snapshot when type domain", () => {
44
- const field = { ...fieldData, type: "domain" };
45
- const wrapper = shallow(<DropdownField {...{ ...props, field }} />);
46
- expect(wrapper).toMatchSnapshot();
47
- });
40
+ const messages = {
41
+ en: { ...defaultMessages.en },
42
+ };
43
+ const renderOpts = {
44
+ mocks: [domainsMock],
45
+ messages,
46
+ fallback: "lazy",
47
+ };
48
48
 
49
- it("renders loader when type system", () => {
50
- const field = { ...fieldData, type: "system" };
51
- const wrapper = shallow(<DropdownField {...{ ...props, field }} />);
52
- expect(wrapper.find("DropdownDataLoader").prop("type")).toBe("system");
49
+ it("matches the latest snapshot", async () => {
50
+ const { container, queryByText } = render(<DropdownField {...props} />);
51
+ await waitFor(() => expect(queryByText(/lazy/i)).not.toBeInTheDocument());
52
+ expect(container).toMatchSnapshot();
53
53
  });
54
54
 
55
- it("renders loader when type domain", () => {
55
+ it("matches the latest snapshot when type domain", async () => {
56
56
  const field = { ...fieldData, type: "domain" };
57
- const wrapper = shallow(<DropdownField {...{ ...props, field }} />);
58
- expect(wrapper.find("DropdownDataLoader").prop("type")).toBe("domain");
57
+ const { container, queryByText } = render(
58
+ <DropdownField {...{ ...props, field }} />
59
+ );
60
+ await waitFor(() => expect(queryByText(/lazy/i)).not.toBeInTheDocument());
61
+ expect(container).toMatchSnapshot();
59
62
  });
60
63
 
61
- it("renders StandardDropdown when type is system", () => {
64
+ it("renders loader when type system", async () => {
62
65
  const field = { ...fieldData, type: "system" };
63
- const wrapper = shallow(<DropdownField {...{ ...props, field }} />);
64
- expect(wrapper.find("Connect(StandardDropdown)").prop("field")).toEqual(
65
- field
66
+ const { container, queryByText } = render(
67
+ <DropdownField {...{ ...props, field }} />,
68
+ renderOpts
66
69
  );
67
- });
68
70
 
69
- it("renders DomainDropdown when type is domain", () => {
70
- const field = { ...fieldData, type: "domain" };
71
- const wrapper = shallow(<DropdownField {...{ ...props, field }} />);
72
- expect(wrapper.find("Connect(DomainDropdown)").prop("field")).toEqual(
73
- field
74
- );
71
+ await waitFor(() => expect(queryByText(/lazy/i)).not.toBeInTheDocument());
72
+ expect(container).toMatchSnapshot();
75
73
  });
76
-
77
- // it("gives proper dropdown props depending on cardinality and value", () => {
78
- // const wrapper = shallow(<DropdownField {...props} />);
79
- // expect(wrapper.find("FormDropdown").prop("value")).toBe(
80
- // _.prop("value")(fieldData)
81
- // );
82
- // expect(wrapper.find("FormDropdown").prop("multiple")).toBeFalsy();
83
- // expect(wrapper.find("FormDropdown").prop("options")).toEqual([
84
- // { key: 0, text: "selector.no.selection", value: null },
85
- // { key: 1, text: "Foo", value: "Foo" },
86
- // { key: 2, text: "Bar", value: "Bar" }
87
- // ]);
88
-
89
- // const multiple = { ...fieldData, cardinality: "*", value: [{ id: 1 }] };
90
- // wrapper.setProps({ ...props, field: multiple });
91
-
92
- // expect(wrapper.find("FormDropdown").prop("value")).toEqual([{ id: 1 }]);
93
- // expect(wrapper.find("FormDropdown").prop("multiple")).toBeTruthy();
94
- // expect(wrapper.find("FormDropdown").prop("options")).toEqual([
95
- // { key: 0, text: "Foo", value: "Foo" },
96
- // { key: 1, text: "Bar", value: "Bar" }
97
- // ]);
98
-
99
- // const withoutValue = { ...fieldData, cardinality: "*", value: null };
100
- // wrapper.setProps({ ...props, field: withoutValue });
101
-
102
- // expect(wrapper.find("FormDropdown").prop("value")).toEqual([]);
103
- // expect(wrapper.find("FormDropdown").prop("multiple")).toBeTruthy();
104
- // expect(wrapper.find("FormDropdown").prop("options")).toEqual([
105
- // { key: 0, text: "Foo", value: "Foo" },
106
- // { key: 1, text: "Bar", value: "Bar" }
107
- // ]);
108
- // });
109
74
  });
@@ -1,36 +1,34 @@
1
1
  // Jest Snapshot v1, https://goo.gl/fbAQLP
2
2
 
3
3
  exports[`<DomainPreview /> matches the latest snapshot when value is array 1`] = `
4
- <Fragment>
4
+ Array [
5
5
  <Label
6
- key="0"
6
+ key="1"
7
7
  >
8
8
  <Link
9
9
  to="/domains/1"
10
10
  >
11
11
  name
12
12
  </Link>
13
- </Label>
13
+ </Label>,
14
14
  <Label
15
- key="1"
15
+ key="2"
16
16
  >
17
17
  <Link
18
18
  to="/domains/2"
19
19
  >
20
20
  name1
21
21
  </Link>
22
- </Label>
23
- </Fragment>
22
+ </Label>,
23
+ ]
24
24
  `;
25
25
 
26
26
  exports[`<DomainPreview /> matches the latest snapshot when value is object 1`] = `
27
- <Fragment>
28
- <Label
29
- key="0"
30
- >
31
- <Link
32
- to="/domains/1"
33
- />
34
- </Label>
35
- </Fragment>
27
+ <Label
28
+ key="1"
29
+ >
30
+ <Link
31
+ to="/domains/1"
32
+ />
33
+ </Label>
36
34
  `;
@@ -1,21 +1,3 @@
1
1
  // Jest Snapshot v1, https://goo.gl/fbAQLP
2
2
 
3
- exports[`<DropdownDataLoader /> matches the latest snapshot when type domain 1`] = `
4
- <Fragment>
5
- <lazy
6
- actions={
7
- Array [
8
- "update_business_concept",
9
- "show",
10
- ]
11
- }
12
- filter="all"
13
- />
14
- </Fragment>
15
- `;
16
-
17
- exports[`<DropdownDataLoader /> matches the latest snapshot when type system 1`] = `
18
- <Fragment>
19
- <lazy />
20
- </Fragment>
21
- `;
3
+ exports[`<DropdownDataLoader /> matches the latest snapshot when type system 1`] = `<lazy />`;
@@ -1,83 +1,177 @@
1
1
  // Jest Snapshot v1, https://goo.gl/fbAQLP
2
2
 
3
3
  exports[`<DropdownField /> matches the latest snapshot 1`] = `
4
- <Fragment>
5
- <DropdownDataLoader
6
- scope="bg"
7
- />
8
- <DimmerDimmable>
9
- <Connect(StandardDropdown)
10
- field={
11
- Object {
12
- "cardinality": "1",
13
- "label": "label",
14
- "name": "name",
15
- "value": "Foo",
16
- }
17
- }
18
- onChange={[MockFunction]}
19
- />
20
- <Dimmer
21
- inverted={true}
4
+ <div>
5
+ <div
6
+ class="dimmable"
7
+ >
8
+ <div
9
+ class="field"
22
10
  >
23
- <Loader />
24
- </Dimmer>
25
- </DimmerDimmable>
26
- </Fragment>
11
+ <div
12
+ aria-expanded="false"
13
+ class="ui fluid search selection dropdown"
14
+ name="name"
15
+ role="combobox"
16
+ >
17
+ <input
18
+ aria-autocomplete="list"
19
+ autocomplete="off"
20
+ class="search"
21
+ tabindex="0"
22
+ type="text"
23
+ value=""
24
+ />
25
+ <div
26
+ aria-atomic="true"
27
+ aria-live="polite"
28
+ class="divider text"
29
+ role="alert"
30
+ >
31
+ Select one...
32
+ </div>
33
+ <i
34
+ aria-hidden="true"
35
+ class="dropdown icon"
36
+ />
37
+ <div
38
+ aria-multiselectable="false"
39
+ class="menu transition"
40
+ role="listbox"
41
+ >
42
+ <div
43
+ aria-checked="false"
44
+ aria-selected="true"
45
+ class="selected item"
46
+ role="option"
47
+ style="pointer-events: all;"
48
+ >
49
+ <span
50
+ class="text"
51
+ >
52
+ No selection
53
+ </span>
54
+ </div>
55
+ </div>
56
+ </div>
57
+ </div>
58
+ <div
59
+ class="ui inverted dimmer"
60
+ >
61
+ <div
62
+ class="content"
63
+ >
64
+ <div
65
+ class="ui loader"
66
+ />
67
+ </div>
68
+ </div>
69
+ </div>
70
+ </div>
27
71
  `;
28
72
 
29
73
  exports[`<DropdownField /> matches the latest snapshot when type domain 1`] = `
30
- <Fragment>
31
- <DropdownDataLoader
32
- scope="bg"
33
- type="domain"
34
- />
35
- <DimmerDimmable>
36
- <Connect(DomainDropdown)
37
- field={
38
- Object {
39
- "cardinality": "1",
40
- "label": "label",
41
- "name": "name",
42
- "type": "domain",
43
- "value": "Foo",
44
- }
45
- }
46
- onChange={[MockFunction]}
47
- />
48
- <Dimmer
49
- inverted={true}
74
+ <div>
75
+ <div
76
+ class="dimmable"
77
+ >
78
+ <div
79
+ class="field"
80
+ >
81
+ <div
82
+ class="ui loading icon input"
83
+ >
84
+ <input
85
+ type="text"
86
+ />
87
+ <i
88
+ aria-hidden="true"
89
+ class="spinner icon"
90
+ />
91
+ </div>
92
+ </div>
93
+ <div
94
+ class="ui inverted dimmer"
50
95
  >
51
- <Loader />
52
- </Dimmer>
53
- </DimmerDimmable>
54
- </Fragment>
96
+ <div
97
+ class="content"
98
+ >
99
+ <div
100
+ class="ui loader"
101
+ />
102
+ </div>
103
+ </div>
104
+ </div>
105
+ </div>
55
106
  `;
56
107
 
57
- exports[`<DropdownField /> matches the latest snapshot when type system 1`] = `
58
- <Fragment>
59
- <DropdownDataLoader
60
- scope="bg"
61
- type="system"
62
- />
63
- <DimmerDimmable>
64
- <Connect(StandardDropdown)
65
- field={
66
- Object {
67
- "cardinality": "1",
68
- "label": "label",
69
- "name": "name",
70
- "type": "system",
71
- "value": "Foo",
72
- }
73
- }
74
- onChange={[MockFunction]}
75
- />
76
- <Dimmer
77
- inverted={true}
108
+ exports[`<DropdownField /> renders loader when type system 1`] = `
109
+ <div>
110
+ <div
111
+ class="dimmable"
112
+ style=""
113
+ >
114
+ <div
115
+ class="field"
116
+ >
117
+ <div
118
+ aria-expanded="false"
119
+ class="ui fluid search selection dropdown"
120
+ name="name"
121
+ role="combobox"
122
+ >
123
+ <input
124
+ aria-autocomplete="list"
125
+ autocomplete="off"
126
+ class="search"
127
+ tabindex="0"
128
+ type="text"
129
+ value=""
130
+ />
131
+ <div
132
+ aria-atomic="true"
133
+ aria-live="polite"
134
+ class="divider default text"
135
+ role="alert"
136
+ >
137
+ Select one...
138
+ </div>
139
+ <i
140
+ aria-hidden="true"
141
+ class="dropdown icon"
142
+ />
143
+ <div
144
+ aria-multiselectable="false"
145
+ class="menu transition"
146
+ role="listbox"
147
+ >
148
+ <div
149
+ aria-checked="false"
150
+ aria-selected="true"
151
+ class="selected item"
152
+ role="option"
153
+ style="pointer-events: all;"
154
+ >
155
+ <span
156
+ class="text"
157
+ >
158
+ No selection
159
+ </span>
160
+ </div>
161
+ </div>
162
+ </div>
163
+ </div>
164
+ <div
165
+ class="ui inverted dimmer"
78
166
  >
79
- <Loader />
80
- </Dimmer>
81
- </DimmerDimmable>
82
- </Fragment>
167
+ <div
168
+ class="content"
169
+ >
170
+ <div
171
+ class="ui loader"
172
+ />
173
+ </div>
174
+ </div>
175
+ </div>
176
+ </div>
83
177
  `;
@@ -11,26 +11,10 @@ const transformValues = (systems) =>
11
11
  }))
12
12
  )(systems);
13
13
 
14
- const getValuesFromProps = (_state, props) =>
15
- _.path("field.parsedValues")(props);
16
-
17
- const getValuesFromState = (state, _props) => _.pick(["systems"])(state);
18
-
19
- const getType = (_state, props) => _.path("field.type")(props);
20
-
21
- const getOptions = (type, valuesFromProps, valuesFromState) =>
22
- type == "system"
23
- ? transformValues(_.prop("systems")(valuesFromState))
24
- : valuesFromProps;
25
-
26
14
  export const getDropdownOptions = createSelector(
27
- getType,
28
- getValuesFromProps,
29
- getValuesFromState,
30
- (type, valuesFromProps, valuesFromState) => {
31
- const options = getOptions(type, valuesFromProps, valuesFromState);
32
- return _.sortBy("text")(options);
33
- }
15
+ ({ systems }, { field }) =>
16
+ field?.type === "system" ? transformValues(systems) : field?.parsedValues,
17
+ _.sortBy("text")
34
18
  );
35
19
 
36
20
  export const makeGetDropdownOptions = () => getDropdownOptions;
@@ -1,9 +1,10 @@
1
1
  import _ from "lodash/fp";
2
2
  import React from "react";
3
3
  import PropTypes from "prop-types";
4
- import { connect } from "react-redux";
5
- import { Form, List } from "semantic-ui-react";
4
+ import { useQuery } from "@apollo/client";
6
5
  import { useIntl } from "react-intl";
6
+ import { Form, List } from "semantic-ui-react";
7
+ import { DOMAINS_QUERY } from "../../../api/queries";
7
8
  import SwitchSegment from "./SwitchSegment";
8
9
 
9
10
  export const DependentDomain = ({
@@ -13,9 +14,10 @@ export const DependentDomain = ({
13
14
  onChange,
14
15
  onDefaultValueChange,
15
16
  values,
17
+ loading,
16
18
  }) => {
17
19
  const { formatMessage } = useIntl();
18
- const selectedDomains = _.flow(_.keys, _.map(_.toInteger))(values);
20
+ const selectedDomains = _.keys(values);
19
21
  const handleChange = (e, { value }) => onChange({ ...values, [value]: [] });
20
22
 
21
23
  const handleContentChange = (id, contentValues) =>
@@ -31,7 +33,8 @@ export const DependentDomain = ({
31
33
 
32
34
  const options = _.flow(
33
35
  _.reject(({ id }) => _.includes(id)(selectedDomains)),
34
- _.map(({ id, name }) => ({ text: name, value: id }))
36
+ _.map(({ id, name }) => ({ text: name, value: id })),
37
+ _.sortBy("text")
35
38
  )(domains);
36
39
 
37
40
  return (
@@ -54,6 +57,7 @@ export const DependentDomain = ({
54
57
  )(values)}
55
58
  <List.Item>
56
59
  <Form.Dropdown
60
+ loading={loading}
57
61
  selection
58
62
  placeholder={formatMessage({
59
63
  id: "template.field.values.domain_field",
@@ -74,8 +78,21 @@ DependentDomain.propTypes = {
74
78
  onChange: PropTypes.func,
75
79
  onDefaultValueChange: PropTypes.func,
76
80
  values: PropTypes.object,
81
+ loading: PropTypes.bool,
77
82
  };
78
83
 
79
- const mapStateToProps = (state) => ({ domains: state.domains });
84
+ export const DependentDomainLoader = (props) => {
85
+ const { loading, error, data } = useQuery(DOMAINS_QUERY, {
86
+ variables: { action: "viewDomain" },
87
+ });
88
+ if (error) return null;
89
+ return (
90
+ <DependentDomain
91
+ {...props}
92
+ domains={data?.domains || []}
93
+ loading={loading}
94
+ />
95
+ );
96
+ };
80
97
 
81
- export default connect(mapStateToProps)(DependentDomain);
98
+ export default DependentDomainLoader;
@@ -103,6 +103,19 @@ exports[`<DependentDomain /> matches the latest snapshot 1`] = `
103
103
  class="selected item"
104
104
  role="option"
105
105
  style="pointer-events: all;"
106
+ >
107
+ <span
108
+ class="text"
109
+ >
110
+ d1
111
+ </span>
112
+ </div>
113
+ <div
114
+ aria-checked="false"
115
+ aria-selected="false"
116
+ class="item"
117
+ role="option"
118
+ style="pointer-events: all;"
106
119
  >
107
120
  <span
108
121
  class="text"