@truedat/bg 7.2.0 → 7.2.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 (37) hide show
  1. package/package.json +6 -6
  2. package/src/concepts/components/ConceptCompleteness.js +2 -2
  3. package/src/concepts/components/ConceptCreate.js +3 -3
  4. package/src/concepts/components/ConceptDetails.js +2 -2
  5. package/src/concepts/components/ConceptEdit.js +3 -3
  6. package/src/concepts/components/ConceptsUploadButton.js +1 -1
  7. package/src/concepts/components/__tests__/ConceptCompleteness.spec.js +13 -15
  8. package/src/concepts/components/__tests__/ConceptDetails.spec.js +12 -19
  9. package/src/concepts/components/__tests__/{ConcepEdit.spec.js → ConceptEdit.spec.js} +13 -21
  10. package/src/concepts/components/__tests__/ConceptManageDomain.spec.js +28 -4
  11. package/src/concepts/components/__tests__/__snapshots__/{ConcepEdit.spec.js.snap → ConceptEdit.spec.js.snap} +7 -7
  12. package/src/concepts/components/__tests__/__snapshots__/ConceptForm.spec.js.snap +10 -12
  13. package/src/concepts/components/__tests__/__snapshots__/ConceptManageDomain.spec.js.snap +58 -1
  14. package/src/concepts/components/__tests__/__snapshots__/ConceptsBulkUpdate.spec.js.snap +10 -12
  15. package/src/concepts/components/__tests__/__snapshots__/SharedToForm.spec.js.snap +10 -12
  16. package/src/messages/en.js +2 -0
  17. package/src/messages/es.js +2 -0
  18. package/src/taxonomy/components/Domain.js +11 -71
  19. package/src/taxonomy/components/DomainCards.js +113 -0
  20. package/src/taxonomy/components/DomainContent.js +119 -0
  21. package/src/taxonomy/components/DomainTabs.js +92 -40
  22. package/src/taxonomy/components/Domains.js +144 -25
  23. package/src/taxonomy/components/DomainsActions.js +4 -4
  24. package/src/taxonomy/components/__tests__/Domain.spec.js +127 -2
  25. package/src/taxonomy/components/__tests__/DomainCards.spec.js +148 -0
  26. package/src/taxonomy/components/__tests__/DomainContent.spec.js +168 -0
  27. package/src/taxonomy/components/__tests__/DomainTabs.spec.js +108 -0
  28. package/src/taxonomy/components/__tests__/Domains.spec.js +149 -2
  29. package/src/taxonomy/components/__tests__/DomainsActions.spec.js +15 -8
  30. package/src/taxonomy/components/__tests__/__snapshots__/Domain.spec.js.snap +8 -0
  31. package/src/taxonomy/components/__tests__/__snapshots__/DomainCards.spec.js.snap +291 -0
  32. package/src/taxonomy/components/__tests__/__snapshots__/DomainContent.spec.js.snap +305 -0
  33. package/src/taxonomy/components/__tests__/__snapshots__/DomainTabs.spec.js.snap +40 -0
  34. package/src/taxonomy/components/__tests__/__snapshots__/Domains.spec.js.snap +74 -4
  35. package/src/taxonomy/components/__tests__/__snapshots__/DomainsActions.spec.js.snap +13 -22
  36. package/src/taxonomy/styles/domainCards.less +4 -0
  37. package/src/taxonomy/styles/domains.less +15 -0
@@ -2,37 +2,16 @@ import React from "react";
2
2
  import PropTypes from "prop-types";
3
3
  import { Route, Switch } from "react-router-dom";
4
4
  import { Segment } from "semantic-ui-react";
5
- import { Unauthorized } from "@truedat/core/components";
6
- import { useAuthorized } from "@truedat/core/hooks";
7
- import {
8
- DOMAIN_CONCEPTS,
9
- DOMAIN_IMPLEMENTATIONS,
10
- DOMAIN_MEMBERS,
11
- DOMAIN_MEMBERS_NEW,
12
- DOMAIN_STRUCTURES,
13
- DOMAIN_NEW,
14
- DOMAIN_EDIT,
15
- } from "@truedat/core/routes";
16
- import UserSearchFiltersLoader from "@truedat/dd/components/UserSearchFiltersLoader";
17
- import DomainConcepts from "../../concepts/components/DomainConcepts";
5
+ import { DOMAIN_NEW, DOMAIN_EDIT } from "@truedat/core/routes";
18
6
  import { useDomain } from "../../hooks/useDomains";
19
7
  import DomainDetail from "./DomainDetail";
