@truedat/bg 7.4.1 → 7.4.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.
Files changed (25) hide show
  1. package/package.json +6 -6
  2. package/src/concepts/components/Concept.js +28 -6
  3. package/src/concepts/components/ConceptArchive.js +3 -3
  4. package/src/concepts/components/ConceptArchiveRow.js +3 -3
  5. package/src/concepts/components/ConceptContext.js +37 -0
  6. package/src/concepts/components/__tests__/Concept.spec.js +50 -1
  7. package/src/concepts/components/__tests__/ConceptArchive.spec.js +3 -3
  8. package/src/concepts/components/__tests__/ConceptContext.spec.js +47 -0
  9. package/src/concepts/components/__tests__/__snapshots__/Concept.spec.js.snap +181 -0
  10. package/src/concepts/components/__tests__/__snapshots__/ConceptArchive.spec.js.snap +2 -2
  11. package/src/concepts/components/__tests__/__snapshots__/ConceptArchiveRow.spec.js.snap +1 -7
  12. package/src/concepts/components/__tests__/__snapshots__/ConceptContext.spec.js.snap +9 -0
  13. package/src/concepts/reducers/__tests__/conceptArchive.spec.js +4 -4
  14. package/src/concepts/reducers/concept.js +1 -0
  15. package/src/concepts/reducers/conceptArchive.js +2 -2
  16. package/src/concepts/relations/components/ConceptLinkActions.js +47 -17
  17. package/src/concepts/relations/components/ConceptLinksActions.js +49 -22
  18. package/src/concepts/relations/components/ConceptLinkstRequestGrantButton.js +65 -0
  19. package/src/concepts/relations/components/ConceptStructureLinks.js +92 -9
  20. package/src/concepts/relations/components/__tests__/ConceptLinksActions.spec.js +65 -0
  21. package/src/concepts/relations/components/__tests__/ConceptLinkstRequestGrantButton.spec.js +37 -0
  22. package/src/concepts/relations/components/__tests__/ConceptStructureLinks.spec.js +82 -6
  23. package/src/concepts/relations/components/__tests__/__snapshots__/ConceptLinksActions.spec.js.snap +61 -0
  24. package/src/concepts/relations/components/__tests__/__snapshots__/ConceptLinkstRequestGrantButton.spec.js.snap +16 -0
  25. package/src/concepts/relations/components/__tests__/__snapshots__/ConceptStructureLinks.spec.js.snap +193 -28
@@ -1,37 +1,64 @@
1
1
  import _ from "lodash/fp";
2
2
  import React from "react";
3
3
  import PropTypes from "prop-types";
4
+ import { useIntl } from "react-intl";
4
5
  import { connect } from "react-redux";
5
6
  import { Button } from "semantic-ui-react";
6
7
  import { Link } from "react-router-dom";
7
- import { FormattedMessage } from "react-intl";
8
8
  import { linkTo } from "@truedat/core/routes";
9
+ import { Checkbox } from "semantic-ui-react";
9
10
 
