@truedat/dd 8.8.6 → 8.8.8

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/dd",
3
- "version": "8.8.6",
3
+ "version": "8.8.8",
4
4
  "description": "Truedat Web Data Dictionary",
5
5
  "sideEffects": false,
6
6
  "module": "src/index.js",
@@ -51,7 +51,7 @@
51
51
  "@testing-library/jest-dom": "^6.6.3",
52
52
  "@testing-library/react": "^16.3.0",
53
53
  "@testing-library/user-event": "^14.6.1",
54
- "@truedat/test": "8.8.6",
54
+ "@truedat/test": "8.8.8",
55
55
  "identity-obj-proxy": "^3.0.0",
56
56
  "jest": "^29.7.0",
57
57
  "redux-saga-test-plan": "^4.0.6"
@@ -86,5 +86,5 @@
86
86
  "svg-pan-zoom": "^3.6.2",
87
87
  "swr": "^2.3.3"
88
88
  },
89
- "gitHead": "608a876aa3b04799eb2e1bb5b5f071a81e2b509e"
89
+ "gitHead": "850b1a20250c39f4781aea0174aeebd383898eea"
90
90
  }
@@ -1,6 +1,6 @@
1
1
  import _ from "lodash/fp";
2
2
  import { useState } from "react";
3
- import { Button, Checkbox, Form, Header } from "semantic-ui-react";
3
+ import { Button, Checkbox, Form, Header, Icon } from "semantic-ui-react";
4
4
  import PropTypes from "prop-types";
5
5
  import { useIntl } from "react-intl";
6
6
  import { connect } from "react-redux";
