@truedat/lm 7.5.12 → 7.5.14

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@truedat/lm",
3
- "version": "7.5.12",
3
+ "version": "7.5.14",
4
4
  "description": "Truedat Link Manager",
5
5
  "sideEffects": false,
6
6
  "module": "src/index.js",
@@ -48,7 +48,7 @@
48
48
  "@testing-library/jest-dom": "^6.6.3",
49
49
  "@testing-library/react": "^16.3.0",
50
50
  "@testing-library/user-event": "^14.6.1",
51
- "@truedat/test": "7.5.12",
51
+ "@truedat/test": "7.5.14",
52
52
  "identity-obj-proxy": "^3.0.0",
53
53
  "jest": "^29.7.0",
54
54
  "redux-saga-test-plan": "^4.0.6"
@@ -79,9 +79,8 @@
79
79
  "redux-saga": "^1.3.0",
80
80
  "redux-saga-routines": "^3.2.3",
81
81
  "reselect": "^5.1.1",
82
- "semantic-ui-calendar-react": "^0.15.3",
83
82
  "semantic-ui-react": "^3.0.0-beta.2",
84
83
  "swr": "^2.3.3"
85
84
  },
86
- "gitHead": "1476061ceb9ed15e0bacec71e20d695a0cd57986"
85
+ "gitHead": "46d017329f0f074db1feb2304c06ba696bb68a14"
87
86
  }
