Skip to content

Commit 7bf10f2

Browse files
authored
SCAL-239365 (#212)
1 parent b26d159 commit 7bf10f2

File tree

5 files changed

+536
-3
lines changed

5 files changed

+536
-3
lines changed

src/embed/bodyless-conversation.spec.ts

Lines changed: 308 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ describe('SpotterAgentEmbed', () => {
3131
fetchMock.resetMocks();
3232
});
3333

34-
test('should render the bodyless conversation embed', async () => {
34+
test('should render the SpotterAgent embed', async () => {
3535
fetchMock.mockResponses(
3636
JSON.stringify({
3737
data: {
@@ -137,4 +137,311 @@ describe('SpotterAgentEmbed', () => {
137137
const errorResult = await spotterEmbed.sendMessage('userMessage');
138138
expect(errorResult.error instanceof Error).toBeTruthy();
139139
});
140+
141+
test('should apply containerClassName to the container element', async () => {
142+
fetchMock.mockResponses(
143+
JSON.stringify({
144+
data: {
145+
ConvAssist__createConversation: {
146+
convId: 'conversationId',
147+
initialCtx: {
148+
type: 'TS_ANSWER',
149+
tsAnsCtx: {
150+
sessionId: 'sessionId',
151+
genNo: 1,
152+
stateKey: {
153+
transactionId: 'transactionId',
154+
generationNumber: 1,
155+
},
156+
worksheet: {
157+
worksheetId: 'worksheetId',
158+
worksheetName: 'GTM',
159+
},
160+
},
161+
},
162+
},
163+
},
164+
}),
165+
JSON.stringify({
166+
data: {
167+
ConvAssist__sendMessage: {
168+
responses: [
169+
{
170+
msgId: 'msgId',
171+
data: {
172+
asstRespData: {
173+
tool: 'TS_NLS',
174+
asstRespText: '',
175+
nlsAnsData: {
176+
sageQuerySuggestions: [
177+
{
178+
llmReasoning: {
179+
assumptions: 'You want the total [COL|sales] for [COL|item_type] [VAL|jackets] for [VAL|this year].',
180+
clarifications: '',
181+
interpretation: '',
182+
__typename: 'eureka_SageQuerySuggestion_LLMReasoning',
183+
},
184+
tokens: [
185+
'sum sales',
186+
"item type = 'jackets'",
187+
"date = 'this year'",
188+
],
189+
tmlTokens: [
190+
'sum [sales]',
191+
"[date] = [date].'this year'",
192+
"[item type] = [item type].'jackets'",
193+
],
194+
worksheetId: 'worksheetId',
195+
description: '',
196+
title: '',
197+
cached: false,
198+
sqlQuery: "SELECT SUM(sales) FROM __Sample_Retail_Apparel WHERE item_type = 'jackets' AND date = _this_year();",
199+
sessionId: 'sessionId',
200+
genNo: 2,
201+
formulaInfo: [],
202+
tmlPhrases: [],
203+
stateKey: {
204+
transactionId: 'transactionId',
205+
generationNumber: 1,
206+
__typename: 'sage_auto_complete_v2_ACStateKey',
207+
},
208+
__typename: 'eureka_SageQuerySuggestion',
209+
},
210+
],
211+
responseType: 'ANSWER',
212+
__typename: 'convassist_nls_tool_NLSToolAsstRespData',
213+
},
214+
__typename: 'convassist_AsstResponseData',
215+
},
216+
__typename: 'convassist_MessageData',
217+
},
218+
type: 'ASST_RESPONSE',
219+
__typename: 'convassist_MessagePayload',
220+
},
221+
],
222+
__typename: 'convassist_SendMessageResponse',
223+
},
224+
},
225+
}),
226+
);
227+
228+
const viewConfig: SpotterAgentEmbedViewConfig = {
229+
worksheetId: 'worksheetId',
230+
containerClassName: 'custom-conversation-container',
231+
};
232+
233+
const spotterAgentEmbed = new SpotterAgentEmbed(viewConfig);
234+
const result = await spotterAgentEmbed.sendMessage('userMessage');
235+
236+
// Verify that the container has the custom class name
237+
expect(result.container.className).toBe('custom-conversation-container');
238+
239+
// Also verify the iframe src is correct
240+
const iframeSrc = getIFrameSrc(result.container);
241+
expectUrlToHaveParamsWithValues(iframeSrc, {
242+
sessionId: 'sessionId',
243+
genNo: 2,
244+
acSessionId: 'transactionId',
245+
acGenNo: 1,
246+
});
247+
});
248+
249+
test('should not set className when containerClassName is not provided', async () => {
250+
fetchMock.mockResponses(
251+
JSON.stringify({
252+
data: {
253+
ConvAssist__createConversation: {
254+
convId: 'conversationId',
255+
initialCtx: {
256+
type: 'TS_ANSWER',
257+
tsAnsCtx: {
258+
sessionId: 'sessionId',
259+
genNo: 1,
260+
stateKey: {
261+
transactionId: 'transactionId',
262+
generationNumber: 1,
263+
},
264+
worksheet: {
265+
worksheetId: 'worksheetId',
266+
worksheetName: 'GTM',
267+
},
268+
},
269+
},
270+
},
271+
},
272+
}),
273+
JSON.stringify({
274+
data: {
275+
ConvAssist__sendMessage: {
276+
responses: [
277+
{
278+
msgId: 'msgId',
279+
data: {
280+
asstRespData: {
281+
tool: 'TS_NLS',
282+
asstRespText: '',
283+
nlsAnsData: {
284+
sageQuerySuggestions: [
285+
{
286+
llmReasoning: {
287+
assumptions: 'You want the total [COL|sales] for [COL|item_type] [VAL|jackets] for [VAL|this year].',
288+
clarifications: '',
289+
interpretation: '',
290+
__typename: 'eureka_SageQuerySuggestion_LLMReasoning',
291+
},
292+
tokens: [
293+
'sum sales',
294+
"item type = 'jackets'",
295+
"date = 'this year'",
296+
],
297+
tmlTokens: [
298+
'sum [sales]',
299+
"[date] = [date].'this year'",
300+
"[item type] = [item type].'jackets'",
301+
],
302+
worksheetId: 'worksheetId',
303+
description: '',
304+
title: '',
305+
cached: false,
306+
sqlQuery: "SELECT SUM(sales) FROM __Sample_Retail_Apparel WHERE item_type = 'jackets' AND date = _this_year();",
307+
sessionId: 'sessionId',
308+
genNo: 2,
309+
formulaInfo: [],
310+
tmlPhrases: [],
311+
stateKey: {
312+
transactionId: 'transactionId',
313+
generationNumber: 1,
314+
__typename: 'sage_auto_complete_v2_ACStateKey',
315+
},
316+
__typename: 'eureka_SageQuerySuggestion',
317+
},
318+
],
319+
responseType: 'ANSWER',
320+
__typename: 'convassist_nls_tool_NLSToolAsstRespData',
321+
},
322+
__typename: 'convassist_AsstResponseData',
323+
},
324+
__typename: 'convassist_MessageData',
325+
},
326+
type: 'ASST_RESPONSE',
327+
__typename: 'convassist_MessagePayload',
328+
},
329+
],
330+
__typename: 'convassist_SendMessageResponse',
331+
},
332+
},
333+
}),
334+
);
335+
336+
const viewConfig: SpotterAgentEmbedViewConfig = {
337+
worksheetId: 'worksheetId',
338+
// No containerClassName provided
339+
};
340+
341+
const spotterAgentEmbed = new SpotterAgentEmbed(viewConfig);
342+
const result = await spotterAgentEmbed.sendMessage('userMessage');
343+
344+
// Verify that the container has no class name (empty string)
345+
expect(result.container.className).toBe('');
346+
});
347+
348+
test('should handle hideActions parameter correctly', async () => {
349+
fetchMock.mockResponses(
350+
JSON.stringify({
351+
data: {
352+
ConvAssist__createConversation: {
353+
convId: 'conversationId',
354+
initialCtx: {
355+
type: 'TS_ANSWER',
356+
tsAnsCtx: {
357+
sessionId: 'sessionId',
358+
genNo: 1,
359+
stateKey: {
360+
transactionId: 'transactionId',
361+
generationNumber: 1,
362+
},
363+
worksheet: {
364+
worksheetId: 'worksheetId',
365+
worksheetName: 'GTM',
366+
},
367+
},
368+
},
369+
},
370+
},
371+
}),
372+
JSON.stringify({
373+
data: {
374+
ConvAssist__sendMessage: {
375+
responses: [
376+
{
377+
msgId: 'msgId',
378+
data: {
379+
asstRespData: {
380+
tool: 'TS_NLS',
381+
asstRespText: '',
382+
nlsAnsData: {
383+
sageQuerySuggestions: [
384+
{
385+
llmReasoning: {
386+
assumptions: 'You want the total [COL|sales] for [COL|item_type] [VAL|jackets] for [VAL|this year].',
387+
clarifications: '',
388+
interpretation: '',
389+
__typename: 'eureka_SageQuerySuggestion_LLMReasoning',
390+
},
391+
tokens: [
392+
'sum sales',
393+
"item type = 'jackets'",
394+
"date = 'this year'",
395+
],
396+
tmlTokens: [
397+
'sum [sales]',
398+
"[date] = [date].'this year'",
399+
"[item type] = [item type].'jackets'",
400+
],
401+
worksheetId: 'worksheetId',
402+
description: '',
403+
title: '',
404+
cached: false,
405+
sqlQuery: "SELECT SUM(sales) FROM __Sample_Retail_Apparel WHERE item_type = 'jackets' AND date = _this_year();",
406+
sessionId: 'sessionId',
407+
genNo: 2,
408+
formulaInfo: [],
409+
tmlPhrases: [],
410+
stateKey: {
411+
transactionId: 'transactionId',
412+
generationNumber: 1,
413+
__typename: 'sage_auto_complete_v2_ACStateKey',
414+
},
415+
__typename: 'eureka_SageQuerySuggestion',
416+
},
417+
],
418+
responseType: 'ANSWER',
419+
__typename: 'convassist_nls_tool_NLSToolAsstRespData',
420+
},
421+
__typename: 'convassist_AsstResponseData',
422+
},
423+
__typename: 'convassist_MessageData',
424+
},
425+
type: 'ASST_RESPONSE',
426+
__typename: 'convassist_MessagePayload',
427+
},
428+
],
429+
__typename: 'convassist_SendMessageResponse',
430+
},
431+
},
432+
}),
433+
);
434+
435+
const viewConfig: SpotterAgentEmbedViewConfig = {
436+
worksheetId: 'worksheetId',
437+
hiddenActions: [Action.Download, Action.Save], // This should trigger the HideActions branch
438+
};
439+
440+
const spotterAgentEmbed = new SpotterAgentEmbed(viewConfig);
441+
const result = await spotterAgentEmbed.sendMessage('userMessage');
442+
443+
// Verify the iframe src contains the hideActions parameter
444+
const iframeSrc = getIFrameSrc(result.container);
445+
expect(iframeSrc).toContain('hideAction');
446+
});
140447
});

src/embed/bodyless-conversation.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,11 @@ export interface SpotterAgentEmbedViewConfig extends ViewConfig {
1313
* The ID of the worksheet to use for the conversation.
1414
*/
1515
worksheetId: string;
16+
17+
/**
18+
* Optional CSS class name to add to the container div.
19+
*/
20+
containerClassName?: string;
1621
}
1722

1823
/**
@@ -111,6 +116,10 @@ export class SpotterAgentEmbed {
111116
}
112117

113118
const container = document.createElement('div');
119+
if (this.viewConfig.containerClassName) {
120+
container.className = this.viewConfig.containerClassName;
121+
}
122+
114123
const embed = new ConversationMessage(container, {
115124
...this.viewConfig,
116125
sessionId: data.sessionId,

src/react/all-types-export.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ export {
1212
SpotterEmbed,
1313
ConversationEmbed,
1414
PreRenderedConversationEmbed,
15+
SpotterAgentEmbed,
1516
useEmbedRef,
1617
useInit,
1718
} from './index';

0 commit comments

Comments
 (0)