20
- import DomainImplementations from "./DomainImplementations";
21
- import DomainMembers from "./DomainMembers";
22
- import DomainStructures from "./DomainStructures";
23
8
  import DomainTabs from "./DomainTabs";
24
9
  import EditDomain from "./EditDomain";
25
10
  import NewDomain from "./NewDomain";
26
- import AddDomainMember from "./AddDomainMember";
11
+ import DomainContent from "./DomainContent";
27
12
 
28
- const RolesLoader = React.lazy(() =>
29
- import("@truedat/auth/roles/components/RolesLoader")
30
- );
31
-
32
- export const Domain = ({ domainId }) => {
13
+ export const Domain = ({ domainId, domains, taxonomyConfig }) => {
33
14
  const { data: domain } = useDomain(domainId);
34
- const ddAuthorized = useAuthorized("data_dictionary");
35
- const dqAuthorized = useAuthorized("quality");
36
15
 
37
16
  return domain ? (
38
17
  <Segment>
@@ -49,54 +28,13 @@ export const Domain = ({ domainId }) => {
49
28
  />
50
29
  <>
51
30
  <DomainDetail id={domain.id} />
52
- <DomainTabs domain={domain} />
31
+ <DomainTabs domain={domain} taxonomyConfig={taxonomyConfig} />
53
32
  <Segment attached="bottom">
54
- <Switch>
55
- <Route
56
- exact
57
- path={DOMAIN_CONCEPTS}
58
- render={() => <DomainConcepts domain={domain} />}
59
- />
60
- <Route
61
- exact
62
- path={DOMAIN_STRUCTURES}
63
- render={() =>
64
- ddAuthorized ? (
65
- <DomainStructures domain={domain} />
66
- ) : (
67
- <Unauthorized />
68
- )
69
- }
70
- />
71
- <Route
72
- exact
73
- path={DOMAIN_IMPLEMENTATIONS}
74
- render={() =>
75
- dqAuthorized ? (
76
- <>
77
- <UserSearchFiltersLoader scope="rule_implementation" />
78
- <DomainImplementations domain={domain} />
79
- </>
80
- ) : (
81
- <Unauthorized />
82
- )
83
- }
84
- />
85
- <Route
86
- exact
87
- path={DOMAIN_MEMBERS}
88
- render={() => <DomainMembers domainId={domain.id} />}
89
- />
90
- <Route
91
- path={DOMAIN_MEMBERS_NEW}
92
- render={({ match }) => (
93
- <>
94
- <RolesLoader />
95
- <AddDomainMember id={parseInt(match?.params?.id)} />
96
- </>
97
- )}
98
- />
99
- </Switch>
33
+ <DomainContent
34
+ domain={domain}
35
+ domains={domains}
36
+ taxonomyConfig={taxonomyConfig}
37
+ />
100
38
  </Segment>
101
39
  </>
102
40
  </Switch>
@@ -106,6 +44,8 @@ export const Domain = ({ domainId }) => {
106
44
 
107
45
  Domain.propTypes = {
108
46
  domainId: PropTypes.number,
47
+ domains: PropTypes.array,
48
+ taxonomyConfig: PropTypes.object,
109
49
  };
110
50
 
111
51
  export default Domain;
@@ -0,0 +1,113 @@
1
+ import _ from "lodash/fp";
2
+ import React, { useState } from "react";
3
+ import PropTypes from "prop-types";
4
+ import { Link } from "react-router-dom";
5
+ import { Card, Header, Icon, Message, Input } from "semantic-ui-react";
6
+ import { FormattedMessage, useIntl } from "react-intl";
7
+ import { linkTo } from "@truedat/core/routes";
8
+ import DomainsActions from "./DomainsActions";
9
+
10
+ export const DomainCard = ({
11
+ id,
12
+ name,
13
+ type,
14
+ description,
15
+ childCount,
16
+ domain_group,
17
+ }) => (
18
+ <Card key={id} link as={Link} to={linkTo.DOMAIN({ id })}>
19
+ <Card.Content>
20
+ <Card.Header>
21
+ <Icon name="cube" />
22
+ {name}
23
+ </Card.Header>
24
+ <Card.Meta>
25
+ {_.get("name")(domain_group) && (
26
+ <>
27
+ <Icon name="object group" /> {_.get("name")(domain_group)}
28
+ <br />
29
+ </>
30
+ )}
31
+ <span>{type || <FormattedMessage id="domain" />}</span>
32
+ </Card.Meta>
33
+ </Card.Content>
34
+ <Card.Content description={description} />
35
+ <Card.Content extra>
36
+ <Icon name="cubes" />
37
+ <FormattedMessage
38
+ id="domain.props.children"
39
+ values={{ count: childCount }}
40
+ />
41
+ </Card.Content>
42
+ </Card>
43
+ );
44
+
45
+ DomainCard.propTypes = {
46
+ id: PropTypes.number,
47
+ name: PropTypes.string,
48
+ type: PropTypes.string,
49
+ childCount: PropTypes.number,
50
+ description: PropTypes.string,
51
+ domain_group: PropTypes.object,
52
+ };
53
+
54
+ export const DomainCards = ({ actions, domain, domains }) => {
55
+ const [domainsFilter, setDomainFilter] = useState("");
56
+ const { formatMessage } = useIntl();
57
+
58
+ const domainChildren = _.filter(["parent_id", domain?.id || null])(domains);
59
+ const visibleDomains = _.flow(
60
+ _.map((domain) => {
61
+ const children = _.filter(({ parent_id }) => parent_id == domain.id)(
62
+ domains
63
+ );
64
+ return { childCount: children.length, ...domain };
65
+ }),
66
+ _.filter((domain) =>
67
+ domain.name.toLowerCase().includes(domainsFilter.toLowerCase())
68
+ ),
69
+ _.orderBy("name", "asc")
70
+ )(domainChildren);
71
+ return (
72
+ <>
73
+ <Header as="h4">
74
+ <Header.Content className="taxonomy-domains-domaincards-header-content">
75
+ <div>
76
+ <Input
77
+ icon="search"
78
+ value={domainsFilter}
79
+ placeholder={formatMessage({
80
+ id: "domains.search.placeholder",
81
+ })}
82
+ onChange={(_e, { value }) => setDomainFilter(value)}
83
+ />
84
+ </div>
85
+ {_.isEmpty(domain) ? <DomainsActions actions={actions} /> : null}
86
+ </Header.Content>
87
+ </Header>
88
+
89
+ {_.isEmpty(visibleDomains) && !_.isEmpty(domainChildren) ? (
90
+ <Header as="h4">
91
+ <Icon name="search" />
92
+ <Header.Content>
93
+ <FormattedMessage id="domains.search.results.empty" />
94
+ </Header.Content>
95
+ </Header>
96
+ ) : null}
97
+
98
+ {_.isEmpty(domainChildren) && domain && domain.id ? (
99
+ <Message header={formatMessage({ id: "domain.children.empty" })} />
100
+ ) : null}
101
+
102
+ <Card.Group>{visibleDomains.map(DomainCard)}</Card.Group>
103
+ </>
104
+ );
105
+ };
106
+
107
+ DomainCards.propTypes = {
108
+ actions: PropTypes.object,
109
+ domains: PropTypes.array,
110
+ domain: PropTypes.object,
111
+ };
112
+
113
+ export default DomainCards;
@@ -0,0 +1,119 @@
1
+ import _ from "lodash/fp";
2
+ import React from "react";
3
+ import { Unauthorized } from "@truedat/core/components";
4
+ import { useAuthorized } from "@truedat/core/hooks";
5
+ import UserSearchFiltersLoader from "@truedat/dd/components/UserSearchFiltersLoader";
6
+ import PropTypes from "prop-types";
7
+ import { Route, Switch } from "react-router-dom/cjs/react-router-dom.min";
8
+ import {
9
+ DOMAIN,
10
+ DOMAIN_CONCEPTS,
11
+ DOMAIN_IMPLEMENTATIONS,
12
+ DOMAIN_MEMBERS,
13
+ DOMAIN_MEMBERS_NEW,
14
+ DOMAIN_STRUCTURES,
15
+ DOMAIN_SUBDOMAINS,
16
+ } from "@truedat/core/routes";
17
+ import DomainConcepts from "../../concepts/components/DomainConcepts";
18
+ import DomainCards from "./DomainCards";
19
+ import DomainStructures from "./DomainStructures";
20
+ import DomainImplementations from "./DomainImplementations";
21
+ import DomainMembers from "./DomainMembers";
22
+ import AddDomainMember from "./AddDomainMember";
23
+
24
+ const RolesLoader = React.lazy(() =>
25
+ import("@truedat/auth/roles/components/RolesLoader")
26
+ );
27
+
28
+ const DomainContent = ({
29
+ domain,
30
+ domains,
31
+ taxonomyConfig: { priorityTabs, hiddenTabs },
32
+ }) => {
33
+ const ddAuthorized = useAuthorized("data_dictionary");
34
+ const dqAuthorized = useAuthorized("quality");
35
+
36
+ const routes = [
37
+ {
38
+ key: "subdomains",
39
+ path: DOMAIN_SUBDOMAINS,
40
+ component: <DomainCards domain={domain} domains={domains} />,
41
+ },
42
+ {
43
+ key: "concepts",
44
+ path: DOMAIN_CONCEPTS,
45
+ component: <DomainConcepts domain={domain} />,
46
+ },
47
+ {
48
+ key: "structures",
49
+ path: DOMAIN_STRUCTURES,
50
+ component: ddAuthorized ? (
51
+ <DomainStructures domain={domain} />
52
+ ) : (
53
+ <Unauthorized />
54
+ ),
55
+ },
56
+ {
57
+ key: "implementations",
58
+ path: DOMAIN_IMPLEMENTATIONS,
59
+ component: dqAuthorized ? (
60
+ <>
61
+ <UserSearchFiltersLoader scope="rule_implementation" />
62
+ <DomainImplementations domain={domain} />
63
+ </>
64
+ ) : (
65
+ <Unauthorized />
66
+ ),
67
+ },
68
+ {
69
+ key: "members",
70
+ path: DOMAIN_MEMBERS,
71
+ component: <DomainMembers domainId={domain.id} />,
72
+ },
73
+ {
74
+ key: "members-new",
75
+ path: DOMAIN_MEMBERS_NEW,
76
+ component: (
77
+ <>
78
+ <RolesLoader />
79
+ <AddDomainMember id={parseInt(domain.id)} />
80
+ </>
81
+ ),
82
+ },
83
+ ];
84
+
85
+ const getPaths = ({ key, path }) =>
86
+ _.cond([
87
+ [
88
+ (key) => !_.head(priorityTabs) && key === _.head(routes).key,
89
+ () => [path, DOMAIN],
90
+ ],
91
+ [(key) => key === _.head(priorityTabs), () => [path, DOMAIN]],
92
+ [_.stubTrue, () => path],
93
+ ])(key);
94
+
95
+ return (
96
+ <Switch>
97
+ {_.map((route) =>
98
+ _.includes(route.key, hiddenTabs) && false ? (
99
+ <Unauthorized key={route.key} />
100
+ ) : (
101
+ <Route
102
+ exact
103
+ key={route.key}
104
+ path={getPaths(route)}
105
+ render={() => route.component}
106
+ />
107
+ )
108
+ )(routes)}
109
+ </Switch>
110
+ );
111
+ };
112
+
113
+ DomainContent.propTypes = {
114
+ domain: PropTypes.object,
115
+ domains: PropTypes.array,
116
+ taxonomyConfig: PropTypes.object,
117
+ };
118
+
119
+ export default DomainContent;
@@ -1,3 +1,4 @@
1
+ import _ from "lodash/fp";
1
2
  import React from "react";
2
3
  import PropTypes from "prop-types";
3
4
  import { FormattedMessage } from "react-intl";
@@ -6,67 +7,118 @@ import { Menu } from "semantic-ui-react";
6
7
  import { compile } from "path-to-regexp";
7
8
  import { useAuthorized } from "@truedat/core/hooks";
8
9
  import {
10
+ DOMAIN,
9
11
  DOMAIN_CONCEPTS,
10
12
  DOMAIN_IMPLEMENTATIONS,
11
13
  DOMAIN_MEMBERS,
12
14
  DOMAIN_MEMBERS_NEW,
13
15
  DOMAIN_STRUCTURES,
16
+ DOMAIN_SUBDOMAINS,
14
17
  linkTo,
15
18
  } from "@truedat/core/routes";
16
19
 
17
- const DomainTabs = ({ domain }) => {
20
+ const DomainTabs = ({
21
+ domain,
22
+ taxonomyConfig: { priorityTabs, hiddenTabs },
23
+ }) => {
18
24
  const { pathname: path } = useLocation();
19
25
  const ddAuthorized = useAuthorized("data_dictionary");
20
26
  const dqAuthorized = useAuthorized("quality");
21
27
  const id = domain.id;
22
28
 
29
+ const getPriority = (key) =>
30
+ _.includes(key, priorityTabs)
31
+ ? _.indexOf(key, priorityTabs)
32
+ : priorityTabs.length;
33
+
34
+ const tabs = [
35
+ {
36
+ key: "subdomains",
37
+ priority: getPriority("subdomains"),
38
+ url: DOMAIN_SUBDOMAINS,
39
+ to: linkTo.DOMAIN_SUBDOMAINS({ id }),
40
+ label: "tabs.subdomains",
41
+ },
42
+ {
43
+ key: "concepts",
44
+ priority: getPriority("concepts"),
45
+ url: DOMAIN_CONCEPTS,
46
+ to: linkTo.DOMAIN_CONCEPTS({ id }),
47
+ label: "tabs.concepts",
48
+ },
49
+ {
50
+ key: "structures",
51
+ priority: getPriority("structures"),
52
+ url: DOMAIN_STRUCTURES,
53
+ to: linkTo.DOMAIN_STRUCTURES({ id }),
54
+ label: "tabs.structures",
55
+ },
56
+ {
57
+ key: "implementations",
58
+ priority: getPriority("implementations"),
59
+ url: DOMAIN_IMPLEMENTATIONS,
60
+ to: linkTo.DOMAIN_IMPLEMENTATIONS({ id }),
61
+ label: "tabs.implementations",
62
+ },
63
+ {
64
+ key: "members",
65
+ priority: getPriority("members"),
66
+ url: [DOMAIN_MEMBERS, DOMAIN_MEMBERS_NEW],
67
+ to: linkTo.DOMAIN_MEMBERS({ id }),
68
+ label: "tabs.members",
69
+ },
70
+ ];
71
+
72
+ const setMainTab = (orderedTabs) =>
73
+ _.flow(_.head, _.set("to", linkTo.DOMAIN({ id })), (mainTab) => [
74
+ mainTab,
75
+ ..._.tail(orderedTabs),
76
+ ])(orderedTabs);
77
+
78
+ const orderedTabs = _.flow(
79
+ _.filter((tab) => ddAuthorized || tab.key !== "structures"),
80
+ _.filter((tab) => dqAuthorized || tab.key !== "implementations"),
81
+ _.reject((tab) => hiddenTabs.includes(tab.key)),
82
+ _.sortBy("priority"),
83
+ setMainTab
84
+ )(tabs);
85
+
86
+ const getActived = (key, url, id) => {
87
+ const tabUrls = _.isArray(url) ? url : [url];
88
+
89
+ const maybeAddMain =
90
+ key === _.head(orderedTabs).key
91
+ ? _.concat([compile(DOMAIN)({ id })], tabUrls)
92
+ : tabUrls;
93
+
94
+ return _.flow(
95
+ _.map((url) => compile(url)({ id })),
96
+ _.some((url) => path === url)
97
+ )(maybeAddMain);
98
+ };
99
+
23
100
  return (
24
101
  <Menu attached="top" pointing secondary tabular>
25
- <Menu.Item
26
- active={path === compile(DOMAIN_CONCEPTS)({ id })}
27
- as={Link}
28
- to={linkTo.DOMAIN_CONCEPTS({ id })}
29
- replace
30
- >
31
- <FormattedMessage id="tabs.concepts" />
32
- </Menu.Item>
33
- {ddAuthorized ? (
34
- <Menu.Item
35
- active={path === compile(DOMAIN_STRUCTURES)({ id })}
36
- as={Link}
37
- to={linkTo.DOMAIN_STRUCTURES({ id })}
38
- replace
39
- >
40
- <FormattedMessage id="tabs.structures" />
41
- </Menu.Item>
42
- ) : null}
43
- {dqAuthorized ? (
44
- <Menu.Item
45
- active={path === compile(DOMAIN_IMPLEMENTATIONS)({ id })}
46
- as={Link}
47
- to={linkTo.DOMAIN_IMPLEMENTATIONS({ id })}
48
- replace
49
- >
50
- <FormattedMessage id="tabs.implementations" />
51
- </Menu.Item>
52
- ) : null}
53
- <Menu.Item
54
- active={
55
- path === compile(DOMAIN_MEMBERS)({ id }) ||
56
- path === compile(DOMAIN_MEMBERS_NEW)({ id })
57
- }
58
- as={Link}
59
- to={linkTo.DOMAIN_MEMBERS({ id })}
60
- replace
61
- >
62
- <FormattedMessage id="tabs.members" />
63
- </Menu.Item>
102
+ {_.map(({ key, url, to, label }) => {
103
+ return (
104
+ <Menu.Item
105
+ key={key}
106
+ active={getActived(key, url, id)}
107
+ as={Link}
108
+ to={to}
109
+ replace
110
+ >
111
+ <FormattedMessage id={label} />
112
+ </Menu.Item>
113
+ );
114
+ }, orderedTabs)}
64
115
  </Menu>
65
116
  );
66
117
  };
67
118
 
68
119
  DomainTabs.propTypes = {
69
120
  domain: PropTypes.object,
121
+ taxonomyConfig: PropTypes.object,
70
122
  };
71
123
 
72
124
  export default DomainTabs;