10
- export const ConceptLinksActions = ({ createLinkUrl }) =>
11
- createLinkUrl ? (
12
- <Button
13
- primary
14
- floated="right"
15
- as={Link}
16
- to={createLinkUrl}
17
- content={<FormattedMessage id="links.actions.create" />}
18
- />
11
+ import ConceptLinkstRequestGrantButton from "./ConceptLinkstRequestGrantButton";
12
+
13
+ export const ConceptLinksActions = ({
14
+ canManageGrantRequests,
15
+ createLinkUrl,
16
+ grantView,
17
+ onGrantViewChange,
18
+ }) => {
19
+ const { formatMessage } = useIntl();
20
+
21
+ return createLinkUrl ? (
22
+ <div style={{ float: "right" }}>
23
+ {canManageGrantRequests ? (
24
+ <React.Fragment>
25
+ <Checkbox
26
+ id="execute_checkbox"
27
+ className="bgOrange"
28
+ toggle
29
+ checked={grantView}
30
+ onChange={() => onGrantViewChange(!grantView)}
31
+ style={{ top: "6px", marginRight: "7.5px" }}
32
+ />
33
+ <ConceptLinkstRequestGrantButton disabled={!grantView} />
34
+ </React.Fragment>
35
+ ) : null}
36
+ <Button
37
+ primary
38
+ as={Link}
39
+ to={createLinkUrl}
40
+ content={formatMessage({ id: "links.actions.create" })}
41
+ />
42
+ </div>
19
43
  ) : null;
44
+ };
20
45
 
21
46
  ConceptLinksActions.propTypes = {
22
- createLinkUrl: PropTypes.string
47
+ canManageGrantRequests: PropTypes.bool,
48
+ createLinkUrl: PropTypes.string,
49
+ grantView: PropTypes.bool,
50
+ onGrantViewChange: PropTypes.func,
23
51
  };
24
52
 
25
- const mapStateToProps = ({
26
- conceptActions,
27
- conceptActionLoading,
28
- concept
29
- }) => ({
30
- createLinkUrl:
31
- _.has("create_structure_link")(conceptActions) && _.has("id")(concept)
32
- ? linkTo.CONCEPT_LINKS_STRUCTURES_NEW(concept)
33
- : null,
34
- conceptActionLoading
35
- });
53
+ const mapStateToProps = ({ conceptActions, conceptActionLoading, concept }) => {
54
+ return {
55
+ createLinkUrl:
56
+ _.has("create_structure_link")(conceptActions) && _.has("id")(concept)
57
+ ? linkTo.CONCEPT_LINKS_STRUCTURES_NEW(concept)
58
+ : null,
59
+ conceptActionLoading,
60
+ canManageGrantRequests: concept.actions?.manage_grant_requests,
61
+ };
62
+ };
36
63
 
37
64
  export default connect(mapStateToProps)(ConceptLinksActions);
@@ -0,0 +1,65 @@
1
+ import _ from "lodash/fp";
2
+ import React from "react";
3
+ import PropTypes from "prop-types";
4
+ import { useIntl } from "react-intl";
5
+ import { connect } from "react-redux";
6
+ import { Button } from "semantic-ui-react";
7
+ import { useSearchContext } from "@truedat/core/search/SearchContext";
8
+ import { addGrantRequestToCart } from "@truedat/dd/routines";
9
+
10
+ export const ConceptLinkstRequestGrantButton = ({
11
+ disabled,
12
+ addGrantRequestToCart,
13
+ requested,
14
+ }) => {
15
+ const { formatMessage } = useIntl();
16
+ const { searchData } = useSearchContext();
17
+ const structures = searchData?.data;
18
+
19
+ const requestAllStructures = () => {
20
+ _.forEach((structure) => {
21
+ const authorizedRequest = _.pathOr(
22
+ false,
23
+ "request_grant"
24
+ )(structure.user_permissions);
25
+
26
+ const isRequested = _.flow(
27
+ _.find({ id: `${structure.id}` }),
28
+ _.negate(_.isUndefined)
29
+ )(requested);
30
+
31
+ const granted = _.has("my_grant_request")(structure);
32
+
33
+ if (authorizedRequest && !isRequested && !granted)
34
+ addGrantRequestToCart({
35
+ ...structure,
36
+ id: `${structure.id}`,
37
+ });
38
+ })(structures);
39
+ };
40
+
41
+ return (
42
+ <Button
43
+ secondary
44
+ icon="shield"
45
+ title={formatMessage({ id: "links.actions.grant_request.tooltip" })}
46
+ disabled={disabled}
47
+ content={formatMessage({ id: "links.actions.grant_request" })}
48
+ onClick={requestAllStructures}
49
+ />
50
+ );
51
+ };
52
+
53
+ ConceptLinkstRequestGrantButton.propTypes = {
54
+ disabled: PropTypes.bool,
55
+ addGrantRequestToCart: PropTypes.func,
56
+ requested: PropTypes.arrayOf(PropTypes.object),
57
+ };
58
+
59
+ const mapStateToProps = ({ grantRequestsCart }) => ({
60
+ requested: _.pathOr([], "structures")(grantRequestsCart),
61
+ });
62
+
63
+ export default connect(mapStateToProps, { addGrantRequestToCart })(
64
+ ConceptLinkstRequestGrantButton
65
+ );
@@ -2,26 +2,109 @@ import _ from "lodash/fp";
2
2
  import React from "react";
3
3
  import PropTypes from "prop-types";
4
4
  import { connect } from "react-redux";
5
- import { Segment } from "semantic-ui-react";
5
+ import { Segment, Grid } from "semantic-ui-react";
6
+ import {
7
+ useDataStructureFilters,
8
+ useDataStructureSearch,
9
+ } from "@truedat/dd/hooks/useStructures";
10
+ import translations from "@truedat/dd/utils/structureCustomTranslations";
11
+ import StructuresSearchResults from "@truedat/dd/components/StructuresSearchResults";
12
+ import {
13
+ SearchContextProvider,
14
+ useSearchContext,
15
+ } from "@truedat/core/search/SearchContext";
6
16
  import { getConceptLinks } from "../selectors";
17
+ import { useConceptContext } from "../../components/ConceptContext";
7
18
  import ConceptLinksActions from "./ConceptLinksActions";
8
19
 
9
20
  const LinksPane = React.lazy(() => import("@truedat/lm/components/LinksPane"));
10
21
 
11
- export const ConceptStructureLinksPane = ({ groups, visible }) => {
12
- const LinksActions = visible ? <ConceptLinksActions /> : null;
22
+ const ConceptStructureLinksSegment = ({ groups, visible }) => {
23
+ const { conceptContext, setConceptContextProperty } = useConceptContext();
24
+ const { searchData, loading } = useSearchContext();
25
+ const structures = searchData?.data;
26
+
27
+ const { grantView } = conceptContext;
28
+
29
+ const onGrantViewChange = (grantViewNewState) =>
30
+ setConceptContextProperty({ grantView: grantViewNewState });
31
+
32
+ const LinksActions = visible ? (
33
+ <ConceptLinksActions
34
+ grantView={grantView}
35
+ onGrantViewChange={onGrantViewChange}
36
+ />
37
+ ) : null;
38
+
13
39
  return (
14
40
  <Segment attached="bottom">
15
- <LinksPane
16
- groups={groups}
17
- sourceType="concept"
18
- targetType="structure"
19
- linksActions={LinksActions}
20
- />
41
+ {grantView ? (
42
+ <Grid>
43
+ <Grid.Row>
44
+ <Grid.Column>{LinksActions}</Grid.Column>
45
+ </Grid.Row>
46
+ <Grid.Row>
47
+ <Grid.Column>
48
+ <StructuresSearchResults
49
+ structures={structures}
50
+ loading={loading}
51
+ grantable
52
+ />
53
+ </Grid.Column>
54
+ </Grid.Row>
55
+ </Grid>
56
+ ) : (
57
+ <LinksPane
58
+ groups={groups}
59
+ sourceType="concept"
60
+ targetType="structure"
61
+ linksActions={LinksActions}
62
+ />
63
+ )}
21
64
  </Segment>
22
65
  );
23
66
  };
24
67
 
68
+ ConceptStructureLinksSegment.propTypes = {
69
+ groups: PropTypes.array,
70
+ visible: PropTypes.bool,
71
+ };
72
+
73
+ export const ConceptStructureLinksPane = ({ groups, visible }) => {
74
+ const structures_ids = _.flow(
75
+ _.flatMap(([_columns, [_tag, links]]) => links),
76
+ _.map(({ resource_id }) => parseInt(resource_id))
77
+ )(groups);
78
+
79
+ const enrichSearchPayload = {
80
+ my_grant_requests: true,
81
+ with_data_fields: false,
82
+ };
83
+
84
+ const searchProps = {
85
+ initialSortColumn: "name.raw",
86
+ initialSortDirection: "ascending",
87
+ useSearch: useDataStructureSearch,
88
+ useFilters: useDataStructureFilters,
89
+ pageSize: 20,
90
+ userFiltersType: "user_search_filters",
91
+ userFilterScope: "data_structure",
92
+ translations,
93
+ filtersGroup: [],
94
+ defaultFilters: {
95
+ exists: { field: "classes._grantable" },
96
+ ids: structures_ids,
97
+ },
98
+ enrichSearchPayload,
99
+ };
100
+
101
+ return (
102
+ <SearchContextProvider {...searchProps}>
103
+ <ConceptStructureLinksSegment groups={groups} visible={visible} />
104
+ </SearchContextProvider>
105
+ );
106
+ };
107
+
25
108
  ConceptStructureLinksPane.propTypes = {
26
109
  groups: PropTypes.array,
27
110
  visible: PropTypes.bool,
@@ -0,0 +1,65 @@
1
+ import React from "react";
2
+ import { render } from "@truedat/test/render";
3
+ import { useSearchContext } from "@truedat/core/search/SearchContext";
4
+ import ConceptLinksActions from "../ConceptLinksActions";
5
+
6
+ jest.mock("@truedat/core/search/SearchContext", () => {
7
+ const originalModule = jest.requireActual(
8
+ "@truedat/core/search/SearchContext"
9
+ );
10
+
11
+ return {
12
+ __esModule: true,
13
+ ...originalModule,
14
+ useSearchContext: jest.fn(),
15
+ };
16
+ });
17
+
18
+ const renderOpts = {
19
+ state: {
20
+ conceptActions: {
21
+ create_structure_link: true,
22
+ },
23
+ concept: {
24
+ id: 1,
25
+ business_concept_id: 11,
26
+ },
27
+ },
28
+ };
29
+
30
+ describe("<ConceptLinksActions />", () => {
31
+ it("matches the latest snapshot with Grant Requests permission", () => {
32
+ useSearchContext.mockReturnValue({ searchData: [] });
33
+
34
+ const grRenderOpts = {
35
+ ...renderOpts,
36
+ state: {
37
+ ...renderOpts.state,
38
+ concept: {
39
+ ...renderOpts.state.concept,
40
+ actions: {
41
+ manage_grant_requests: {},
42
+ },
43
+ },
44
+ },
45
+ };
46
+
47
+ const { container } = render(
48
+ <ConceptLinksActions onGrantViewChange={jest.fn()} />,
49
+ grRenderOpts
50
+ );
51
+
52
+ expect(container).toMatchSnapshot();
53
+ });
54
+
55
+ it("matches the latest snapshot without Grant Requests permission", () => {
56
+ useSearchContext.mockReturnValue({ searchData: [] });
57
+
58
+ const { container } = render(
59
+ <ConceptLinksActions onGrantViewChange={jest.fn()} />,
60
+ renderOpts
61
+ );
62
+
63
+ expect(container).toMatchSnapshot();
64
+ });
65
+ });
@@ -0,0 +1,37 @@
1
+ import React from "react";
2
+ import { render } from "@truedat/test/render";
3
+ import { useSearchContext } from "@truedat/core/search/SearchContext";
4
+ import ConceptLinkstRequestGrantButton from "../ConceptLinkstRequestGrantButton";
5
+
6
+ jest.mock("@truedat/core/search/SearchContext", () => {
7
+ const originalModule = jest.requireActual(
8
+ "@truedat/core/search/SearchContext"
9
+ );
10
+
11
+ return {
12
+ __esModule: true,
13
+ ...originalModule,
14
+ useSearchContext: jest.fn(),
15
+ };
16
+ });
17
+
18
+ const renderOpts = {
19
+ state: {
20
+ grantRequestsCart: {
21
+ structures: [],
22
+ },
23
+ },
24
+ };
25
+
26
+ describe("<ConceptLinkstRequestGrantButton />", () => {
27
+ it("matches the latest snapshot", () => {
28
+ useSearchContext.mockReturnValue({ searchData: [] });
29
+
30
+ const { container } = render(
31
+ <ConceptLinkstRequestGrantButton onGrantViewChange={jest.fn()} />,
32
+ renderOpts
33
+ );
34
+
35
+ expect(container).toMatchSnapshot();
36
+ });
37
+ });
@@ -1,15 +1,91 @@
1
1
  import _ from "lodash/fp";
2
- import React from "react";
3
- import { shallow } from "enzyme";
2
+ import React, { Suspense } from "react";
3
+ import { render } from "@truedat/test/render";
4
+ import { useSearchContext } from "@truedat/core/search/SearchContext";
4
5
  import { ConceptStructureLinksPane } from "../ConceptStructureLinks";
5
6
 
7
+ import { useConceptContext } from "../../../components/ConceptContext";
8
+
9
+ jest.mock("../../../components/ConceptContext", () => {
10
+ const originalModule = jest.requireActual(
11
+ "../../../components/ConceptContext"
12
+ );
13
+
14
+ return {
15
+ __esModule: true,
16
+ ...originalModule,
17
+ useConceptContext: jest.fn(),
18
+ };
19
+ });
20
+
21
+ jest.mock("@truedat/core/search/SearchContext", () => {
22
+ const originalModule = jest.requireActual(
23
+ "@truedat/core/search/SearchContext"
24
+ );
25
+
26
+ return {
27
+ __esModule: true,
28
+ ...originalModule,
29
+ useSearchContext: jest.fn(),
30
+ };
31
+ });
32
+
33
+ beforeAll(() => {
34
+ jest.useFakeTimers();
35
+ jest.setSystemTime(new Date("2025-01-01T10:00:00Z"));
36
+ });
37
+
38
+ afterAll(() => {
39
+ jest.useRealTimers();
40
+ });
41
+
6
42
  describe("<ConceptStructureLinksPane />", () => {
7
43
  const props = {
8
- groups: [[[{ name: "name" }], ["group", [{ name: "foo" }]]]]
44
+ groups: [[[{ name: "name" }], ["group", [{ name: "foo" }]]]],
9
45
  };
10
46
 
11
- it("matches the latest snapshot", () => {
12
- const wrapper = shallow(<ConceptStructureLinksPane {...props} />);
13
- expect(wrapper).toMatchSnapshot();
47
+ it("matches the latest snapshot", async () => {
48
+ useConceptContext.mockReturnValue({
49
+ conceptContext: { grantView: false },
50
+ });
51
+ useSearchContext.mockReturnValue({
52
+ searchData: [],
53
+ });
54
+
55
+ const { container, findByText } = render(
56
+ <Suspense fallback={null}>
57
+ <ConceptStructureLinksPane {...props} />
58
+ </Suspense>
59
+ );
60
+
61
+ await findByText("Links to Structures");
62
+
63
+ expect(container).toMatchSnapshot();
64
+ });
65
+
66
+ it("matches the latest snapshot with grantView", async () => {
67
+ useConceptContext.mockReturnValue({
68
+ conceptContext: { grantView: true },
69
+ });
70
+ useSearchContext.mockReturnValue({
71
+ searchData: {
72
+ data: [
73
+ {
74
+ id: 1,
75
+ name: "test structure",
76
+ type: "Data Base",
77
+ group: "test",
78
+ system: { name: "System_Test" },
79
+ path: ["path", "to", "structure"],
80
+ updated_at: "2024-02-26 10:30:29.909476Z",
81
+ },
82
+ ],
83
+ },
84
+ loading: false,
85
+ });
86
+
87
+ const { container } = render(<ConceptStructureLinksPane {...props} />);
88
+
89
+ expect(container).toMatchSnapshot();
14
90
  });
15
91
  });
@@ -0,0 +1,61 @@
1
+ // Jest Snapshot v1, https://goo.gl/fbAQLP
2
+
3
+ exports[`<ConceptLinksActions /> matches the latest snapshot with Grant Requests permission 1`] = `
4
+ <div>
5
+ <div
6
+ style="float: right;"
7
+ >
8
+ <div
9
+ class="ui fitted toggle checkbox bgOrange"
10
+ style="top: 6px; margin-right: 7.5px;"
11
+ >
12
+ <input
13
+ class="hidden"
14
+ id="execute_checkbox"
15
+ readonly=""
16
+ tabindex="0"
17
+ type="checkbox"
18
+ value=""
19
+ />
20
+ <label
21
+ for="execute_checkbox"
22
+ />
23
+ </div>
24
+ <button
25
+ class="ui secondary disabled button"
26
+ disabled=""
27
+ tabindex="-1"
28
+ title="links.actions.grant_request.tooltip"
29
+ >
30
+ <i
31
+ aria-hidden="true"
32
+ class="shield icon"
33
+ />
34
+ links.actions.grant_request
35
+ </button>
36
+ <a
37
+ class="ui primary button"
38
+ href="/concepts/11/versions/1/links/structures/new"
39
+ role="button"
40
+ >
41
+ Add Link
42
+ </a>
43
+ </div>
44
+ </div>
45
+ `;
46
+
47
+ exports[`<ConceptLinksActions /> matches the latest snapshot without Grant Requests permission 1`] = `
48
+ <div>
49
+ <div
50
+ style="float: right;"
51
+ >
52
+ <a
53
+ class="ui primary button"
54
+ href="/concepts/11/versions/1/links/structures/new"
55
+ role="button"
56
+ >
57
+ Add Link
58
+ </a>
59
+ </div>
60
+ </div>
61
+ `;
@@ -0,0 +1,16 @@
1
+ // Jest Snapshot v1, https://goo.gl/fbAQLP
2
+
3
+ exports[`<ConceptLinkstRequestGrantButton /> matches the latest snapshot 1`] = `
4
+ <div>
5
+ <button
6
+ class="ui secondary button"
7
+ title="links.actions.grant_request.tooltip"
8
+ >
9
+ <i
10
+ aria-hidden="true"
11
+ class="shield icon"
12
+ />
13
+ links.actions.grant_request
14
+ </button>
15
+ </div>
16
+ `;