Skip to content

Commit 23acee4

Browse files
DanilaRubleuskiDanila Rubleuski
and
Danila Rubleuski
authored
feat(boxai-sidebar): Cache custom suggested questions (#4019)
* feat(boxai-sidebar): Cache custom suggested questions * feat(boxai-sidebar): Prop fix * feat(boxai-sidebar): PR fix * feat(boxai-sidebar): PR fix * feat(boxai-sidebar): Bump box-ai-content-answers to 0.113.0 * feat(boxai-sidebar): PR fix --------- Co-authored-by: Danila Rubleuski <[email protected]>
1 parent 241c92d commit 23acee4

File tree

7 files changed

+81
-21
lines changed

7 files changed

+81
-21
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.112.1",
128+
"@box/box-ai-content-answers": "^0.113.0",
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.112.1",
311+
"@box/box-ai-content-answers": "^0.113.0",
312312
"@box/cldr-data": ">=34.2.0",
313313
"@box/combobox-with-api": "^0.28.4",
314314
"@box/item-icon": "^0.9.58",

src/elements/content-sidebar/BoxAISidebar.tsx

+10-2
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
*/
55
import * as React from 'react';
66
import { useIntl } from 'react-intl';
7-
import { type ItemType } from '@box/box-ai-content-answers';
7+
import {type ItemType, SuggestedQuestionType} from '@box/box-ai-content-answers';
88
import { AgentsProvider, RecordActionType } from '@box/box-ai-agent-selector';
99
import BoxAISidebarContent from './BoxAISidebarContent';
1010
import { BoxAISidebarContext } from './context/BoxAISidebarContext';
@@ -133,22 +133,30 @@ const BoxAISidebar = (props: BoxAISidebarProps) => {
133133
spreadsheetNotice = formatMessage(messages.welcomeMessageSpreadsheetNotice);
134134
}
135135

136+
const handleSuggestedQuestionsFetched = (fetchedSuggestedQuestions: SuggestedQuestionType[]) => {
137+
setCacheValue('suggestedQuestions', fetchedSuggestedQuestions);
138+
};
139+
140+
const suggestedQuestions = getSuggestedQuestions === null ? localizedQuestions : [];
141+
136142
return (
137143
// BoxAISidebarContent is using withApiWrapper that is not passing all provided props,
138144
// that's why we need to use provider to pass other props
139145
<AgentsProvider value={cache.agents}>
140146
<BoxAISidebarContext.Provider value={contextValue}>
141147
<BoxAISidebarContent
148+
cachedSuggestedQuestions={cache.suggestedQuestions}
142149
getSuggestedQuestions={getSuggestedQuestions}
143150
isOpen
144151
isStopResponseEnabled={isStopResponseEnabled}
145152
itemID={fileID}
146153
itemIDs={[fileID]}
154+
onSuggestedQuestionsFetched={handleSuggestedQuestionsFetched}
147155
restoredQuestions={questionsWithoutInProgress}
148156
restoredSession={cache.encodedSession}
149157
restoredShouldShowLandingPage={cache.shouldShowLandingPage}
150158
shouldPreinitSession={shouldPreinitSession}
151-
suggestedQuestions={getSuggestedQuestions === null ? localizedQuestions : []}
159+
suggestedQuestions={cache.suggestedQuestions.length > 0 ? cache.suggestedQuestions : suggestedQuestions}
152160
warningNotice={spreadsheetNotice}
153161
warningNoticeAriaLabel={formatMessage(messages.welcomeMessageSpreadsheetNoticeAriaLabel)}
154162
{...rest}

src/elements/content-sidebar/BoxAISidebarContent.tsx

+3-3
Original file line numberDiff line numberDiff line change
@@ -211,10 +211,10 @@ function BoxAISidebarContent(props: ApiWrapperWithInjectedProps & { shouldShowLa
211211
items={items}
212212
questions={questions}
213213
onUserIntentToUseAI={handleUserIntentToUseAI}
214+
shouldShowLandingPage={cache.shouldShowLandingPage}
215+
showLoadingIndicator={isLoading && shouldPreinitSession}
214216
stopQuestion={stopQuestion}
215217
submitQuestion={sendQuestion}
216-
shouldShowLandingPage={shouldShowLandingPage}
217-
showLoadingIndicator={isLoading && shouldPreinitSession}
218218
variant="sidebar"
219219
recordAction={recordAction}
220220
{...rest}
@@ -241,7 +241,7 @@ function BoxAISidebarContent(props: ApiWrapperWithInjectedProps & { shouldShowLa
241241
open={isModalOpen}
242242
questions={questions}
243243
recordAction={isModalOpen ? recordAction : undefined}
244-
shouldShowLandingPage={shouldShowLandingPage}
244+
shouldShowLandingPage={cache.shouldShowLandingPage}
245245
showLoadingIndicator={false}
246246
stopPropagationOnEsc
247247
stopQuestion={stopQuestion}

src/elements/content-sidebar/SidebarPanels.js

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

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

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

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

+29-1
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,13 @@ jest.mock('@box/box-ai-content-answers', () => ({
1818
// BoxAiContentAnswers: jest.fn().mockImplementation(() => <div data-testid="content-answers" />),
1919
withApiWrapper: Component => props => (
2020
<Component
21+
cachedSuggestedQuestions={props.cachedSuggestedQuestions}
2122
createSession={props.createSessionRequest}
2223
encodedSession={props.restoredSession}
2324
error={null}
2425
getAIStudioAgents={props.getAIStudioAgents}
26+
getSuggestedQuestions={props.getSuggestedQuestions}
2527
hostAppName={props.hostAppName}
26-
hasCustomSuggestedQuestions={false}
2728
isAgentSelectorEnabled={props.isAgentSelectorEnabled}
2829
isAIStudioAgentSelectorEnabled={props.isAIStudioAgentSelectorEnabled}
2930
isCitationsEnabled={props.isCitationsEnabled}
@@ -38,8 +39,10 @@ jest.mock('@box/box-ai-content-answers', () => ({
3839
onClearAction={mockOnClearAction}
3940
onCloseModal={jest.fn()}
4041
onSelectAgent={jest.fn()}
42+
onSuggestedQuestionsFetched={props.onSuggestedQuestionsFetched}
4143
onAgentEditorToggle={jest.fn()}
4244
questions={props.restoredQuestions}
45+
restoredShouldShowLandingPage={props.restoredShouldShowLandingPage}
4346
retryQuestion={jest.fn()}
4447
sendQuestion={props.sendQuestion}
4548
shouldPreinitSession={props.shouldPreinitSession}
@@ -69,6 +72,7 @@ describe('elements/content-sidebar/BoxAISidebar', () => {
6972
questions: [],
7073
agents: mockAgents,
7174
shouldShowLandingPage: true,
75+
suggestedQuestions: [],
7276
},
7377
createSessionRequest: jest.fn(() => ({ encodedSession: '1234' })),
7478
elementId: '123',
@@ -208,6 +212,7 @@ describe('elements/content-sidebar/BoxAISidebar', () => {
208212
],
209213
agents: mockAgents,
210214
shouldShowLandingPage: false,
215+
suggestedQuestions: [],
211216
},
212217
});
213218

@@ -240,6 +245,28 @@ describe('elements/content-sidebar/BoxAISidebar', () => {
240245
expect(screen.getByText('Welcome to Box AI', { exact: false })).toBeInTheDocument();
241246
});
242247

248+
test('should render cached custom suggested questions', async () => {
249+
await renderComponent( {
250+
cache: {
251+
encodedSession: '1234',
252+
questions: [],
253+
agents: mockAgents,
254+
shouldShowLandingPage: true,
255+
suggestedQuestions: [
256+
{
257+
id: 'suggested-question-1',
258+
prompt: 'Summarize this document',
259+
label: 'Please summarize this document',
260+
},
261+
],
262+
},
263+
getSuggestedQuestions: jest.fn(),
264+
});
265+
266+
expect(screen.getByText('Summarize this document', { exact: false })).toBeInTheDocument();
267+
expect(screen.queryByText('Loading suggested questions', { exact: false })).not.toBeInTheDocument();
268+
});
269+
243270
test('should not set questions that are in progress', async () => {
244271
await renderComponent({
245272
cache: {
@@ -258,6 +285,7 @@ describe('elements/content-sidebar/BoxAISidebar', () => {
258285
],
259286
agents: mockAgents,
260287
shouldShowLandingPage: false,
288+
suggestedQuestions: [],
261289
},
262290
});
263291

Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
1-
import { type QuestionType } from '@box/box-ai-content-answers';
1+
import { type QuestionType , type SuggestedQuestionType } from '@box/box-ai-content-answers';
22
import { type AgentState } from '@box/box-ai-agent-selector';
33

44
export type BoxAISidebarCache = {
55
agents: AgentState,
66
encodedSession: string | null,
77
questions: QuestionType[],
88
shouldShowLandingPage: boolean,
9+
suggestedQuestions: SuggestedQuestionType[],
910
};
1011

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

yarn.lock

+32-10
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.112.1":
1502-
version "0.112.1"
1503-
resolved "https://registry.yarnpkg.com/@box/box-ai-content-answers/-/box-ai-content-answers-0.112.1.tgz#1fd2b062e811ca20fd9911edd6b901c35e97abca"
1504-
integrity sha512-gMNi9CiJAEbtpttOpDLxqUJFKM6vMvIaaIpyZm3zNdri3nWuzF22X4c7WjND0ebm8Q9F1L0+NGLKdzyvH/avxw==
1501+
"@box/box-ai-content-answers@^0.113.0":
1502+
version "0.113.0"
1503+
resolved "https://registry.yarnpkg.com/@box/box-ai-content-answers/-/box-ai-content-answers-0.113.0.tgz#6bd92abac22e06ea067983b7f42cd91d8ea35f8b"
1504+
integrity sha512-vY70YANv2RAwkSEEsIbhJBlEOTKxo3hP5SZ71fgpVb+7jMKLjDBranUN/18uu3orri6q998E2vOhN0BwRO2GfA==
15051505

15061506
"@box/cldr-data@^34.2.0":
15071507
version "34.8.0"
@@ -22393,8 +22393,7 @@ string-replace-loader@^3.1.0:
2239322393
loader-utils "^2.0.0"
2239422394
schema-utils "^3.0.0"
2239522395

22396-
"string-width-cjs@npm:string-width@^4.2.0", "string-width@^1.0.2 || 2 || 3 || 4", string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3:
22397-
name string-width-cjs
22396+
"string-width-cjs@npm:string-width@^4.2.0":
2239822397
version "4.2.3"
2239922398
resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010"
2240022399
integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==
@@ -22412,6 +22411,15 @@ string-width@^1.0.1:
2241222411
is-fullwidth-code-point "^1.0.0"
2241322412
strip-ansi "^3.0.0"
2241422413

22414+
"string-width@^1.0.2 || 2 || 3 || 4", string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3:
22415+
version "4.2.3"
22416+
resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010"
22417+
integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==
22418+
dependencies:
22419+
emoji-regex "^8.0.0"
22420+
is-fullwidth-code-point "^3.0.0"
22421+
strip-ansi "^6.0.1"
22422+
2241522423
string-width@^2.0.0, string-width@^2.1.0, string-width@^2.1.1:
2241622424
version "2.1.1"
2241722425
resolved "https://registry.yarnpkg.com/string-width/-/string-width-2.1.1.tgz#ab93f27a8dc13d28cac815c462143a6d9012ae9e"
@@ -22550,8 +22558,7 @@ stringify-package@^1.0.0, stringify-package@^1.0.1:
2255022558
resolved "https://registry.yarnpkg.com/stringify-package/-/stringify-package-1.0.1.tgz#e5aa3643e7f74d0f28628b72f3dad5cecfc3ba85"
2255122559
integrity sha512-sa4DUQsYciMP1xhKWGuFM04fB0LG/9DlluZoSVywUMRNvzid6XucHK0/90xGxRoHrAaROrcHK1aPKaijCtSrhg==
2255222560

22553-
"strip-ansi-cjs@npm:strip-ansi@^6.0.1", strip-ansi@^6.0.0, strip-ansi@^6.0.1:
22554-
name strip-ansi-cjs
22561+
"strip-ansi-cjs@npm:strip-ansi@^6.0.1":
2255522562
version "6.0.1"
2255622563
resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9"
2255722564
integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==
@@ -22579,6 +22586,13 @@ strip-ansi@^5.0.0, strip-ansi@^5.1.0, strip-ansi@^5.2.0:
2257922586
dependencies:
2258022587
ansi-regex "^4.1.0"
2258122588

22589+
strip-ansi@^6.0.0, strip-ansi@^6.0.1:
22590+
version "6.0.1"
22591+
resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9"
22592+
integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==
22593+
dependencies:
22594+
ansi-regex "^5.0.1"
22595+
2258222596
strip-ansi@^7.0.1, strip-ansi@^7.1.0:
2258322597
version "7.1.0"
2258422598
resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-7.1.0.tgz#d5b6568ca689d8561370b0707685d22434faff45"
@@ -24783,8 +24797,7 @@ worker-farm@^1.6.0, worker-farm@^1.7.0:
2478324797
dependencies:
2478424798
errno "~0.1.7"
2478524799

24786-
"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0", wrap-ansi@^7.0.0:
24787-
name wrap-ansi-cjs
24800+
"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0":
2478824801
version "7.0.0"
2478924802
resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43"
2479024803
integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==
@@ -24827,6 +24840,15 @@ wrap-ansi@^6.2.0:
2482724840
string-width "^4.1.0"
2482824841
strip-ansi "^6.0.0"
2482924842

24843+
wrap-ansi@^7.0.0:
24844+
version "7.0.0"
24845+
resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43"
24846+
integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==
24847+
dependencies:
24848+
ansi-styles "^4.0.0"
24849+
string-width "^4.1.0"
24850+
strip-ansi "^6.0.0"
24851+
2483024852
wrap-ansi@^8.1.0:
2483124853
version "8.1.0"
2483224854
resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-8.1.0.tgz#56dc22368ee570face1b49819975d9b9a5ead214"

0 commit comments

Comments
 (0)