@truedat/ai 6.0.1

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 (27) hide show
  1. package/LICENSE +685 -0
  2. package/README.md +13 -0
  3. package/package.json +101 -0
  4. package/src/api.js +6 -0
  5. package/src/components/AiRoutes.js +24 -0
  6. package/src/components/constants.js +20 -0
  7. package/src/components/index.js +2 -0
  8. package/src/components/prompts/PromptEditor.js +365 -0
  9. package/src/components/prompts/Prompts.js +136 -0
  10. package/src/components/prompts/__tests__/Prompt.spec.js +77 -0
  11. package/src/components/prompts/__tests__/PromptEditor.spec.js +208 -0
  12. package/src/components/prompts/__tests__/__snapshots__/Prompt.spec.js.snap +77 -0
  13. package/src/components/prompts/__tests__/__snapshots__/PromptEditor.spec.js.snap +896 -0
  14. package/src/components/resourceMappings/ResourceMappingEditor.js +203 -0
  15. package/src/components/resourceMappings/ResourceMappingFields.js +119 -0
  16. package/src/components/resourceMappings/ResourceMappings.js +140 -0
  17. package/src/components/resourceMappings/__tests__/ResourceMappingEditor.spec.js +204 -0
  18. package/src/components/resourceMappings/__tests__/ResourceMappings.spec.js +79 -0
  19. package/src/components/resourceMappings/__tests__/__snapshots__/ResourceMappingEditor.spec.js.snap +748 -0
  20. package/src/components/resourceMappings/__tests__/__snapshots__/ResourceMappings.spec.js.snap +77 -0
  21. package/src/components/resourceMappings/selectors/DataStructureSelector.js +80 -0
  22. package/src/components/resourceMappings/selectors/index.js +11 -0
  23. package/src/hooks/__tests__/usePrompts.spec.js +101 -0
  24. package/src/hooks/__tests__/useResourceMappings.spec.js +101 -0
  25. package/src/hooks/usePrompts.js +31 -0
  26. package/src/hooks/useResourceMappings.js +33 -0
  27. package/src/index.js +3 -0
