@mitodl/smoot-design 6.1.0 → 6.2.0
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/dist/bundles/remoteTutorDrawer.es.js +982 -975
- package/dist/bundles/remoteTutorDrawer.umd.js +25 -25
- package/dist/cjs/bundles/RemoteTutorDrawer/FlashcardsScreen.js +2 -2
- package/dist/cjs/bundles/RemoteTutorDrawer/RemoteTutorDrawer.js +8 -5
- package/dist/cjs/bundles/RemoteTutorDrawer/RemoteTutorDrawer.stories.js +40 -30
- package/dist/cjs/bundles/RemoteTutorDrawer/RemoteTutorDrawer.test.d.ts +1 -0
- package/dist/cjs/bundles/RemoteTutorDrawer/RemoteTutorDrawer.test.js +241 -0
- package/dist/cjs/components/AiChat/AiChat.test.js +31 -0
- package/dist/cjs/components/TabButtons/TabButtonList.d.ts +10 -1
- package/dist/cjs/components/TabButtons/TabButtonList.js +12 -1
- package/dist/cjs/index.d.ts +1 -0
- package/dist/cjs/index.js +5 -1
- package/dist/esm/bundles/RemoteTutorDrawer/FlashcardsScreen.js +2 -2
- package/dist/esm/bundles/RemoteTutorDrawer/RemoteTutorDrawer.js +8 -5
- package/dist/esm/bundles/RemoteTutorDrawer/RemoteTutorDrawer.stories.js +40 -30
- package/dist/esm/bundles/RemoteTutorDrawer/RemoteTutorDrawer.test.d.ts +1 -0
- package/dist/esm/bundles/RemoteTutorDrawer/RemoteTutorDrawer.test.js +239 -0
- package/dist/esm/components/AiChat/AiChat.test.js +31 -0
- package/dist/esm/components/TabButtons/TabButtonList.d.ts +10 -1
- package/dist/esm/components/TabButtons/TabButtonList.js +12 -1
- package/dist/esm/index.d.ts +1 -0
- package/dist/esm/index.js +1 -0
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +1 -1
|
@@ -75,13 +75,13 @@ const FlashcardsScreen = ({ flashcards, wasKeyboardFocus, }) => {
|
|
|
75
75
|
return (React.createElement(Container, { ref: containerRef },
|
|
76
76
|
React.createElement(Flashcard, { ref: flashcardRef, content: flashcards[cardIndex], "aria-label": `Flashcard ${cardIndex + 1} of ${flashcards.length}` }),
|
|
77
77
|
React.createElement(Navigation, null,
|
|
78
|
-
React.createElement(ActionButton_1.ActionButton, { onClick: () => setCardIndex(cardIndex - 1), disabled: cardIndex === 0, variant: "secondary", color: "secondary", size: "small" },
|
|
78
|
+
React.createElement(ActionButton_1.ActionButton, { onClick: () => setCardIndex(cardIndex - 1), disabled: cardIndex === 0, variant: "secondary", color: "secondary", size: "small", "aria-label": "Previous card" },
|
|
79
79
|
React.createElement(react_2.RiArrowLeftLine, { "aria-hidden": true })),
|
|
80
80
|
React.createElement(Page, null,
|
|
81
81
|
cardIndex + 1,
|
|
82
82
|
" / ",
|
|
83
83
|
flashcards.length),
|
|
84
|
-
React.createElement(ActionButton_1.ActionButton, { onClick: () => setCardIndex(cardIndex + 1), disabled: cardIndex === flashcards.length - 1, variant: "secondary", color: "secondary", size: "small" },
|
|
84
|
+
React.createElement(ActionButton_1.ActionButton, { onClick: () => setCardIndex(cardIndex + 1), disabled: cardIndex === flashcards.length - 1, variant: "secondary", color: "secondary", size: "small", "aria-label": "Next card" },
|
|
85
85
|
React.createElement(react_2.RiArrowRightLine, { "aria-hidden": true })))));
|
|
86
86
|
};
|
|
87
87
|
exports.FlashcardsScreen = FlashcardsScreen;
|
|
@@ -10,6 +10,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
10
10
|
};
|
|
11
11
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
12
|
exports.RemoteTutorDrawer = void 0;
|
|
13
|
+
// @format
|
|
13
14
|
const React = require("react");
|
|
14
15
|
const react_1 = require("react");
|
|
15
16
|
const styled_1 = require("@emotion/styled");
|
|
@@ -215,26 +216,28 @@ const RemoteTutorDrawer = ({ messageOrigin, transformBody = identity, className,
|
|
|
215
216
|
};
|
|
216
217
|
}, [messageOrigin, target]);
|
|
217
218
|
(0, react_1.useEffect)(() => {
|
|
218
|
-
|
|
219
|
+
var _a;
|
|
220
|
+
(_a = scrollElement === null || scrollElement === void 0 ? void 0 : scrollElement.scrollTo) === null || _a === void 0 ? void 0 : _a.call(scrollElement, {
|
|
219
221
|
top: tab === "chat" ? scrollElement.scrollHeight : 0,
|
|
220
222
|
});
|
|
221
223
|
}, [tab, scrollElement]);
|
|
222
224
|
const conversationStarters = (0, react_1.useMemo)(() => {
|
|
225
|
+
var _a;
|
|
223
226
|
if (!payload)
|
|
224
227
|
return [];
|
|
225
228
|
return (payload.chat.conversationStarters ||
|
|
226
|
-
((response === null || response === void 0 ? void 0 : response.flashcards)
|
|
229
|
+
(((_a = response === null || response === void 0 ? void 0 : response.flashcards) === null || _a === void 0 ? void 0 : _a.length) && response.flashcards.length >= 3
|
|
227
230
|
? randomItems(response.flashcards, 3).map((flashcard) => ({
|
|
228
231
|
content: flashcard.question,
|
|
229
232
|
}))
|
|
230
233
|
: DEFAULT_VIDEO_STARTERS));
|
|
231
234
|
}, [payload, response]);
|
|
232
235
|
if (!payload) {
|
|
233
|
-
return
|
|
236
|
+
return React.createElement("div", { "data-testid": "remote-tutor-drawer-waiting" });
|
|
234
237
|
}
|
|
235
238
|
const { blockType, chat } = payload;
|
|
236
239
|
const hasTabs = blockType === "video";
|
|
237
|
-
return (React.createElement(Drawer_1.default, { className: className, PaperProps: {
|
|
240
|
+
return (React.createElement(Drawer_1.default, { "data-testid": "remote-tutor-drawer", className: className, PaperProps: {
|
|
238
241
|
ref: paperRefCallback,
|
|
239
242
|
sx: {
|
|
240
243
|
width: "900px",
|
|
@@ -249,7 +252,7 @@ const RemoteTutorDrawer = ({ messageOrigin, transformBody = identity, className,
|
|
|
249
252
|
React.createElement(Header, null,
|
|
250
253
|
React.createElement(Title, null,
|
|
251
254
|
payload.title ? React.createElement(react_2.RiSparkling2Line, null) : null,
|
|
252
|
-
React.createElement(Typography_1.default, { variant: "body1" }, ((_b = payload.title) === null || _b === void 0 ? void 0 : _b.includes("AskTIM")) ? (React.createElement(React.Fragment, null,
|
|
255
|
+
React.createElement(Typography_1.default, { variant: "body1", component: "h2" }, ((_b = payload.title) === null || _b === void 0 ? void 0 : _b.includes("AskTIM")) ? (React.createElement(React.Fragment, null,
|
|
253
256
|
"Ask",
|
|
254
257
|
React.createElement("strong", null, "TIM"),
|
|
255
258
|
payload.title.replace("AskTIM", ""))) : (payload.title))),
|
|
@@ -54,21 +54,8 @@ const IFrame = ({ payload }) => {
|
|
|
54
54
|
};
|
|
55
55
|
const meta = {
|
|
56
56
|
title: "smoot-design/AI/RemoteTutorDrawer",
|
|
57
|
-
render: ({ target }, { parameters: {
|
|
58
|
-
|
|
59
|
-
blockType,
|
|
60
|
-
target,
|
|
61
|
-
title: "AskTIM for help with Problem: Derivatives 1.1",
|
|
62
|
-
chat: Object.assign({ apiUrl: TEST_API_STREAMING, initialMessages: INITIAL_MESSAGES, conversationStarters: STARTERS }, chat),
|
|
63
|
-
} })) : null,
|
|
64
|
-
blockType === "video" ? (React.createElement(IFrame, { payload: {
|
|
65
|
-
blockType,
|
|
66
|
-
target,
|
|
67
|
-
chat: Object.assign({ apiUrl: TEST_API_STREAMING, initialMessages: INITIAL_MESSAGES, conversationStarters: STARTERS }, chat),
|
|
68
|
-
summary: {
|
|
69
|
-
apiUrl: CONTENT_FILE_URL,
|
|
70
|
-
},
|
|
71
|
-
} })) : null,
|
|
57
|
+
render: ({ target }, { parameters: { payload } }) => (React.createElement(React.Fragment, null,
|
|
58
|
+
React.createElement(IFrame, { payload: payload }),
|
|
72
59
|
React.createElement(RemoteTutorDrawer_1.RemoteTutorDrawer, { target: target, messageOrigin: "http://localhost:6006" }))),
|
|
73
60
|
};
|
|
74
61
|
exports.default = meta;
|
|
@@ -77,9 +64,15 @@ exports.ProblemStory = {
|
|
|
77
64
|
target: "problem-frame",
|
|
78
65
|
},
|
|
79
66
|
parameters: {
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
67
|
+
payload: {
|
|
68
|
+
blockType: "problem",
|
|
69
|
+
target: "problem-frame",
|
|
70
|
+
title: "AskTIM for help with Problem: Derivatives 1.1",
|
|
71
|
+
chat: {
|
|
72
|
+
apiUrl: TEST_API_STREAMING,
|
|
73
|
+
initialMessages: INITIAL_MESSAGES,
|
|
74
|
+
conversationStarters: STARTERS,
|
|
75
|
+
},
|
|
83
76
|
},
|
|
84
77
|
},
|
|
85
78
|
};
|
|
@@ -88,11 +81,16 @@ exports.EntryScreenStory = {
|
|
|
88
81
|
target: "entry-screen-frame",
|
|
89
82
|
},
|
|
90
83
|
parameters: {
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
84
|
+
payload: {
|
|
85
|
+
blockType: "problem",
|
|
86
|
+
target: "entry-screen-frame",
|
|
87
|
+
chat: {
|
|
88
|
+
apiUrl: TEST_API_STREAMING,
|
|
89
|
+
initialMessages: INITIAL_MESSAGES,
|
|
90
|
+
conversationStarters: STARTERS,
|
|
91
|
+
entryScreenEnabled: true,
|
|
92
|
+
entryScreenTitle: "AskTIM about this problem",
|
|
93
|
+
},
|
|
96
94
|
},
|
|
97
95
|
},
|
|
98
96
|
};
|
|
@@ -104,9 +102,16 @@ exports.VideoStory = {
|
|
|
104
102
|
target: "video-frame",
|
|
105
103
|
},
|
|
106
104
|
parameters: {
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
105
|
+
payload: {
|
|
106
|
+
blockType: "video",
|
|
107
|
+
target: "video-frame",
|
|
108
|
+
chat: {
|
|
109
|
+
apiUrl: TEST_API_STREAMING,
|
|
110
|
+
conversationStarters: STARTERS,
|
|
111
|
+
},
|
|
112
|
+
summary: {
|
|
113
|
+
apiUrl: CONTENT_FILE_URL,
|
|
114
|
+
},
|
|
110
115
|
},
|
|
111
116
|
msw: {
|
|
112
117
|
handlers: [
|
|
@@ -127,10 +132,15 @@ exports.FlashcardConversationStartersStory = {
|
|
|
127
132
|
target: "starters-frame",
|
|
128
133
|
},
|
|
129
134
|
parameters: {
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
135
|
+
payload: {
|
|
136
|
+
blockType: "video",
|
|
137
|
+
target: "starters-frame",
|
|
138
|
+
chat: {
|
|
139
|
+
apiUrl: TEST_API_STREAMING,
|
|
140
|
+
},
|
|
141
|
+
summary: {
|
|
142
|
+
apiUrl: CONTENT_FILE_URL,
|
|
143
|
+
},
|
|
134
144
|
},
|
|
135
145
|
msw: {
|
|
136
146
|
handlers: [
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,241 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
const react_1 = require("@testing-library/react");
|
|
13
|
+
const user_event_1 = require("@testing-library/user-event");
|
|
14
|
+
const RemoteTutorDrawer_1 = require("./RemoteTutorDrawer");
|
|
15
|
+
const ThemeProvider_1 = require("../../components/ThemeProvider/ThemeProvider");
|
|
16
|
+
const React = require("react");
|
|
17
|
+
const msw_1 = require("msw");
|
|
18
|
+
const node_1 = require("msw/node");
|
|
19
|
+
const TEST_API_STREAMING = "http://localhost:4567/test";
|
|
20
|
+
const CONTENT_FILE_URL = "http://localhost:4567/api/v1/contentfiles/1";
|
|
21
|
+
const CONTENT_RESPONSE = {
|
|
22
|
+
count: 1,
|
|
23
|
+
next: null,
|
|
24
|
+
previous: null,
|
|
25
|
+
results: [
|
|
26
|
+
{
|
|
27
|
+
id: 1,
|
|
28
|
+
summary: "This is a test summary",
|
|
29
|
+
flashcards: [
|
|
30
|
+
{
|
|
31
|
+
question: "Test question 1?",
|
|
32
|
+
answer: "Test answer 1",
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
question: "Test question 2?",
|
|
36
|
+
answer: "Test answer 2",
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
question: "Test question 3?",
|
|
40
|
+
answer: "Test answer 3",
|
|
41
|
+
},
|
|
42
|
+
],
|
|
43
|
+
},
|
|
44
|
+
],
|
|
45
|
+
};
|
|
46
|
+
class MockResizeObserver {
|
|
47
|
+
constructor() {
|
|
48
|
+
this.observe = jest.fn();
|
|
49
|
+
this.unobserve = jest.fn();
|
|
50
|
+
this.disconnect = jest.fn();
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
global.ResizeObserver = MockResizeObserver;
|
|
54
|
+
describe("RemoteTutorDrawer", () => {
|
|
55
|
+
const server = (0, node_1.setupServer)(msw_1.http.post(TEST_API_STREAMING, () => __awaiter(void 0, void 0, void 0, function* () {
|
|
56
|
+
return msw_1.HttpResponse.text("AI Response");
|
|
57
|
+
})), msw_1.http.get(CONTENT_FILE_URL, () => {
|
|
58
|
+
return msw_1.HttpResponse.json(CONTENT_RESPONSE);
|
|
59
|
+
}));
|
|
60
|
+
beforeEach(() => {
|
|
61
|
+
jest.resetAllMocks();
|
|
62
|
+
});
|
|
63
|
+
afterEach(() => {
|
|
64
|
+
server.resetHandlers();
|
|
65
|
+
});
|
|
66
|
+
afterAll(() => server.close());
|
|
67
|
+
const setup = (message) => __awaiter(void 0, void 0, void 0, function* () {
|
|
68
|
+
server.listen();
|
|
69
|
+
(0, react_1.render)(React.createElement(RemoteTutorDrawer_1.RemoteTutorDrawer, { "data-testid": "remote-tutor-drawer", messageOrigin: "http://localhost:6006", target: "ai-chat" }), { wrapper: ThemeProvider_1.ThemeProvider });
|
|
70
|
+
yield react_1.screen.findByTestId("remote-tutor-drawer-waiting");
|
|
71
|
+
const event = new MessageEvent("message", {
|
|
72
|
+
data: message,
|
|
73
|
+
origin: "http://localhost:6006",
|
|
74
|
+
});
|
|
75
|
+
yield (0, react_1.act)(() => __awaiter(void 0, void 0, void 0, function* () {
|
|
76
|
+
window.dispatchEvent(event);
|
|
77
|
+
yield new Promise((resolve) => setTimeout(resolve, 100));
|
|
78
|
+
}));
|
|
79
|
+
});
|
|
80
|
+
test("Problem drawer opens showing title", () => __awaiter(void 0, void 0, void 0, function* () {
|
|
81
|
+
yield setup({
|
|
82
|
+
type: "smoot-design::tutor-drawer-open",
|
|
83
|
+
payload: {
|
|
84
|
+
blockType: "problem",
|
|
85
|
+
target: "ai-chat",
|
|
86
|
+
title: "Drawer Title",
|
|
87
|
+
chat: {
|
|
88
|
+
apiUrl: TEST_API_STREAMING,
|
|
89
|
+
},
|
|
90
|
+
},
|
|
91
|
+
});
|
|
92
|
+
react_1.screen.getByRole("heading", { name: "Drawer Title" });
|
|
93
|
+
}));
|
|
94
|
+
test("Video drawer opens showing chat entry screen and tabs", () => __awaiter(void 0, void 0, void 0, function* () {
|
|
95
|
+
yield setup({
|
|
96
|
+
type: "smoot-design::tutor-drawer-open",
|
|
97
|
+
payload: {
|
|
98
|
+
blockType: "video",
|
|
99
|
+
target: "ai-chat",
|
|
100
|
+
chat: {
|
|
101
|
+
entryScreenTitle: "Entry screen title",
|
|
102
|
+
apiUrl: TEST_API_STREAMING,
|
|
103
|
+
conversationStarters: [
|
|
104
|
+
{ content: "Prompt 1" },
|
|
105
|
+
{ content: "Prompt 2" },
|
|
106
|
+
{ content: "Prompt 3" },
|
|
107
|
+
],
|
|
108
|
+
},
|
|
109
|
+
summary: {
|
|
110
|
+
apiUrl: CONTENT_FILE_URL,
|
|
111
|
+
},
|
|
112
|
+
},
|
|
113
|
+
});
|
|
114
|
+
react_1.screen.getByText("Entry screen title");
|
|
115
|
+
react_1.screen.getByRole("tab", { name: "Chat" });
|
|
116
|
+
react_1.screen.getByRole("tab", { name: "Flashcards" });
|
|
117
|
+
react_1.screen.getByRole("tab", { name: "Summary" });
|
|
118
|
+
react_1.screen.getByRole("button", { name: "Prompt 1" });
|
|
119
|
+
react_1.screen.getByRole("button", { name: "Prompt 2" });
|
|
120
|
+
react_1.screen.getByRole("button", { name: "Prompt 3" });
|
|
121
|
+
}));
|
|
122
|
+
test("Video drawer chat entry screen selects starters from flashcards", () => __awaiter(void 0, void 0, void 0, function* () {
|
|
123
|
+
yield setup({
|
|
124
|
+
type: "smoot-design::tutor-drawer-open",
|
|
125
|
+
payload: {
|
|
126
|
+
blockType: "video",
|
|
127
|
+
target: "ai-chat",
|
|
128
|
+
chat: {
|
|
129
|
+
entryScreenTitle: "Entry screen title",
|
|
130
|
+
apiUrl: TEST_API_STREAMING,
|
|
131
|
+
},
|
|
132
|
+
summary: {
|
|
133
|
+
apiUrl: CONTENT_FILE_URL,
|
|
134
|
+
},
|
|
135
|
+
},
|
|
136
|
+
});
|
|
137
|
+
react_1.screen.getByRole("button", { name: "Test question 1?" });
|
|
138
|
+
react_1.screen.getByRole("button", { name: "Test question 2?" });
|
|
139
|
+
react_1.screen.getByRole("button", { name: "Test question 3?" });
|
|
140
|
+
}));
|
|
141
|
+
test("Video drawer chat entry screen shows default starters where no flashcards are available", server.boundary(() => __awaiter(void 0, void 0, void 0, function* () {
|
|
142
|
+
const contentResponse = JSON.parse(JSON.stringify(CONTENT_RESPONSE));
|
|
143
|
+
contentResponse.results[0].flashcards = null;
|
|
144
|
+
server.use(msw_1.http.get(CONTENT_FILE_URL, () => {
|
|
145
|
+
return msw_1.HttpResponse.json(contentResponse);
|
|
146
|
+
}));
|
|
147
|
+
yield setup({
|
|
148
|
+
type: "smoot-design::tutor-drawer-open",
|
|
149
|
+
payload: {
|
|
150
|
+
blockType: "video",
|
|
151
|
+
target: "ai-chat",
|
|
152
|
+
chat: {
|
|
153
|
+
entryScreenTitle: "Entry screen title",
|
|
154
|
+
apiUrl: TEST_API_STREAMING,
|
|
155
|
+
},
|
|
156
|
+
summary: {
|
|
157
|
+
apiUrl: CONTENT_FILE_URL,
|
|
158
|
+
},
|
|
159
|
+
},
|
|
160
|
+
});
|
|
161
|
+
react_1.screen.getByRole("button", {
|
|
162
|
+
name: "What are the most important concepts introduced in the video?",
|
|
163
|
+
});
|
|
164
|
+
react_1.screen.getByRole("button", {
|
|
165
|
+
name: "What examples are used to illustrate concepts covered in the video?",
|
|
166
|
+
});
|
|
167
|
+
react_1.screen.getByRole("button", {
|
|
168
|
+
name: "What are the key terms introduced in this video?",
|
|
169
|
+
});
|
|
170
|
+
})));
|
|
171
|
+
test("Video drawer chat entry screen displays default title", () => __awaiter(void 0, void 0, void 0, function* () {
|
|
172
|
+
yield setup({
|
|
173
|
+
type: "smoot-design::tutor-drawer-open",
|
|
174
|
+
payload: {
|
|
175
|
+
blockType: "video",
|
|
176
|
+
target: "ai-chat",
|
|
177
|
+
chat: {
|
|
178
|
+
apiUrl: TEST_API_STREAMING,
|
|
179
|
+
},
|
|
180
|
+
summary: {
|
|
181
|
+
apiUrl: CONTENT_FILE_URL,
|
|
182
|
+
},
|
|
183
|
+
},
|
|
184
|
+
});
|
|
185
|
+
react_1.screen.getByText("What do you want to know about this video?");
|
|
186
|
+
}));
|
|
187
|
+
test("Flashcard shows content and can be click navigated", server.boundary(() => __awaiter(void 0, void 0, void 0, function* () {
|
|
188
|
+
yield setup({
|
|
189
|
+
type: "smoot-design::tutor-drawer-open",
|
|
190
|
+
payload: {
|
|
191
|
+
blockType: "video",
|
|
192
|
+
target: "ai-chat",
|
|
193
|
+
chat: {
|
|
194
|
+
apiUrl: TEST_API_STREAMING,
|
|
195
|
+
},
|
|
196
|
+
summary: {
|
|
197
|
+
apiUrl: CONTENT_FILE_URL,
|
|
198
|
+
},
|
|
199
|
+
},
|
|
200
|
+
});
|
|
201
|
+
yield user_event_1.default.click(react_1.screen.getByRole("tab", { name: "Flashcards" }));
|
|
202
|
+
yield user_event_1.default.click(react_1.screen.getByText("Q: Test question 1?"));
|
|
203
|
+
react_1.screen.getByText("Answer: Test answer 1");
|
|
204
|
+
yield user_event_1.default.click(react_1.screen.getByRole("button", { name: "Next card" }));
|
|
205
|
+
yield user_event_1.default.click(react_1.screen.getByText("Q: Test question 2?"));
|
|
206
|
+
react_1.screen.getByText("Answer: Test answer 2");
|
|
207
|
+
yield user_event_1.default.click(react_1.screen.getByRole("button", { name: "Previous card" }));
|
|
208
|
+
react_1.screen.getByText("Q: Test question 1?");
|
|
209
|
+
})));
|
|
210
|
+
test("Flashcard shows content and can be keyboard navigated and cycles", server.boundary(() => __awaiter(void 0, void 0, void 0, function* () {
|
|
211
|
+
yield setup({
|
|
212
|
+
type: "smoot-design::tutor-drawer-open",
|
|
213
|
+
payload: {
|
|
214
|
+
blockType: "video",
|
|
215
|
+
target: "ai-chat",
|
|
216
|
+
chat: {
|
|
217
|
+
apiUrl: TEST_API_STREAMING,
|
|
218
|
+
},
|
|
219
|
+
summary: {
|
|
220
|
+
apiUrl: CONTENT_FILE_URL,
|
|
221
|
+
},
|
|
222
|
+
},
|
|
223
|
+
});
|
|
224
|
+
yield user_event_1.default.click(react_1.screen.getByRole("tab", { name: "Flashcards" }));
|
|
225
|
+
react_1.screen.getByText("Q: Test question 1?");
|
|
226
|
+
yield user_event_1.default.keyboard("{enter}");
|
|
227
|
+
react_1.screen.getByText("Answer: Test answer 1");
|
|
228
|
+
yield user_event_1.default.keyboard("{arrowright}");
|
|
229
|
+
react_1.screen.getByText("Q: Test question 2?");
|
|
230
|
+
yield user_event_1.default.keyboard("{enter}");
|
|
231
|
+
react_1.screen.getByText("Answer: Test answer 2");
|
|
232
|
+
yield user_event_1.default.keyboard("{arrowleft}");
|
|
233
|
+
react_1.screen.getByText("Q: Test question 1?");
|
|
234
|
+
yield user_event_1.default.keyboard("{arrowleft}");
|
|
235
|
+
react_1.screen.getByText("Q: Test question 3?");
|
|
236
|
+
yield user_event_1.default.keyboard("{arrowright}");
|
|
237
|
+
yield user_event_1.default.keyboard("{arrowright}");
|
|
238
|
+
yield user_event_1.default.keyboard("{arrowright}");
|
|
239
|
+
react_1.screen.getByText("Q: Test question 3?");
|
|
240
|
+
})));
|
|
241
|
+
});
|
|
@@ -177,4 +177,35 @@ describe("AiChat", () => {
|
|
|
177
177
|
const alert = yield react_1.screen.findByRole("alert");
|
|
178
178
|
expect(alert).toHaveTextContent("An unexpected error has occurred");
|
|
179
179
|
}));
|
|
180
|
+
test("Shows the entry screen if entryScreenEnabled is true", () => __awaiter(void 0, void 0, void 0, function* () {
|
|
181
|
+
setup({
|
|
182
|
+
entryScreenEnabled: true,
|
|
183
|
+
entryScreenTitle: "Entry Screen Title",
|
|
184
|
+
});
|
|
185
|
+
yield expect(react_1.screen.getByText("Entry Screen Title")).toBeInTheDocument();
|
|
186
|
+
}));
|
|
187
|
+
test("User can submit a prompt from the entry screen", () => __awaiter(void 0, void 0, void 0, function* () {
|
|
188
|
+
setup({
|
|
189
|
+
entryScreenEnabled: true,
|
|
190
|
+
entryScreenTitle: "Entry Screen Title",
|
|
191
|
+
initialMessages: [],
|
|
192
|
+
conversationStarters: [],
|
|
193
|
+
});
|
|
194
|
+
yield user_event_1.default.click(react_1.screen.getByRole("textbox"));
|
|
195
|
+
yield user_event_1.default.paste("User message");
|
|
196
|
+
yield user_event_1.default.click(react_1.screen.getByRole("button", { name: "Send" }));
|
|
197
|
+
const messages = getMessages();
|
|
198
|
+
expect(messages[0]).toHaveTextContent("User message");
|
|
199
|
+
}));
|
|
200
|
+
test("User can click starter on the entry screen to submit a prompt", () => __awaiter(void 0, void 0, void 0, function* () {
|
|
201
|
+
setup({
|
|
202
|
+
entryScreenEnabled: true,
|
|
203
|
+
entryScreenTitle: "Entry Screen Title",
|
|
204
|
+
initialMessages: [],
|
|
205
|
+
conversationStarters: [{ content: "Starter 1" }],
|
|
206
|
+
});
|
|
207
|
+
yield user_event_1.default.click(react_1.screen.getByRole("button", { name: "Starter 1" }));
|
|
208
|
+
const messages = getMessages();
|
|
209
|
+
expect(messages[0]).toHaveTextContent("Starter 1");
|
|
210
|
+
}));
|
|
180
211
|
});
|
|
@@ -3,7 +3,7 @@ import type { TabProps } from "@mui/material/Tab";
|
|
|
3
3
|
import type { TabListProps } from "@mui/lab/TabList";
|
|
4
4
|
import type { ButtonLinkProps } from "../Button/Button";
|
|
5
5
|
type StyleVariant = "chat";
|
|
6
|
-
|
|
6
|
+
type TabButtonListProps = TabListProps & {
|
|
7
7
|
styleVariant?: StyleVariant;
|
|
8
8
|
};
|
|
9
9
|
declare const TabButtonList: React.FC<TabButtonListProps>;
|
|
@@ -11,6 +11,15 @@ declare const TabLinkInner: React.ForwardRefExoticComponent<Omit<ButtonLinkProps
|
|
|
11
11
|
type TabButtonProps = Omit<TabProps<"button">, "color"> & {
|
|
12
12
|
styleVariant?: StyleVariant;
|
|
13
13
|
};
|
|
14
|
+
/**
|
|
15
|
+
* Wrapper around [MUI Tab](https://mui.com/material-ui/api/tab/) using our
|
|
16
|
+
* Button as the `component` implementation.
|
|
17
|
+
*/
|
|
14
18
|
declare const TabButton: (props: TabButtonProps) => React.JSX.Element;
|
|
19
|
+
/**
|
|
20
|
+
* Wrapper around [MUI Tab](https://mui.com/material-ui/api/tab/) using our
|
|
21
|
+
* ButtonLink as the `component` implementation.
|
|
22
|
+
*/
|
|
15
23
|
declare const TabButtonLink: ({ ...props }: TabProps<typeof TabLinkInner>) => React.JSX.Element;
|
|
16
24
|
export { TabButtonList, TabButton, TabButtonLink };
|
|
25
|
+
export type { TabButtonListProps, TabButtonProps };
|
|
@@ -23,7 +23,10 @@ const defaultTabListProps = {
|
|
|
23
23
|
allowScrollButtonsMobile: true,
|
|
24
24
|
scrollButtons: "auto",
|
|
25
25
|
};
|
|
26
|
-
const TabButtonList = (0, styled_1.default)((
|
|
26
|
+
const TabButtonList = (0, styled_1.default)((_a) => {
|
|
27
|
+
var { styleVariant } = _a, props = __rest(_a, ["styleVariant"]);
|
|
28
|
+
return (React.createElement(TabList_1.default, Object.assign({}, defaultTabListProps, props)));
|
|
29
|
+
})(({ theme, styleVariant }) => (Object.assign({ minHeight: "unset", ".MuiTabs-indicator": {
|
|
27
30
|
display: "none",
|
|
28
31
|
}, ".MuiTabs-flexContainer": {
|
|
29
32
|
gap: "8px",
|
|
@@ -77,8 +80,16 @@ const TabLinkInner = React.forwardRef((props, ref) => {
|
|
|
77
80
|
return React.createElement(TabLinkStyled, Object.assign({}, defaultTabButtonProps, others, { ref: ref }));
|
|
78
81
|
});
|
|
79
82
|
TabLinkInner.displayName = "TabLinkInner";
|
|
83
|
+
/**
|
|
84
|
+
* Wrapper around [MUI Tab](https://mui.com/material-ui/api/tab/) using our
|
|
85
|
+
* Button as the `component` implementation.
|
|
86
|
+
*/
|
|
80
87
|
const TabButton = (props) => (React.createElement(Tab_1.default, Object.assign({}, props, { component: TabButtonInner })));
|
|
81
88
|
exports.TabButton = TabButton;
|
|
89
|
+
/**
|
|
90
|
+
* Wrapper around [MUI Tab](https://mui.com/material-ui/api/tab/) using our
|
|
91
|
+
* ButtonLink as the `component` implementation.
|
|
92
|
+
*/
|
|
82
93
|
const TabButtonLink = (_a) => {
|
|
83
94
|
var props = __rest(_a, []);
|
|
84
95
|
return (React.createElement(Tab_1.default, Object.assign({}, props, { component: TabLinkInner })));
|
package/dist/cjs/index.d.ts
CHANGED
|
@@ -12,4 +12,5 @@ export { TextField } from "./components/TextField/TextField";
|
|
|
12
12
|
export type { TextFieldProps } from "./components/TextField/TextField";
|
|
13
13
|
export { SrAnnouncer } from "./components/SrAnnouncer/SrAnnouncer";
|
|
14
14
|
export type { SrAnnouncerProps } from "./components/SrAnnouncer/SrAnnouncer";
|
|
15
|
+
export { TabButton, TabButtonLink, TabButtonList, } from "./components/TabButtons/TabButtonList";
|
|
15
16
|
export { VisuallyHidden } from "./components/VisuallyHidden/VisuallyHidden";
|
package/dist/cjs/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
"use client";
|
|
3
3
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
-
exports.VisuallyHidden = exports.SrAnnouncer = exports.TextField = exports.Input = exports.ActionButtonLink = exports.ActionButton = exports.ButtonLink = exports.Button = exports.createTheme = exports.ThemeProvider = exports.Global = exports.css = exports.styled = void 0;
|
|
4
|
+
exports.VisuallyHidden = exports.TabButtonList = exports.TabButtonLink = exports.TabButton = exports.SrAnnouncer = exports.TextField = exports.Input = exports.ActionButtonLink = exports.ActionButton = exports.ButtonLink = exports.Button = exports.createTheme = exports.ThemeProvider = exports.Global = exports.css = exports.styled = void 0;
|
|
5
5
|
var styled_1 = require("@emotion/styled");
|
|
6
6
|
Object.defineProperty(exports, "styled", { enumerable: true, get: function () { return styled_1.default; } });
|
|
7
7
|
var react_1 = require("@emotion/react");
|
|
@@ -22,5 +22,9 @@ var TextField_1 = require("./components/TextField/TextField");
|
|
|
22
22
|
Object.defineProperty(exports, "TextField", { enumerable: true, get: function () { return TextField_1.TextField; } });
|
|
23
23
|
var SrAnnouncer_1 = require("./components/SrAnnouncer/SrAnnouncer");
|
|
24
24
|
Object.defineProperty(exports, "SrAnnouncer", { enumerable: true, get: function () { return SrAnnouncer_1.SrAnnouncer; } });
|
|
25
|
+
var TabButtonList_1 = require("./components/TabButtons/TabButtonList");
|
|
26
|
+
Object.defineProperty(exports, "TabButton", { enumerable: true, get: function () { return TabButtonList_1.TabButton; } });
|
|
27
|
+
Object.defineProperty(exports, "TabButtonLink", { enumerable: true, get: function () { return TabButtonList_1.TabButtonLink; } });
|
|
28
|
+
Object.defineProperty(exports, "TabButtonList", { enumerable: true, get: function () { return TabButtonList_1.TabButtonList; } });
|
|
25
29
|
var VisuallyHidden_1 = require("./components/VisuallyHidden/VisuallyHidden");
|
|
26
30
|
Object.defineProperty(exports, "VisuallyHidden", { enumerable: true, get: function () { return VisuallyHidden_1.VisuallyHidden; } });
|
|
@@ -72,12 +72,12 @@ export const FlashcardsScreen = ({ flashcards, wasKeyboardFocus, }) => {
|
|
|
72
72
|
return (React.createElement(Container, { ref: containerRef },
|
|
73
73
|
React.createElement(Flashcard, { ref: flashcardRef, content: flashcards[cardIndex], "aria-label": `Flashcard ${cardIndex + 1} of ${flashcards.length}` }),
|
|
74
74
|
React.createElement(Navigation, null,
|
|
75
|
-
React.createElement(ActionButton, { onClick: () => setCardIndex(cardIndex - 1), disabled: cardIndex === 0, variant: "secondary", color: "secondary", size: "small" },
|
|
75
|
+
React.createElement(ActionButton, { onClick: () => setCardIndex(cardIndex - 1), disabled: cardIndex === 0, variant: "secondary", color: "secondary", size: "small", "aria-label": "Previous card" },
|
|
76
76
|
React.createElement(RiArrowLeftLine, { "aria-hidden": true })),
|
|
77
77
|
React.createElement(Page, null,
|
|
78
78
|
cardIndex + 1,
|
|
79
79
|
" / ",
|
|
80
80
|
flashcards.length),
|
|
81
|
-
React.createElement(ActionButton, { onClick: () => setCardIndex(cardIndex + 1), disabled: cardIndex === flashcards.length - 1, variant: "secondary", color: "secondary", size: "small" },
|
|
81
|
+
React.createElement(ActionButton, { onClick: () => setCardIndex(cardIndex + 1), disabled: cardIndex === flashcards.length - 1, variant: "secondary", color: "secondary", size: "small", "aria-label": "Next card" },
|
|
82
82
|
React.createElement(RiArrowRightLine, { "aria-hidden": true })))));
|
|
83
83
|
};
|
|
@@ -7,6 +7,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
7
7
|
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
8
8
|
});
|
|
9
9
|
};
|
|
10
|
+
// @format
|
|
10
11
|
import * as React from "react";
|
|
11
12
|
import { useEffect, useState, useRef, useMemo } from "react";
|
|
12
13
|
import styled from "@emotion/styled";
|
|
@@ -212,26 +213,28 @@ const RemoteTutorDrawer = ({ messageOrigin, transformBody = identity, className,
|
|
|
212
213
|
};
|
|
213
214
|
}, [messageOrigin, target]);
|
|
214
215
|
useEffect(() => {
|
|
215
|
-
|
|
216
|
+
var _a;
|
|
217
|
+
(_a = scrollElement === null || scrollElement === void 0 ? void 0 : scrollElement.scrollTo) === null || _a === void 0 ? void 0 : _a.call(scrollElement, {
|
|
216
218
|
top: tab === "chat" ? scrollElement.scrollHeight : 0,
|
|
217
219
|
});
|
|
218
220
|
}, [tab, scrollElement]);
|
|
219
221
|
const conversationStarters = useMemo(() => {
|
|
222
|
+
var _a;
|
|
220
223
|
if (!payload)
|
|
221
224
|
return [];
|
|
222
225
|
return (payload.chat.conversationStarters ||
|
|
223
|
-
((response === null || response === void 0 ? void 0 : response.flashcards)
|
|
226
|
+
(((_a = response === null || response === void 0 ? void 0 : response.flashcards) === null || _a === void 0 ? void 0 : _a.length) && response.flashcards.length >= 3
|
|
224
227
|
? randomItems(response.flashcards, 3).map((flashcard) => ({
|
|
225
228
|
content: flashcard.question,
|
|
226
229
|
}))
|
|
227
230
|
: DEFAULT_VIDEO_STARTERS));
|
|
228
231
|
}, [payload, response]);
|
|
229
232
|
if (!payload) {
|
|
230
|
-
return
|
|
233
|
+
return React.createElement("div", { "data-testid": "remote-tutor-drawer-waiting" });
|
|
231
234
|
}
|
|
232
235
|
const { blockType, chat } = payload;
|
|
233
236
|
const hasTabs = blockType === "video";
|
|
234
|
-
return (React.createElement(Drawer, { className: className, PaperProps: {
|
|
237
|
+
return (React.createElement(Drawer, { "data-testid": "remote-tutor-drawer", className: className, PaperProps: {
|
|
235
238
|
ref: paperRefCallback,
|
|
236
239
|
sx: {
|
|
237
240
|
width: "900px",
|
|
@@ -246,7 +249,7 @@ const RemoteTutorDrawer = ({ messageOrigin, transformBody = identity, className,
|
|
|
246
249
|
React.createElement(Header, null,
|
|
247
250
|
React.createElement(Title, null,
|
|
248
251
|
payload.title ? React.createElement(RiSparkling2Line, null) : null,
|
|
249
|
-
React.createElement(Typography, { variant: "body1" }, ((_b = payload.title) === null || _b === void 0 ? void 0 : _b.includes("AskTIM")) ? (React.createElement(React.Fragment, null,
|
|
252
|
+
React.createElement(Typography, { variant: "body1", component: "h2" }, ((_b = payload.title) === null || _b === void 0 ? void 0 : _b.includes("AskTIM")) ? (React.createElement(React.Fragment, null,
|
|
250
253
|
"Ask",
|
|
251
254
|
React.createElement("strong", null, "TIM"),
|
|
252
255
|
payload.title.replace("AskTIM", ""))) : (payload.title))),
|