@@ -17,18 +17,61 @@ export const EditDomainForm = ({
17
17
  const { formatMessage } = useIntl();
18
18
  const [domainIds, setDomainIds] = useState(structure?.domain_ids || []);
19
19
  const [inherit, setInherit] = useState(true);
20
+ const [showConfirm, setShowConfirm] = useState(false);
20
21
 
21
- const onSubmit = () => {
22
+ const doUpdate = () => {
22
23
  const data_structure = { id: structure.id, domain_ids: domainIds };
23
-
24
24
  updateStructure({ data_structure, inherit });
25
25
  };
26
26
 
27
+ const onSubmit = () => {
28
+ if (inherit) {
29
+ setShowConfirm(true);
30
+ return;
31
+ }
32
+ doUpdate();
33
+ };
34
+
35
+ const handleConfirm = () => {
36
+ setShowConfirm(false);
37
+ doUpdate();
38
+ };
39
+
40
+ const handleCancel = () => {
41
+ setShowConfirm(false);
42
+ };
43
+
27
44
  const handleReset = () => {
28
45
  setDomainIds(structure?.domain_ids || []);
29
46
  setInherit(true);
30
47
  };
31
48
 
49
+ if (showConfirm) {
50
+ return (
51
+ <div className="edit-domain-form">
52
+ <div className="confirm-content">
53
+ <div className="confirm-icon pulse-warning">
54
+ <Icon name="exclamation triangle" />
55
+ </div>
56
+ <p className="confirm-message">
57
+ {formatMessage(
58
+ { id: "structure.edit_domain.confirm_inherit" },
59
+ { name: <b>{structure.name}</b> },
60
+ )}
61
+ </p>
62
+ <div className="confirm-actions">
63
+ <Button type="button" size="tiny" onClick={handleCancel}>
64
+ {formatMessage({ id: "structure.edit_domain.close" })}
65
+ </Button>
66
+ <Button type="button" primary size="tiny" onClick={handleConfirm}>
67
+ {formatMessage({ id: "structureDomain.actions.update" })}
68
+ </Button>
69
+ </div>
70
+ </div>
71
+ </div>
72
+ );
73
+ }
74
+
32
75
  return (
33
76
  <div className="edit-domain-form">
34
77
  <div className="header-wrapper">
@@ -79,6 +122,7 @@ export const EditDomainForm = ({
79
122
  type="button"
80
123
  secondary
81
124
  size="tiny"
125
+ disabled={_.isEqual(domainIds, structure?.domain_ids)}
82
126
  content={formatMessage({ id: "structure.edit_domain.reset" })}
83
127
  onClick={handleReset}
84
128
  />
@@ -88,7 +132,7 @@ export const EditDomainForm = ({
88
132
  disabled={
89
133
  saving ||
90
134
  _.isEmpty(domainIds) ||
91
- domainIds == [structure?.domain_ids]
135
+ _.isEqual(domainIds, structure?.domain_ids)
92
136
  }
93
137
  primary
94
138
  content={formatMessage({ id: "structureDomain.actions.update" })}
@@ -108,7 +152,7 @@ EditDomainForm.propTypes = {
108
152
  };
109
153
 
110
154
  const mapStateToProps = ({ structure, structureUpdating }) => ({
111
- structure: _.pick(["id", "domain_ids"])(structure),
155
+ structure: _.pick(["id", "domain_ids", "name"])(structure),
112
156
  saving: structureUpdating,
113
157
  });
114
158
 
@@ -32,7 +32,7 @@ export const EditDomainPopup = ({
32
32
  className="edit-domain-button"
33
33
  size="tiny"
34
34
  circular
35
- icon="plus"
35
+ icon="pencil"
36
36
  />
37
37
  );
38
38
 
@@ -7,7 +7,6 @@ import { useIntl } from "react-intl";
7
7
  import { HistoryBackButton } from "@truedat/core/components";
8
8
  import { selectTemplate, selectDomains } from "@truedat/df/routines";
9
9
  import { applyTemplate, validateContent } from "@truedat/df/utils";
10
- import { apiJson } from "@truedat/core/services/api";
11
10
  import SuggestionsWidget from "@truedat/ai/components/suggestions/SuggestionsWidget";
12
11
  import { doStructureNoteAction } from "../routines";
13
12
  import { getLatestDfContent } from "../selectors/getSortedStructureNotes";
@@ -29,9 +28,6 @@ export const StructureNotesEdit = ({
29
28
  latestDfContent,
30
29
  }) => {
31
30
  const [content, setContent] = useState(latestDfContent);
32
- const aiSuggestionsUrl = _.prop("_actions.ai_suggestions.href")(
33
- structureNotes,
34
- );
35
31
 
36
32
  const isModification = !_.isEmpty(latestDfContent);
37
33
 
@@ -76,22 +72,28 @@ export const StructureNotesEdit = ({
76
72
  setContent({ ...content, ...suggestions });
77
73
  };
78
74
 
79
- const requestAiSuggestion = (callback) => {
80
- const url = `${aiSuggestionsUrl}?language=${locale}`;
81
- apiJson(url).then(callback);
75
+ const suggestionParams = {
76
+ resource_type: "data_structure",
77
+ resource_body: {
78
+ name: structure.name || "",
79
+ domain: _.get("domains[0].name")(structure) || "",
80
+ type: template?.name,
81
+ },
82
+ domain_ids: structure.domain_ids,
83
+ template_id: template?.id,
84
+ language: locale,
85
+ resource_id: structure.id ?? null,
82
86
  };
83
87
 
84
88
  return (
85
89
  <Segment attached="bottom">
86
90
  <TemplateLoader id="templateloader" />
87
- {aiSuggestionsUrl ? (
88
- <SuggestionsWidget
89
- requestAiSuggestion={requestAiSuggestion}
90
- template={template}
91
- applySuggestions={applySuggestions}
92
- isModification={isModification}
93
- />
94
- ) : null}
91
+ <SuggestionsWidget
92
+ suggestionParams={suggestionParams}
93
+ template={template}
94
+ applySuggestions={applySuggestions}
95
+ isModification={isModification}
96
+ />
95
97
  <Form>
96
98
  <DynamicForm
97
99
  onChange={setContent}
@@ -49,7 +49,7 @@ describe("<EditDomainForm />", () => {
49
49
  });
50
50
  });
51
51
 
52
- it("invokes function when send button clicked", async () => {
52
+ it("invokes function when send button clicked and confirm modal confirmed", async () => {
53
53
  const rendered = render(<EditDomainForm {...props} />, renderOpts);
54
54
  await waitForLoad(rendered);
55
55
 
@@ -63,6 +63,13 @@ describe("<EditDomainForm />", () => {
63
63
  expect(button).not.toBeDisabled();
64
64
  });
65
65
  userEvent.click(button);
66
+ await waitFor(() => {
67
+ expect(
68
+ rendered.getByText("structure.edit_domain.confirm_inherit"),
69
+ ).toBeInTheDocument();
70
+ });
71
+ const confirmButton = rendered.getByRole("button", { name: /update/i });
72
+ userEvent.click(confirmButton);
66
73
  await waitFor(() => {
67
74
  expect(updateStructure.mock.calls.length).toBe(1);
68
75
  });
@@ -100,7 +107,7 @@ describe("<EditDomainForm />", () => {
100
107
  );
101
108
  });
102
109
 
103
- it("send selected multiple domain ids when button clicked", async () => {
110
+ it("send selected multiple domain ids when button clicked and confirm modal confirmed", async () => {
104
111
  const rendered = render(<EditDomainForm {...props} />, renderOpts);
105
112
  await waitForLoad(rendered);
106
113
 
@@ -115,6 +122,13 @@ describe("<EditDomainForm />", () => {
115
122
  expect(button).not.toBeDisabled();
116
123
  });
117
124
  userEvent.click(button);
125
+ await waitFor(() => {
126
+ expect(
127
+ rendered.getByText("structure.edit_domain.confirm_inherit"),
128
+ ).toBeInTheDocument();
129
+ });
130
+ const confirmButton = rendered.getByRole("button", { name: /update/i });
131
+ userEvent.click(confirmButton);
118
132
  await waitFor(() => {
119
133
  expect(updateStructure.mock.calls.length).toBe(1);
120
134
  });
@@ -2,12 +2,22 @@ import userEvent from "@testing-library/user-event";
2
2
  import { waitFor } from "@testing-library/react";
3
3
  import { render, waitForLoad } from "@truedat/test/render";
4
4
  import { applyTemplate } from "@truedat/df/utils";
5
+ import SuggestionsWidget from "@truedat/ai/components/suggestions/SuggestionsWidget";
5
6
  import { StructureNotesEdit } from "../StructureNotesEdit";
6
7
 
8
+ jest.mock("@truedat/ai/components/suggestions/SuggestionsWidget", () => ({
9
+ __esModule: true,
10
+ default: jest.fn(() => null),
11
+ }));
12
+
7
13
  describe("<StructureNotesEdit />", () => {
14
+ beforeEach(() => {
15
+ jest.clearAllMocks();
16
+ });
17
+
8
18
  it("matches the latest snapshot", async () => {
9
19
  const props = {
10
- structure: { id: 1 },
20
+ structure: { id: 1, domain_ids: [1] },
11
21
  template: { id: 2 },
12
22
  doStructureNoteAction: () => {},
13
23
  selectTemplate: () => {},
@@ -24,17 +34,19 @@ describe("<StructureNotesEdit />", () => {
24
34
  expect(rendered.container).toMatchSnapshot();
25
35
  });
26
36
 
27
- it("matches the latest snapshot with ai suggestion action", async () => {
37
+ it("passes data_structure suggestion params to the widget", async () => {
28
38
  const props = {
29
- structure: { id: 1 },
30
- template: { id: 2 },
39
+ structure: {
40
+ id: 7,
41
+ name: "my structure",
42
+ domain_ids: [3],
43
+ domains: [{ name: "my domain" }],
44
+ },
45
+ template: { id: 2, name: "my template" },
31
46
  doStructureNoteAction: () => {},
32
47
  selectTemplate: () => {},
33
48
  selectDomain: () => {},
34
49
  structureNotes: {
35
- _actions: {
36
- ai_suggestions: { href: "suggestion" },
37
- },
38
50
  structureNotes: [],
39
51
  },
40
52
  latestDfContent: { foo: { value: "bar", origin: "user" } },
@@ -43,7 +55,19 @@ describe("<StructureNotesEdit />", () => {
43
55
  };
44
56
  const rendered = render(<StructureNotesEdit {...props} />);
45
57
  await waitForLoad(rendered);
46
- expect(rendered.container).toMatchSnapshot();
58
+
59
+ await waitFor(() => expect(SuggestionsWidget).toHaveBeenCalled());
60
+ expect(SuggestionsWidget.mock.calls[0][0].suggestionParams).toMatchObject({
61
+ resource_type: "data_structure",
62
+ resource_id: 7,
63
+ template_id: 2,
64
+ domain_ids: [3],
65
+ resource_body: {
66
+ name: "my structure",
67
+ domain: "my domain",
68
+ type: "my template",
69
+ },
70
+ });
47
71
  });
48
72
 
49
73
  it("calls doStructureNoteAction when submit is clicked", async () => {
@@ -25,53 +25,3 @@ exports[`<StructureNotesEdit /> matches the latest snapshot 1`] = `
25
25
  </div>
26
26
  </div>
27
27
  `;
28
-
29
- exports[`<StructureNotesEdit /> matches the latest snapshot with ai suggestion action 1`] = `
30
- <div>
31
- <div
32
- class="ui bottom attached segment"
33
- >
34
- <div
35
- class="ui segment"
36
- >
37
- <div
38
- class="ui container"
39
- style="display: flex; justify-content: space-between;"
40
- >
41
- <h4>
42
- <i
43
- aria-hidden="true"
44
- class="lightbulb icon"
45
- />
46
- structure_note.ai_suggestion.header
47
- </h4>
48
- <div
49
- class="ui hidden divider"
50
- />
51
- <button
52
- class="ui button"
53
- >
54
- actions.ai_suggestion
55
- </button>
56
- </div>
57
- </div>
58
- <form
59
- class="ui form"
60
- >
61
- <button
62
- class="ui primary button"
63
- >
64
- actions.save
65
- </button>
66
- <a
67
- class="ui secondary button td-icon-text-control"
68
- data-discover="true"
69
- href="/"
70
- role="button"
71
- >
72
- actions.cancel
73
- </a>
74
- </form>
75
- </div>
76
- </div>
77
- `;
@@ -75,3 +75,53 @@
75
75
  background: #f8fafc;
76
76
  margin: 1.5rem -1.5rem -1.5rem;
77
77
  }
78
+
79
+ .edit-domain-form .footer-actions .button,
80
+ .edit-domain-form .confirm-actions .button {
81
+ max-width: 120px;
82
+ overflow: hidden;
83
+ text-overflow: ellipsis;
84
+ white-space: nowrap;
85
+ }
86
+
87
+ .edit-domain-form .confirm-content {
88
+ display: flex;
89
+ flex-direction: column;
90
+ align-items: center;
91
+ justify-content: center;
92
+ padding: 2.5rem 1.5rem 2rem;
93
+ text-align: center;
94
+ }
95
+
96
+ .edit-domain-form .confirm-icon {
97
+ font-size: 2.5rem;
98
+ color: #f59e0b;
99
+ margin-bottom: 1rem;
100
+ }
101
+
102
+ .edit-domain-form .confirm-message {
103
+ font-size: 0.9rem;
104
+ color: #334155;
105
+ margin: 0 0 1.5rem;
106
+ line-height: 1.5;
107
+ font-weight: 500;
108
+ }
109
+
110
+ .edit-domain-form .confirm-actions {
111
+ display: flex;
112
+ gap: 0.75rem;
113
+ }
114
+
115
+ @keyframes pulse-warning {
116
+ 0%,
117
+ 100% {
118
+ transform: scale(1);
119
+ }
120
+ 50% {
121
+ transform: scale(1.25);
122
+ }
123
+ }
124
+
125
+ .confirm-icon.pulse-warning i {
126
+ animation: pulse-warning 0.9s ease-in-out 2;
127
+ }