Skip to content

Commit 7dd2934

Browse files
feat(boxai-sidebar): Box AI Landing page cache (#4009)
* feat(boxai-sidebar): Box AI Landing page cache * feat(boxai-sidebar): UT updated * feat(boxai-sidebar): content-answers version bump * feat(boxai-sidebar): Tests cleanup * feat(boxai-sidebar): Tests cleanup * feat(boxai-sidebar): Skip failing tests * feat(boxai-sidebar): Landing page bump and tests adjustment * feat(boxai-sidebar): Tests adjustment
1 parent 73c77e6 commit 7dd2934

File tree

10 files changed

+63
-56
lines changed

10 files changed

+63
-56
lines changed

package.json

+2-2
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,7 @@
125125
"@box/blueprint-web": "^9.18.11",
126126
"@box/blueprint-web-assets": "4.36.0",
127127
"@box/box-ai-agent-selector": "^0.31.0",
128-
"@box/box-ai-content-answers": "^0.106.0",
128+
"@box/box-ai-content-answers": "^0.109.4",
129129
"@box/cldr-data": "^34.2.0",
130130
"@box/combobox-with-api": "^0.28.4",
131131
"@box/frontend": "^10.0.1",
@@ -308,7 +308,7 @@
308308
"@box/blueprint-web": "^9.18.11",
309309
"@box/blueprint-web-assets": "^4.36.0",
310310
"@box/box-ai-agent-selector": "^0.31.0",
311-
"@box/box-ai-content-answers": "^0.106.0",
311+
"@box/box-ai-content-answers": "^0.109.4",
312312
"@box/cldr-data": ">=34.2.0",
313313
"@box/combobox-with-api": "^0.28.4",
314314
"@box/item-icon": "^0.9.58",

src/elements/common/content-answers/__tests__/ContentAnswersModal.test.tsx

+25-12
Original file line numberDiff line numberDiff line change
@@ -52,9 +52,19 @@ describe('elements/common/content-answers/ContentAnswersModal', () => {
5252
const submitButton = screen.getByRole('button', { name: 'Ask' });
5353
await userEvent.click(submitButton);
5454

55-
expect(mockApi.getIntelligenceAPI().ask).toBeCalledWith(mockQuestion, [{ id: mockFile.id, type: 'file' }], [], {
56-
include_citations: true,
57-
});
55+
expect(mockApi.getIntelligenceAPI().ask).toBeCalledWith(
56+
mockQuestion,
57+
[
58+
{
59+
id: mockFile.id,
60+
type: 'file',
61+
},
62+
],
63+
[],
64+
{
65+
include_citations: true,
66+
},
67+
);
5868

5969
expect(onAskMock).toBeCalled();
6070
expect(screen.getByText(answer)).toBeInTheDocument();
@@ -70,7 +80,7 @@ describe('elements/common/content-answers/ContentAnswersModal', () => {
7080
const submitButton = screen.getByRole('button', { name: 'Ask' });
7181
await userEvent.click(submitButton);
7282

73-
expect(screen.getByText('The Box AI service was unavailable.')).toBeInTheDocument();
83+
expect(screen.getByText('Box AI is having trouble generating a response right now. Please try again.')).toBeInTheDocument();
7484
});
7585

7686
test('should render retry button when ask request fails', async () => {
@@ -136,17 +146,20 @@ describe('elements/common/content-answers/ContentAnswersModal', () => {
136146
);
137147
});
138148

139-
test('renders suggested questions when provided', () => {
140-
const suggestedQuestions = [{ id: '1', label: 'Suggested Question 1', prompt: 'Prompt 1' }];
141-
renderComponent(mockApi, { suggestedQuestions });
149+
// Skipping those tests, since now suggested questions will be a part of a new landing page, which is turned off for ContentAnswersModal
150+
describe.skip('should render suggested questions', () => {
151+
test('renders suggested questions when provided', () => {
152+
const suggestedQuestions = [{ id: '1', label: 'Suggested Question 1', prompt: 'Prompt 1' }];
153+
renderComponent(mockApi, { suggestedQuestions });
142154

143-
expect(screen.getByText('Suggested Question 1')).toBeInTheDocument();
144-
});
155+
expect(screen.getByText('Suggested Question 1')).toBeInTheDocument();
156+
});
145157

146-
test('renders localized questions when suggestedQuestions is not provided', () => {
147-
renderComponent();
158+
test('renders localized questions when suggestedQuestions is not provided', () => {
159+
renderComponent();
148160

149-
expect(screen.getByText('Summarize this document')).toBeInTheDocument();
161+
expect(screen.getByText('Summarize this document')).toBeInTheDocument();
162+
});
150163
});
151164

152165
test('should call onClearConversation when the conversation is cleared', async () => {

src/elements/content-preview/stories/tests/ContentPreview-visual.stories.js

+16-34
Original file line numberDiff line numberDiff line change
@@ -24,13 +24,7 @@ export const basic = {
2424

2525
const modal = within(dialog);
2626
expect(modal.getByText(/Welcome to Box AI/i)).toBeInTheDocument();
27-
expect(modal.getByText('Ask Box AI')).toBeInTheDocument();
28-
expect(modal.getByText('This chat will be cleared when you close this pdf')).toBeInTheDocument();
29-
30-
expect(modal.getByText('Summarize this document')).toBeInTheDocument();
31-
expect(modal.getByText('What are the key takeaways?')).toBeInTheDocument();
32-
expect(modal.getByText('How can this document be improved?')).toBeInTheDocument();
33-
expect(modal.getByText('Are there any next steps defined?')).toBeInTheDocument();
27+
expect(modal.getByText('Chat cleared when you close pdf')).toBeInTheDocument();
3428

3529
expect(modal.getByText('Ask Box AI')).toBeInTheDocument();
3630
},
@@ -76,27 +70,6 @@ export const submitAnswer = {
7670
},
7771
};
7872

79-
export const clickOnSuggestion = {
80-
play: async ({ canvasElement }) => {
81-
const canvas = within(canvasElement);
82-
const button = await canvas.findByRole('button', { name: 'Box AI' }, { timeout: WAIT_TIMEOUT });
83-
expect(button).toBeInTheDocument();
84-
await userEvent.click(button);
85-
86-
const dialog = await waitFor(() => document.querySelector('[role="dialog"]'));
87-
expect(dialog).toBeInTheDocument();
88-
89-
const modal = within(dialog);
90-
const suggestion = modal.getByText('Summarize this document');
91-
await userEvent.click(suggestion);
92-
93-
const answer = await modal.findByText('Public APIs are important because of key and important reasons.');
94-
expect(answer).toBeInTheDocument();
95-
96-
expect(modal.getByText('Based on:')).toBeInTheDocument();
97-
},
98-
};
99-
10073
export const hoverOverCitation = {
10174
play: async ({ canvasElement }) => {
10275
const canvas = within(canvasElement);
@@ -108,8 +81,11 @@ export const hoverOverCitation = {
10881

10982
expect(dialog).toBeInTheDocument();
11083
const modal = within(dialog);
111-
const suggestion = modal.getByText('Summarize this document');
112-
await userEvent.click(suggestion);
84+
const textInput = modal.getByRole('textbox', { name: 'Ask Box AI' });
85+
expect(textInput).toBeInTheDocument();
86+
textInput.focus();
87+
await userEvent.keyboard('Why are public APIs important?');
88+
await userEvent.click(modal.getByRole('button', { name: 'Ask' }), { pointerEventsCheck: 0 });
11389

11490
const answer = await modal.findByText('Public APIs are important because of key and important reasons.');
11591
expect(answer).toBeInTheDocument();
@@ -146,8 +122,11 @@ export const citationDisabled = {
146122
expect(dialog).toBeInTheDocument();
147123

148124
const modal = within(dialog);
149-
const suggestion = modal.getByText('Summarize this document');
150-
await userEvent.click(suggestion);
125+
const textInput = modal.getByRole('textbox', { name: 'Ask Box AI' });
126+
expect(textInput).toBeInTheDocument();
127+
textInput.focus();
128+
await userEvent.keyboard('Why are public APIs important?');
129+
await userEvent.click(modal.getByRole('button', { name: 'Ask' }), { pointerEventsCheck: 0 });
151130

152131
const answer = await modal.findByText('Public APIs are important because of key and important reasons.');
153132
expect(answer).toBeInTheDocument();
@@ -167,8 +146,11 @@ export const clearConversation = {
167146
expect(dialog).toBeInTheDocument();
168147

169148
const modal = within(dialog);
170-
const suggestion = modal.getByText('Summarize this document');
171-
await userEvent.click(suggestion);
149+
const textInput = modal.getByRole('textbox', { name: 'Ask Box AI' });
150+
expect(textInput).toBeInTheDocument();
151+
textInput.focus();
152+
await userEvent.keyboard('Why are public APIs important?');
153+
await userEvent.click(modal.getByRole('button', { name: 'Ask' }), { pointerEventsCheck: 0 });
172154

173155
const answer = await modal.findByText('Public APIs are important because of key and important reasons.');
174156
expect(answer).toBeInTheDocument();

src/elements/content-sidebar/BoxAISidebar.tsx

+1
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,7 @@ const BoxAISidebar = (props: BoxAISidebarProps) => {
142142
itemIDs={[fileID]}
143143
restoredQuestions={questionsWithoutInProgress}
144144
restoredSession={cache.encodedSession}
145+
restoredShouldShowLandingPage={cache.shouldShowLandingPage}
145146
shouldPreinitSession={shouldPreinitSession}
146147
suggestedQuestions={getSuggestedQuestions === null ? localizedQuestions : []}
147148
warningNotice={spreadsheetNotice}

src/elements/content-sidebar/BoxAISidebarContent.tsx

+7
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ function BoxAISidebarContent(props: ApiWrapperWithInjectedProps) {
4848
isResetChatEnabled,
4949
onSelectAgent,
5050
questions,
51+
shouldShowLandingPage,
5152
sendQuestion,
5253
stopQuestion,
5354
...rest
@@ -71,6 +72,10 @@ function BoxAISidebarContent(props: ApiWrapperWithInjectedProps) {
7172
const { agents, requestState, selectedAgent } = useAgents();
7273
const { questions: cacheQuestions } = cache;
7374

75+
if (cache.shouldShowLandingPage !== shouldShowLandingPage) {
76+
setCacheValue('shouldShowLandingPage', shouldShowLandingPage);
77+
}
78+
7479
if (cache.encodedSession !== encodedSession) {
7580
setCacheValue('encodedSession', encodedSession);
7681
}
@@ -204,6 +209,7 @@ function BoxAISidebarContent(props: ApiWrapperWithInjectedProps) {
204209
onUserIntentToUseAI={handleUserIntentToUseAI}
205210
stopQuestion={stopQuestion}
206211
submitQuestion={sendQuestion}
212+
shouldShowLandingPage={shouldShowLandingPage}
207213
showLoadingIndicator={isLoading && shouldPreinitSession}
208214
variant="sidebar"
209215
recordAction={recordAction}
@@ -231,6 +237,7 @@ function BoxAISidebarContent(props: ApiWrapperWithInjectedProps) {
231237
open={isModalOpen}
232238
questions={questions}
233239
recordAction={isModalOpen ? recordAction : undefined}
240+
shouldShowLandingPage={shouldShowLandingPage}
234241
showLoadingIndicator={false}
235242
stopPropagationOnEsc
236243
stopQuestion={stopQuestion}

src/elements/content-sidebar/SidebarPanels.js

+2-1
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,7 @@ class SidebarPanels extends React.Component<Props, State> {
141141
},
142142
encodedSession: null,
143143
questions: [],
144+
shouldShowLandingPage: true,
144145
};
145146

146147
componentDidMount() {
@@ -171,7 +172,7 @@ class SidebarPanels extends React.Component<Props, State> {
171172
}
172173
};
173174

174-
setBoxAiSidebarCacheValue = (key: 'agents' | 'encodedSession' | 'questions', value: any) => {
175+
setBoxAiSidebarCacheValue = (key: 'agents' | 'encodedSession' | 'questions' | 'shouldShowLandingPage', value: any) => {
175176
this.boxAiSidebarCache[key] = value;
176177
};
177178

src/elements/content-sidebar/__tests__/BoxAISidebar.test.tsx

+3
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ describe('elements/content-sidebar/BoxAISidebar', () => {
6868
encodedSession: '',
6969
questions: [],
7070
agents: mockAgents,
71+
shouldShowLandingPage: true,
7172
},
7273
createSessionRequest: jest.fn(() => ({ encodedSession: '1234' })),
7374
elementId: '123',
@@ -205,6 +206,7 @@ describe('elements/content-sidebar/BoxAISidebar', () => {
205206
},
206207
],
207208
agents: mockAgents,
209+
shouldShowLandingPage: false,
208210
},
209211
});
210212

@@ -254,6 +256,7 @@ describe('elements/content-sidebar/BoxAISidebar', () => {
254256
},
255257
],
256258
agents: mockAgents,
259+
shouldShowLandingPage: false,
257260
},
258261
});
259262

src/elements/content-sidebar/stories/tests/BoxAISidebar-visual.stories.tsx

+1-2
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,7 @@ export const basic: StoryObj<typeof BoxAISidebar> = {
1616
expect(clearButton).toBeInTheDocument();
1717

1818
expect(await canvas.findByText(/Welcome to Box AI/i)).toBeInTheDocument();
19-
expect(await canvas.findByText(/Ask questions about/i)).toBeInTheDocument();
20-
expect(await canvas.findByText('This chat will be cleared when you close this content')).toBeInTheDocument();
19+
expect(await canvas.findByText('Chat cleared when you close content')).toBeInTheDocument();
2120
expect(await canvas.findByPlaceholderText('Ask Box AI')).toBeInTheDocument();
2221
expect(await canvas.findByText('Summarize this document')).toBeInTheDocument();
2322
expect(await canvas.findByText('What are the key takeaways?')).toBeInTheDocument();

src/elements/content-sidebar/types/BoxAISidebarTypes.ts

+2-1
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ export type BoxAISidebarCache = {
55
agents: AgentState,
66
encodedSession: string | null,
77
questions: QuestionType[],
8+
shouldShowLandingPage: boolean,
89
};
910

10-
export type BoxAISidebarCacheSetter = (key: 'agents' | 'encodedSession' | 'questions', value: AgentState | QuestionType[] | string | null) => void;
11+
export type BoxAISidebarCacheSetter = (key: 'agents' | 'encodedSession' | 'questions' | 'shouldShowLandingPage', value: AgentState | QuestionType[] | string | boolean | null) => void;

yarn.lock

+4-4
Original file line numberDiff line numberDiff line change
@@ -1498,10 +1498,10 @@
14981498
resolved "https://registry.yarnpkg.com/@box/box-ai-agent-selector/-/box-ai-agent-selector-0.31.0.tgz#a2ef6c3c7284529ae268b609d04b6000348bb294"
14991499
integrity sha512-4+M/4g8LHJfZkP+7ISBKveQs2q5HeGvXv8B6/N8yFb9cpYuOjpKFxRvHyILdQWjwictHZbgY2XrNrpxbYGEXRQ==
15001500

1501-
"@box/box-ai-content-answers@^0.106.0":
1502-
version "0.106.0"
1503-
resolved "https://registry.yarnpkg.com/@box/box-ai-content-answers/-/box-ai-content-answers-0.106.0.tgz#ee2ea313e13b5c156b32bb0bc1c73dc9f2f8f07b"
1504-
integrity sha512-mWPo6Ls/7rIXoI9UPkel0zexlsqktzFcfVbumXx1Ie1cP8F76bK7tUXVjTEyZarw8H5K9CuvY34WN2ds/28cHA==
1501+
"@box/box-ai-content-answers@^0.109.4":
1502+
version "0.109.4"
1503+
resolved "https://registry.yarnpkg.com/@box/box-ai-content-answers/-/box-ai-content-answers-0.109.4.tgz#62aa53ddada3f60e308807035045b9e51185ca00"
1504+
integrity sha512-8p7km9MgODjIXYlDvlwsQ1+1pfqNVkdvVf5DtGhSHvwqoMccRNsbDSMk1vHg8dQ8BSD0eexKxUl2rzCUxyxS5A==
15051505

15061506
"@box/cldr-data@^34.2.0":
15071507
version "34.8.0"

0 commit comments

Comments
 (0)