@@ -0,0 +1,82 @@
1
+ import _ from "lodash/fp";
2
+ import React, { useState, useEffect } from "react";
3
+ import { Divider } from "semantic-ui-react";
4
+ import { useParams } from "react-router";
5
+ import { useDispatch, useSelector } from "react-redux";
6
+ import { useIntl } from "react-intl";
7
+ import { makeTagOptionsSelector } from "@truedat/core/selectors";
8
+ import { HistoryBackButton } from "@truedat/core/components";
9
+ import { linkTo } from "@truedat/core/routes";
10
+ import { Button } from "semantic-ui-react";
11
+
12
+ import { createRelation, clearSelectedRelationTags } from "../routines";
13
+ import TagTypeDropdownSelector from "./TagTypeDropdownSelector";
14
+
15
+ const StructureSuggestions = React.lazy(() =>
16
+ import("@truedat/dd/components/StructureSuggestions")
17
+ );
18
+
19
+ const selectTagOptions = makeTagOptionsSelector("data_field");
20
+
21
+ export const ConceptSuggestionLinkForm = () => {
22
+ const { business_concept_id: sourceId, id: version } = useParams();
23
+ const { tagOptions, selectedRelationTags } = useSelector((state) => ({
24
+ tagOptions: selectTagOptions(state),
25
+ selectedRelationTags: state.selectedRelationTags,
26
+ }));
27
+ const dispatch = useDispatch();
28
+ const [selectedStructure, setSelectedStructure] = useState(null);
29
+ const { formatMessage } = useIntl();
30
+
31
+ useEffect(() => {
32
+ return () => {
33
+ dispatch(clearSelectedRelationTags.trigger());
34
+ };
35
+ }, [clearSelectedRelationTags, dispatch]);
36
+
37
+ const handleSubmit = () => {
38
+ const structureLink = {
39
+ redirectUrl: linkTo.CONCEPT_LINKS_STRUCTURES({
40
+ business_concept_id: sourceId,
41
+ id: version,
42
+ }),
43
+ source_id: sourceId,
44
+ source_type: "business_concept",
45
+ target_id: selectedStructure.id,
46
+ target_type: "data_structure",
47
+ tag_ids: selectedRelationTags ? selectedRelationTags : [],
48
+ };
49
+ dispatch(createRelation.trigger(structureLink));
50
+ };
51
+
52
+ const disabled = !(selectedStructure && selectedRelationTags);
53
+
54
+ return (
55
+ <>
56
+ <Divider hidden />
57
+ {!_.isEmpty(tagOptions) && (
58
+ <>
59
+ <TagTypeDropdownSelector options={tagOptions} />
60
+ <Divider hidden />
61
+ </>
62
+ )}
63
+ <StructureSuggestions
64
+ handleSelectedStructure={setSelectedStructure}
65
+ selectedStructure={selectedStructure}
66
+ selectable={true}
67
+ />
68
+ <Divider hidden />
69
+ <Button.Group>
70
+ <Button
71
+ primary
72
+ content={formatMessage({ id: "actions.create" })}
73
+ disabled={disabled}
74
+ onClick={handleSubmit}
75
+ />
76
+ <HistoryBackButton content={formatMessage({ id: "actions.cancel" })} />
77
+ </Button.Group>
78
+ </>
79
+ );
80
+ };
81
+
82
+ export default ConceptSuggestionLinkForm;
@@ -0,0 +1,115 @@
1
+ import { render, fireEvent, screen, waitFor } from "@testing-library/react";
2
+ import ConceptSuggestionLinkForm from "../ConceptSuggestionLinkForm";
3
+ import { useSelector, useDispatch } from "react-redux";
4
+ import { useParams } from "react-router";
5
+ import { createRelation, clearSelectedRelationTags } from "../../routines";
6
+
7
+ jest.mock("react-redux", () => ({
8
+ useSelector: jest.fn(),
9
+ useDispatch: jest.fn(),
10
+ }));
11
+
12
+ jest.mock("react-router", () => ({
13
+ useParams: jest.fn(),
14
+ }));
15
+
16
+ jest.mock("react-intl", () => ({
17
+ useIntl: () => ({
18
+ formatMessage: ({ id }) => id, // mock translated strings
19
+ }),
20
+ }));
21
+
22
+ // Mock selector factory
23
+ jest.mock("@truedat/core/selectors", () => ({
24
+ makeTagOptionsSelector: jest.fn(() => jest.fn(() => [{ id: "tag1", name: "Tag 1" }])),
25
+ }));
26
+
27
+ // Mock components
28
+ jest.mock("@truedat/dd/components/StructureSuggestions", () =>
29
+ jest.fn((props) => {
30
+ // Include a button to simulate structure selection
31
+ return (
32
+ <div>
33
+ <div>MockStructureSuggestions</div>
34
+ <button onClick={() => props.handleSelectedStructure({ id: "structure123" })}>
35
+ Select Structure
36
+ </button>
37
+ </div>
38
+ );
39
+ })
40
+ );
41
+
42
+ jest.mock("../TagTypeDropdownSelector", () =>
43
+ jest.fn(() => <div>MockTagTypeDropdownSelector</div>)
44
+ );
45
+
46
+ jest.mock("@truedat/core/components", () => ({
47
+ HistoryBackButton: (props) => <button>{props.content}</button>,
48
+ }));
49
+
50
+ jest.mock("@truedat/core/routes", () => ({
51
+ linkTo: {
52
+ CONCEPT_LINKS_STRUCTURES: jest.fn(() => "/mocked/redirect/url"),
53
+ },
54
+ }));
55
+
56
+ describe("ConceptSuggestionLinkForm", () => {
57
+ const mockDispatch = jest.fn();
58
+
59
+ beforeEach(() => {
60
+ jest.clearAllMocks();
61
+
62
+ useParams.mockReturnValue({ business_concept_id: "bc1", id: "v1" });
63
+ useDispatch.mockReturnValue(mockDispatch);
64
+ useSelector.mockImplementation((selector) =>
65
+ selector({
66
+ selectedRelationTags: ["tag1"],
67
+ })
68
+ );
69
+
70
+ clearSelectedRelationTags.trigger = jest.fn(() => ({ type: "CLEAR_TAGS" }));
71
+ createRelation.trigger = jest.fn((payload) => ({ type: "CREATE_RELATION", payload }));
72
+ });
73
+
74
+ it("renders structure suggestions and tag dropdown", async () => {
75
+ render(<ConceptSuggestionLinkForm />);
76
+
77
+ await waitFor(() => {
78
+ expect(screen.getByText("MockStructureSuggestions")).toBeInTheDocument();
79
+ expect(screen.getByText("actions.create")).toBeDisabled();
80
+ });
81
+
82
+ });
83
+
84
+ it("dispatches createRelation on submit", async () => {
85
+ render(<ConceptSuggestionLinkForm />);
86
+
87
+ // Simulate structure selection
88
+ fireEvent.click(screen.getByText("Select Structure"));
89
+
90
+ // Now the submit button should be enabled
91
+ const createBtn = screen.getByText("actions.create");
92
+ expect(createBtn).not.toBeDisabled();
93
+
94
+ fireEvent.click(createBtn);
95
+
96
+ expect(createRelation.trigger).toHaveBeenCalledWith({
97
+ redirectUrl: "/mocked/redirect/url",
98
+ source_id: "bc1",
99
+ source_type: "business_concept",
100
+ target_id: "structure123",
101
+ target_type: "data_structure",
102
+ tag_ids: ["tag1"],
103
+ });
104
+
105
+ expect(mockDispatch).toHaveBeenCalledWith(expect.objectContaining({ type: "CREATE_RELATION" }));
106
+ });
107
+
108
+ it("dispatches clearSelectedRelationTags on unmount", () => {
109
+ const { unmount } = render(<ConceptSuggestionLinkForm />);
110
+ unmount();
111
+
112
+ expect(clearSelectedRelationTags.trigger).toHaveBeenCalled();
113
+ expect(mockDispatch).toHaveBeenCalledWith({ type: "CLEAR_TAGS" });
114
+ });
115
+ });