@@ -0,0 +1,77 @@
1
+ import React from "react";
2
+ import { waitFor } from "@testing-library/react";
3
+ import { render } from "@truedat/test/render";
4
+ import Prompts from "../Prompts";
5
+
6
+ jest.mock("@truedat/ai/hooks/usePrompts", () => {
7
+ const originalModule = jest.requireActual("@truedat/ai/hooks/usePrompts");
8
+
9
+ return {
10
+ __esModule: true,
11
+ ...originalModule,
12
+ usePrompts: jest.fn(() => ({
13
+ data: {
14
+ data: [
15
+ {
16
+ name: "rm1",
17
+ resource_type: "boolean",
18
+ fields: [{ source: "s1", target: "t1" }],
19
+ selector: { system_external_id: 1 },
20
+ },
21
+ ],
22
+ },
23
+ loading: false,
24
+ })),
25
+ usePromptCreate: jest.fn(() => ({
26
+ trigger: jest.fn(() => new Promise(() => {})),
27
+ isMutating: false,
28
+ })),
29
+ usePromptDelete: jest.fn(() => ({
30
+ trigger: jest.fn(() => new Promise(() => {})),
31
+ isMutating: false,
32
+ })),
33
+ usePromptUpdate: jest.fn(() => ({
34
+ trigger: jest.fn(() => new Promise(() => {})),
35
+ isMutating: false,
36
+ })),
37
+ };
38
+ });
39
+
40
+ describe("<Prompts />", () => {
41
+ const renderOpts = {
42
+ messages: {
43
+ en: {
44
+ "prompts.header": "prompts.header",
45
+ "prompts.subheader": "prompts.subheader",
46
+ "prompts.no_selection": "prompts.no_selection",
47
+ "prompts.empty_list": "prompts.empty_list",
48
+ "prompts.action.new": "prompts.action.new",
49
+ "group.props.name": "name",
50
+ "prompts.form.name": "name",
51
+ "prompts.form.add_description": "add_description",
52
+ "prompts.form.name": "name",
53
+ "prompts.form.add_param": "add_param",
54
+ "actions.save": "save",
55
+ "actions.cancel": "cancel",
56
+ "actions.delete": "delete",
57
+ "prompts.action.delete.header": "delete_header",
58
+ "prompts.action.delete.content": "delete_content",
59
+ "prompts.form.output": "output",
60
+ "prompts.form.params": "params",
61
+ "form.validation.required": "required",
62
+ "confirmation.yes": "confirm_yes",
63
+ "confirmation.no": "confirm_no",
64
+ "actions.discard.confirmation.header": "confirmation_header",
65
+ "actions.discard.confirmation.content": "confirmation_content",
66
+ "prompts.action.new": "prompts.action.new",
67
+ },
68
+ },
69
+ fallback: "lazy",
70
+ };
71
+
72
+ it("matches the latest snapshot", async () => {
73
+ const { container, queryByText } = render(<Prompts />, renderOpts);
74
+ await waitFor(() => expect(queryByText(/lazy/i)).not.toBeInTheDocument());
75
+ expect(container).toMatchSnapshot();
76
+ });
77
+ });
@@ -0,0 +1,208 @@
1
+ import React from "react";
2
+ import { act } from "react-dom/test-utils";
3
+ import { waitFor } from "@testing-library/react";
4
+ import { render } from "@truedat/test/render";
5
+ import userEvent from "@testing-library/user-event";
6
+ import PromptEditor from "../PromptEditor";
7
+
8
+ jest.mock("@truedat/core/hooks", () => ({
9
+ useLocales: jest.fn(() => ({
10
+ loading: false,
11
+ locales: [{ lang: "es", id: 1 }],
12
+ })),
13
+ }));
14
+
15
+ const renderOpts = {
16
+ messages: {
17
+ en: {
18
+ "prompts.resourceType.data_structure":
19
+ "prompts.resourceType.data_structure",
20
+ "form.validation.required": "form.validation.required",
21
+ "prompts.form.selector": "prompts.form.selector",
22
+ "prompts.form.fields": "prompts.form.fields",
23
+ "actions.save": "actions.save",
24
+ "actions.cancel": "actions.cancel",
25
+ "actions.delete": "actions.delete",
26
+ "functions.action.delete.header": "functions.action.delete.header",
27
+ "functions.action.delete.content": "functions.action.delete.content",
28
+ "prompts.form.name": "prompts.form.name",
29
+ "prompts.form.name": "prompts.form.name",
30
+ "prompts.form.resource_type": "prompts.form.resource_type",
31
+ "prompts.form.fields.add": "prompts.form.fields.add",
32
+ "prompts.form.fields.source": "prompts.form.fields.source",
33
+ "form.validation.required": "form.validation.required",
34
+ "prompts.form.fields.source": "prompts.form.fields.source",
35
+ "prompts.form.fields.target": "prompts.form.fields.target",
36
+ "actions.discard.confirmation.content":
37
+ "actions.discard.confirmation.content",
38
+ "actions.discard.confirmation.header":
39
+ "actions.discard.confirmation.header",
40
+ "confirmation.yes": "confirmation.yes",
41
+ "confirmation.no": "confirmation.no",
42
+ "prompts.form.model": "prompts.form.model",
43
+ "prompts.form.provider": "prompts.form.provider",
44
+ "prompts.form.user_prompt_template": "prompts.form.user_prompt_template",
45
+ "prompts.form.system_prompt": "prompts.form.system_prompt",
46
+ "prompts.form.language": "prompts.form.language",
47
+ "prompts.provider.openai": "prompts.provider.openai",
48
+ "resourceMappings.resourceType.data_structure":
49
+ "resourceMappings.resourceType.data_structure",
50
+ },
51
+ },
52
+ fallback: "lazy",
53
+ };
54
+
55
+ const props = {
56
+ selectedPrompt: {
57
+ id: 1,
58
+ name: "prompt1",
59
+ resource_type: "data_structure",
60
+ language: "en",
61
+ system_prompt: "system_prompt",
62
+ user_prompt_template: "user_prompt",
63
+ provider: "openai",
64
+ model: "model1",
65
+ },
66
+ prompts: [
67
+ {
68
+ id: 1,
69
+ name: "prompt1",
70
+ resource_type: "data_structure",
71
+ language: "en",
72
+ system_prompt: "system_prompt",
73
+ user_prompt_template: "user_prompt",
74
+ provider: "openai",
75
+ model: "model1",
76
+ },
77
+ ],
78
+ onSubmit: jest.fn(),
79
+ onCancel: jest.fn(),
80
+ onDelete: jest.fn(),
81
+ isSubmitting: false,
82
+ setDirty: jest.fn(),
83
+ };
84
+
85
+ describe("<PromptEditor />", () => {
86
+ it("matches the latest snapshot", async () => {
87
+ const { container } = render(<PromptEditor {...props} />, renderOpts);
88
+ await act(async () => {
89
+ expect(container).toMatchSnapshot();
90
+ });
91
+ });
92
+
93
+ it("matches snapshot without selected resource mapping", async () => {
94
+ const props = { setDirty: jest.fn() };
95
+ const { container, queryByText } = render(
96
+ <PromptEditor {...props} />,
97
+ renderOpts
98
+ );
99
+ await waitFor(() => expect(queryByText(/lazy/i)).not.toBeInTheDocument());
100
+ expect(container).toMatchSnapshot();
101
+ });
102
+
103
+ it("matches snapshot without onDelete", async () => {
104
+ const thisProps = {
105
+ ...props,
106
+ onDelete: null,
107
+ };
108
+ const { container } = render(<PromptEditor {...thisProps} />, renderOpts);
109
+
110
+ await waitFor(() => expect(container).toMatchSnapshot());
111
+ });
112
+
113
+ it("test cancel button", async () => {
114
+ const onCancel = jest.fn();
115
+ const thisProps = { ...props, onCancel };
116
+ const { getByRole } = render(<PromptEditor {...thisProps} />, renderOpts);
117
+
118
+ userEvent.click(getByRole("button", { name: /cancel/i }));
119
+
120
+ await waitFor(() => expect(onCancel).toHaveBeenCalled());
121
+ });
122
+
123
+ it("test cancel button with confirm", async () => {
124
+ const onCancel = jest.fn();
125
+ const thisProps = { ...props, onCancel };
126
+ const { container, getByRole, getAllByRole } = render(
127
+ <PromptEditor {...thisProps} />,
128
+ renderOpts
129
+ );
130
+
131
+ userEvent.type(getAllByRole("textbox")[0], "name");
132
+
133
+ await waitFor(() =>
134
+ expect(getByRole("button", { name: /save/i })).toBeEnabled()
135
+ );
136
+
137
+ userEvent.click(getByRole("button", { name: /cancel/i }));
138
+ expect(onCancel).toHaveBeenCalledTimes(0);
139
+
140
+ userEvent.click(getByRole("button", { name: /modal-negative-action/i }));
141
+ expect(onCancel).toHaveBeenCalledTimes(0);
142
+
143
+ userEvent.click(getByRole("button", { name: /cancel/i }));
144
+ expect(onCancel).toHaveBeenCalledTimes(0);
145
+
146
+ expect(container).toMatchSnapshot();
147
+
148
+ userEvent.click(getByRole("button", { name: /modal-affirmative-action/i }));
149
+ expect(onCancel).toHaveBeenCalledTimes(1);
150
+ });
151
+
152
+ it("test delete button", async () => {
153
+ const onDelete = jest.fn();
154
+ const thisProps = { ...props, onDelete };
155
+ const { container, getByRole } = render(
156
+ <PromptEditor {...thisProps} />,
157
+ renderOpts
158
+ );
159
+
160
+ userEvent.click(getByRole("button", { name: /delete/i }));
161
+ expect(onDelete).toHaveBeenCalledTimes(0);
162
+
163
+ userEvent.click(getByRole("button", { name: /modal-negative-action/i }));
164
+ expect(onDelete).toHaveBeenCalledTimes(0);
165
+
166
+ userEvent.click(getByRole("button", { name: /delete/i }));
167
+ expect(onDelete).toHaveBeenCalledTimes(0);
168
+
169
+ await waitFor(() => expect(container).toMatchSnapshot());
170
+
171
+ userEvent.click(getByRole("button", { name: /modal-affirmative-action/i }));
172
+ expect(onDelete).toHaveBeenCalledTimes(1);
173
+ });
174
+
175
+ it("test submit", async () => {
176
+ const onSubmit = jest.fn();
177
+ const thisProps = { ...props, onSubmit };
178
+ const { getByRole, getAllByRole } = render(
179
+ <PromptEditor {...thisProps} />,
180
+ renderOpts
181
+ );
182
+
183
+ expect(getByRole("button", { name: /save/i })).toBeDisabled();
184
+
185
+ userEvent.type(getAllByRole("textbox")[0], "name");
186
+
187
+ await waitFor(() =>
188
+ expect(getByRole("button", { name: /save/i })).toBeEnabled()
189
+ );
190
+
191
+ userEvent.click(getByRole("button", { name: /save/i }));
192
+
193
+ await waitFor(() =>
194
+ expect(getByRole("button", { name: /save/i })).toBeEnabled()
195
+ );
196
+
197
+ expect(onSubmit.mock.calls[0][0]).toEqual({
198
+ id: 1,
199
+ language: "en",
200
+ model: "model1",
201
+ name: "prompt1name",
202
+ provider: "openai",
203
+ resource_type: "data_structure",
204
+ system_prompt: "system_prompt",
205
+ user_prompt_template: "user_prompt",
206
+ });
207
+ });
208
+ });
@@ -0,0 +1,77 @@
1
+ // Jest Snapshot v1, https://goo.gl/fbAQLP
2
+
3
+ exports[`<Prompts /> matches the latest snapshot 1`] = `
4
+ <div>
5
+ <div
6
+ class="ui segment"
7
+ >
8
+ <h2
9
+ class="ui header"
10
+ >
11
+ <i
12
+ aria-hidden="true"
13
+ class="map signs circular icon"
14
+ />
15
+ <div
16
+ class="content"
17
+ >
18
+ prompts.header
19
+ <div
20
+ class="sub header"
21
+ >
22
+ prompts.subheader
23
+ </div>
24
+ </div>
25
+ </h2>
26
+ <div
27
+ class="ui grid"
28
+ >
29
+ <div
30
+ class="four wide column"
31
+ >
32
+ <button
33
+ class="ui fluid button"
34
+ >
35
+ prompts.action.new
36
+ </button>
37
+ <div
38
+ class="ui divided selection list"
39
+ role="list"
40
+ >
41
+ <div
42
+ class="item"
43
+ role="listitem"
44
+ >
45
+ <div
46
+ class="content"
47
+ >
48
+ <div
49
+ class="header"
50
+ >
51
+ rm1
52
+ </div>
53
+ </div>
54
+ </div>
55
+ </div>
56
+ </div>
57
+ <div
58
+ class="eleven wide column"
59
+ >
60
+ <h2
61
+ class="ui icon center aligned header"
62
+ >
63
+ <i
64
+ aria-hidden="true"
65
+ class="hand pointer outline icon"
66
+ />
67
+ <div
68
+ class="sub header"
69
+ >
70
+ prompts.no_selection
71
+ </div>
72
+ </h2>
73
+ </div>
74
+ </div>
75
+ </div>
76
+ </div>
77
+ `;