Skip to content

Commit 0a88f20

Browse files
feat(boxai-sidebar): Add cache for Agent Selector (#3928)
* feat(boxai-sidebar): Add cache for Agent Selector * chore(): add missing line end * feat(boxai-sidebar): Add cache for Agent Selector Add missing Flow types and agents prop to mocked cache in tests. Remove unneeded type import. --------- Co-authored-by: Dawid Jankowiak <[email protected]>
1 parent dc5d352 commit 0a88f20

File tree

7 files changed

+133
-82
lines changed

7 files changed

+133
-82
lines changed

src/elements/content-sidebar/BoxAISidebar.tsx

+22-19
Original file line numberDiff line numberDiff line change
@@ -4,17 +4,18 @@
44
*/
55
import * as React from 'react';
66
import { useIntl } from 'react-intl';
7-
import { type ItemType, type QuestionType } from '@box/box-ai-content-answers';
8-
import { RecordActionType } from '@box/box-ai-agent-selector';
7+
import { type ItemType } from '@box/box-ai-content-answers';
8+
import { AgentsProvider , RecordActionType } from '@box/box-ai-agent-selector';
99
import BoxAISidebarContent from './BoxAISidebarContent';
1010
import { BoxAISidebarContext } from './context/BoxAISidebarContext';
1111
import { DOCUMENT_SUGGESTED_QUESTIONS, SPREADSHEET_FILE_EXTENSIONS } from '../common/content-answers/constants';
12+
import type { BoxAISidebarCache, BoxAISidebarCacheSetter } from './types/BoxAISidebarTypes';
1213

1314
import messages from '../common/content-answers/messages';
1415

1516
export interface BoxAISidebarProps {
1617
contentName: string;
17-
cache: { encodedSession?: string | null; questions?: QuestionType[] };
18+
cache: BoxAISidebarCache;
1819
createSessionRequest: (payload: Record<string, unknown>, itemID: string) => Promise<unknown>;
1920
elementId: string;
2021
fetchTimeout: Record<string, unknown>;
@@ -51,7 +52,7 @@ export interface BoxAISidebarProps {
5152
itemSize?: string;
5253
userInfo: { name: string; avatarURL: string };
5354
recordAction: (params: RecordActionType) => void;
54-
setCacheValue: (key: 'encodedSession' | 'questions', value: string | null | QuestionType[]) => void;
55+
setCacheValue: BoxAISidebarCacheSetter;
5556
}
5657

5758
const BoxAISidebar = (props: BoxAISidebarProps) => {
@@ -127,21 +128,23 @@ const BoxAISidebar = (props: BoxAISidebarProps) => {
127128
return (
128129
// BoxAISidebarContent is using withApiWrapper that is not passing all provided props,
129130
// that's why we need to use provider to pass other props
130-
<BoxAISidebarContext.Provider value={contextValue}>
131-
<BoxAISidebarContent
132-
getSuggestedQuestions={getSuggestedQuestions}
133-
isOpen
134-
isStopResponseEnabled={isStopResponseEnabled}
135-
itemID={fileID}
136-
itemIDs={[fileID]}
137-
restoredQuestions={questionsWithoutInProgress}
138-
restoredSession={cache.encodedSession}
139-
suggestedQuestions={getSuggestedQuestions === null ? localizedQuestions : []}
140-
warningNotice={spreadsheetNotice}
141-
warningNoticeAriaLabel={formatMessage(messages.welcomeMessageSpreadsheetNoticeAriaLabel)}
142-
{...rest}
143-
/>
144-
</BoxAISidebarContext.Provider>
131+
<AgentsProvider value={cache.agents}>
132+
<BoxAISidebarContext.Provider value={contextValue}>
133+
<BoxAISidebarContent
134+
getSuggestedQuestions={getSuggestedQuestions}
135+
isOpen
136+
isStopResponseEnabled={isStopResponseEnabled}
137+
itemID={fileID}
138+
itemIDs={[fileID]}
139+
restoredQuestions={questionsWithoutInProgress}
140+
restoredSession={cache.encodedSession}
141+
suggestedQuestions={getSuggestedQuestions === null ? localizedQuestions : []}
142+
warningNotice={spreadsheetNotice}
143+
warningNoticeAriaLabel={formatMessage(messages.welcomeMessageSpreadsheetNoticeAriaLabel)}
144+
{...rest}
145+
/>
146+
</BoxAISidebarContext.Provider>
147+
</AgentsProvider>
145148
);
146149
};
147150

src/elements/content-sidebar/BoxAISidebarContent.tsx

+59-56
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import * as React from 'react';
66
import flow from 'lodash/flow';
77
import { useIntl } from 'react-intl';
88
import classNames from 'classnames';
9-
import { AgentsProvider, BoxAiAgentSelectorWithApi } from '@box/box-ai-agent-selector';
9+
import { BoxAiAgentSelectorWithApi, useAgents } from '@box/box-ai-agent-selector';
1010
import { IconButton, Tooltip } from '@box/blueprint-web';
1111
import { ArrowsExpand } from '@box/blueprint-web-assets/icons/Fill';
1212
import {
@@ -65,6 +65,7 @@ function BoxAISidebarContent(props: ApiWrapperProps) {
6565
setCacheValue,
6666
userInfo,
6767
} = React.useContext(BoxAISidebarContext);
68+
const { agents, requestState, selectedAgent } = useAgents();
6869
const { questions: cacheQuestions } = cache;
6970

7071
if (cache.encodedSession !== encodedSession) {
@@ -75,6 +76,10 @@ function BoxAISidebarContent(props: ApiWrapperProps) {
7576
setCacheValue('questions', questions);
7677
}
7778

79+
if (cache.agents.selectedAgent !== selectedAgent) {
80+
setCacheValue('agents', { agents, requestState, selectedAgent });
81+
}
82+
7883
const handleModalClose = () => {
7984
setIsModalOpen(false);
8085
};
@@ -152,61 +157,59 @@ function BoxAISidebarContent(props: ApiWrapperProps) {
152157
);
153158

154159
return (
155-
<AgentsProvider>
156-
<>
157-
<SidebarContent
158-
actions={renderActions()}
159-
className={classNames('bcs-BoxAISidebar', { 'with-modal-open': isModalOpen })}
160-
elementId={elementId}
161-
sidebarView={SIDEBAR_VIEW_BOXAI}
162-
>
163-
<div className="bcs-BoxAISidebar-content">
164-
<BoxAiContentAnswers
165-
className="bcs-BoxAISidebar-contentAnswers"
166-
contentType={formatMessage(messages.sidebarBoxAIContent)}
167-
hostAppName={hostAppName}
168-
isAIStudioAgentSelectorEnabled={isAIStudioAgentSelectorEnabled}
169-
isFeedbackEnabled={isFeedbackEnabled}
170-
isStopResponseEnabled={isStopResponseEnabled}
171-
items={items}
172-
questions={questions}
173-
stopQuestion={stopQuestion}
174-
submitQuestion={sendQuestion}
175-
userInfo={userInfo}
176-
variant="sidebar"
177-
recordAction={recordAction}
178-
{...rest}
179-
/>
180-
</div>
181-
</SidebarContent>
182-
<IntelligenceModal
183-
contentName={contentName}
184-
contentType={formatMessage(messages.sidebarBoxAIContent)}
185-
extension={fileExtension}
186-
getAIStudioAgents={getAIStudioAgents}
187-
hostAppName={hostAppName}
188-
isAIStudioAgentSelectorEnabled={isAIStudioAgentSelectorEnabled}
189-
isFeedbackEnabled={isFeedbackEnabled}
190-
isResetChatEnabled={isResetChatEnabled}
191-
isStopResponseEnabled={isStopResponseEnabled}
192-
items={items}
193-
itemSize={itemSize}
194-
onClearAction={onClearAction}
195-
onOpenChange={handleModalClose}
196-
onSelectAgent={onSelectAgent}
197-
open={isModalOpen}
198-
questions={questions}
199-
recordAction={isModalOpen ? recordAction : undefined}
200-
showLoadingIndicator={false}
201-
stopPropagationOnEsc
202-
submitQuestion={sendQuestion}
203-
userInfo={userInfo}
204-
variant="collapsible"
205-
{...rest}
206-
shouldRenderProviders={false}
207-
/>
208-
</>
209-
</AgentsProvider>
160+
<>
161+
<SidebarContent
162+
actions={renderActions()}
163+
className={classNames('bcs-BoxAISidebar', { 'with-modal-open': isModalOpen })}
164+
elementId={elementId}
165+
sidebarView={SIDEBAR_VIEW_BOXAI}
166+
>
167+
<div className="bcs-BoxAISidebar-content">
168+
<BoxAiContentAnswers
169+
className="bcs-BoxAISidebar-contentAnswers"
170+
contentType={formatMessage(messages.sidebarBoxAIContent)}
171+
hostAppName={hostAppName}
172+
isAIStudioAgentSelectorEnabled={isAIStudioAgentSelectorEnabled}
173+
isFeedbackEnabled={isFeedbackEnabled}
174+
isStopResponseEnabled={isStopResponseEnabled}
175+
items={items}
176+
questions={questions}
177+
stopQuestion={stopQuestion}
178+
submitQuestion={sendQuestion}
179+
userInfo={userInfo}
180+
variant="sidebar"
181+
recordAction={recordAction}
182+
{...rest}
183+
/>
184+
</div>
185+
</SidebarContent>
186+
<IntelligenceModal
187+
contentName={contentName}
188+
contentType={formatMessage(messages.sidebarBoxAIContent)}
189+
extension={fileExtension}
190+
getAIStudioAgents={getAIStudioAgents}
191+
hostAppName={hostAppName}
192+
isAIStudioAgentSelectorEnabled={isAIStudioAgentSelectorEnabled}
193+
isFeedbackEnabled={isFeedbackEnabled}
194+
isResetChatEnabled={isResetChatEnabled}
195+
isStopResponseEnabled={isStopResponseEnabled}
196+
items={items}
197+
itemSize={itemSize}
198+
onClearAction={onClearAction}
199+
onOpenChange={handleModalClose}
200+
onSelectAgent={onSelectAgent}
201+
open={isModalOpen}
202+
questions={questions}
203+
recordAction={isModalOpen ? recordAction : undefined}
204+
showLoadingIndicator={false}
205+
stopPropagationOnEsc
206+
submitQuestion={sendQuestion}
207+
userInfo={userInfo}
208+
variant="collapsible"
209+
{...rest}
210+
shouldRenderProviders={false}
211+
/>
212+
</>
210213
);
211214
}
212215

src/elements/content-sidebar/SidebarPanels.js

+8-3
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ import * as React from 'react';
88
import flow from 'lodash/flow';
99
import noop from 'lodash/noop';
1010
import { matchPath, Redirect, Route, Switch, type Location } from 'react-router-dom';
11-
import { type QuestionType } from '@box/box-ai-content-answers';
1211
import SidebarUtils from './SidebarUtils';
1312
import withSidebarAnnotations from './withSidebarAnnotations';
1413
import { withAnnotatorContext } from '../common/annotator-context';
@@ -42,6 +41,7 @@ import type { VersionsSidebarProps } from './versions';
4241
import type { User, BoxItem } from '../../common/types/core';
4342
import type { Errors } from '../common/flowTypes';
4443
import type { FeatureConfig } from '../common/feature-checking';
44+
import type { BoxAISidebarCache } from './types/BoxAISidebarTypes';
4545

4646
type Props = {
4747
activitySidebarProps: ActivitySidebarProps,
@@ -133,7 +133,12 @@ class SidebarPanels extends React.Component<Props, State> {
133133

134134
versionsSidebar: ElementRefType = React.createRef();
135135

136-
boxAiSidebarCache: { encodedSession?: string | null, questions?: QuestionType[] } = {
136+
boxAiSidebarCache: BoxAISidebarCache = {
137+
agents: {
138+
agents: [],
139+
selectedAgent: null,
140+
requestState: 'not_started',
141+
},
137142
encodedSession: null,
138143
questions: [],
139144
};
@@ -166,7 +171,7 @@ class SidebarPanels extends React.Component<Props, State> {
166171
}
167172
};
168173

169-
setBoxAiSidebarCacheValue = (key: 'encodedSession' | 'questions', value: any) => {
174+
setBoxAiSidebarCacheValue = (key: 'agents' | 'encodedSession' | 'questions', value: any) => {
170175
this.boxAiSidebarCache[key] = value;
171176
};
172177

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

+12-1
Original file line numberDiff line numberDiff line change
@@ -50,9 +50,19 @@ jest.mock('@box/box-ai-content-answers', () => ({
5050
jest.mock('../BoxAISidebarTitle', () => () => <div data-testid="boxai-sidebar-title" />);
5151

5252
describe('elements/content-sidebar/BoxAISidebar', () => {
53+
const mockAgents = {
54+
agents: [],
55+
requestState: 'success',
56+
selectedAgent: null,
57+
};
58+
5359
const mockProps = {
5460
contentName: 'testName.txt',
55-
cache: { encodedSession: '', questions: [] },
61+
cache: {
62+
encodedSession: '',
63+
questions: [],
64+
agents: mockAgents,
65+
},
5666
createSessionRequest: jest.fn(() => ({ encodedSession: '1234' })),
5767
elementId: '123',
5868
fetchTimeout: {},
@@ -200,6 +210,7 @@ describe('elements/content-sidebar/BoxAISidebar', () => {
200210
prompt: 'not completed question',
201211
},
202212
],
213+
agents: mockAgents,
203214
},
204215
});
205216

src/elements/content-sidebar/context/BoxAISidebarContext.ts

+4-3
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,8 @@ import * as React from 'react';
22
import noop from 'lodash/noop';
33
import { RecordActionType as AgentSelectorRecordActionType } from '@box/box-ai-agent-selector';
44
import { RecordActionType as ContentAnswersRecordActionType } from '@box/box-ai-content-answers';
5-
import type { ItemType, QuestionType } from '@box/box-ai-content-answers';
5+
import type { ItemType } from '@box/box-ai-content-answers';
6+
import type { BoxAISidebarCache, BoxAISidebarCacheSetter } from '../types/BoxAISidebarTypes';
67

78
type BoxAISidebarRecordActionType =
89
| AgentSelectorRecordActionType
@@ -14,7 +15,7 @@ type BoxAISidebarRecordActionType =
1415
});
1516

1617
export interface BoxAISidebarContextValues {
17-
cache: { encodedSession?: string | null; questions?: QuestionType[] };
18+
cache: BoxAISidebarCache;
1819
contentName: string;
1920
elementId: string;
2021
fileExtension: string;
@@ -23,7 +24,7 @@ export interface BoxAISidebarContextValues {
2324
items: Array<ItemType>;
2425
itemSize?: string;
2526
recordAction: (params: BoxAISidebarRecordActionType) => void;
26-
setCacheValue: (key: 'encodedSession' | 'questions', value: string | null | QuestionType[]) => void;
27+
setCacheValue: BoxAISidebarCacheSetter;
2728
userInfo: { name: string; avatarURL: string };
2829
}
2930

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
/**
2+
* Flowtype definitions for BoxAISidebarTypes.ts
3+
* Generated by Flowgen from a Typescript Definition
4+
* Flowgen v1.21.0
5+
*/
6+
7+
import { type, QuestionType } from "@box/box-ai-content-answers";
8+
import { type, AgentState } from "@box/box-ai-agent-selector";
9+
export type BoxAISidebarCache = {
10+
agents: AgentState,
11+
encodedSession: string | null,
12+
questions: QuestionType[],
13+
...
14+
};
15+
export type BoxAISidebarCacheSetter = (
16+
key: "agents" | "encodedSession" | "questions",
17+
value: AgentState | QuestionType[] | string | null
18+
) => void;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
import { type QuestionType } from '@box/box-ai-content-answers';
2+
import { type AgentState } from '@box/box-ai-agent-selector';
3+
4+
export type BoxAISidebarCache = {
5+
agents: AgentState,
6+
encodedSession: string | null,
7+
questions: QuestionType[],
8+
};
9+
10+
export type BoxAISidebarCacheSetter = (key: 'agents' | 'encodedSession' | 'questions', value: AgentState | QuestionType[] | string | null) => void;

0 commit comments

Comments
 (0)