diff --git a/package.json b/package.json index 795e551c4f..6f66168252 100644 --- a/package.json +++ b/package.json @@ -125,7 +125,7 @@ "@box/blueprint-web": "^9.18.11", "@box/blueprint-web-assets": "4.36.0", "@box/box-ai-agent-selector": "^0.31.0", - "@box/box-ai-content-answers": "^0.112.1", + "@box/box-ai-content-answers": "^0.113.0", "@box/cldr-data": "^34.2.0", "@box/combobox-with-api": "^0.28.4", "@box/frontend": "^10.0.1", @@ -308,7 +308,7 @@ "@box/blueprint-web": "^9.18.11", "@box/blueprint-web-assets": "^4.36.0", "@box/box-ai-agent-selector": "^0.31.0", - "@box/box-ai-content-answers": "^0.112.1", + "@box/box-ai-content-answers": "^0.113.0", "@box/cldr-data": ">=34.2.0", "@box/combobox-with-api": "^0.28.4", "@box/item-icon": "^0.9.58", diff --git a/src/elements/content-sidebar/BoxAISidebar.tsx b/src/elements/content-sidebar/BoxAISidebar.tsx index 0227cd02c7..3aa4d17b86 100644 --- a/src/elements/content-sidebar/BoxAISidebar.tsx +++ b/src/elements/content-sidebar/BoxAISidebar.tsx @@ -4,7 +4,7 @@ */ import * as React from 'react'; import { useIntl } from 'react-intl'; -import { type ItemType } from '@box/box-ai-content-answers'; +import {type ItemType, SuggestedQuestionType} from '@box/box-ai-content-answers'; import { AgentsProvider, RecordActionType } from '@box/box-ai-agent-selector'; import BoxAISidebarContent from './BoxAISidebarContent'; import { BoxAISidebarContext } from './context/BoxAISidebarContext'; @@ -133,22 +133,30 @@ const BoxAISidebar = (props: BoxAISidebarProps) => { spreadsheetNotice = formatMessage(messages.welcomeMessageSpreadsheetNotice); } + const handleSuggestedQuestionsFetched = (fetchedSuggestedQuestions: SuggestedQuestionType[]) => { + setCacheValue('suggestedQuestions', fetchedSuggestedQuestions); + }; + + const suggestedQuestions = getSuggestedQuestions === null ? localizedQuestions : []; + return ( // BoxAISidebarContent is using withApiWrapper that is not passing all provided props, // that's why we need to use provider to pass other props 0 ? cache.suggestedQuestions : suggestedQuestions} warningNotice={spreadsheetNotice} warningNoticeAriaLabel={formatMessage(messages.welcomeMessageSpreadsheetNoticeAriaLabel)} {...rest} diff --git a/src/elements/content-sidebar/BoxAISidebarContent.tsx b/src/elements/content-sidebar/BoxAISidebarContent.tsx index bd70e4332d..01de9cdc4a 100644 --- a/src/elements/content-sidebar/BoxAISidebarContent.tsx +++ b/src/elements/content-sidebar/BoxAISidebarContent.tsx @@ -211,10 +211,10 @@ function BoxAISidebarContent(props: ApiWrapperWithInjectedProps & { shouldShowLa items={items} questions={questions} onUserIntentToUseAI={handleUserIntentToUseAI} + shouldShowLandingPage={cache.shouldShowLandingPage} + showLoadingIndicator={isLoading && shouldPreinitSession} stopQuestion={stopQuestion} submitQuestion={sendQuestion} - shouldShowLandingPage={shouldShowLandingPage} - showLoadingIndicator={isLoading && shouldPreinitSession} variant="sidebar" recordAction={recordAction} {...rest} @@ -241,7 +241,7 @@ function BoxAISidebarContent(props: ApiWrapperWithInjectedProps & { shouldShowLa open={isModalOpen} questions={questions} recordAction={isModalOpen ? recordAction : undefined} - shouldShowLandingPage={shouldShowLandingPage} + shouldShowLandingPage={cache.shouldShowLandingPage} showLoadingIndicator={false} stopPropagationOnEsc stopQuestion={stopQuestion} diff --git a/src/elements/content-sidebar/SidebarPanels.js b/src/elements/content-sidebar/SidebarPanels.js index b31f0e9a8f..e860dc8f98 100644 --- a/src/elements/content-sidebar/SidebarPanels.js +++ b/src/elements/content-sidebar/SidebarPanels.js @@ -142,6 +142,7 @@ class SidebarPanels extends React.Component { encodedSession: null, questions: [], shouldShowLandingPage: true, + suggestedQuestions: [], }; componentDidMount() { @@ -172,7 +173,7 @@ class SidebarPanels extends React.Component { } }; - setBoxAiSidebarCacheValue = (key: 'agents' | 'encodedSession' | 'questions' | 'shouldShowLandingPage', value: any) => { + setBoxAiSidebarCacheValue = (key: 'agents' | 'encodedSession' | 'questions' | 'shouldShowLandingPage' | 'suggestedQuestions', value: any) => { this.boxAiSidebarCache[key] = value; }; diff --git a/src/elements/content-sidebar/__tests__/BoxAISidebar.test.tsx b/src/elements/content-sidebar/__tests__/BoxAISidebar.test.tsx index 338b923a3a..a6c1886c27 100644 --- a/src/elements/content-sidebar/__tests__/BoxAISidebar.test.tsx +++ b/src/elements/content-sidebar/__tests__/BoxAISidebar.test.tsx @@ -18,12 +18,13 @@ jest.mock('@box/box-ai-content-answers', () => ({ // BoxAiContentAnswers: jest.fn().mockImplementation(() =>
), withApiWrapper: Component => props => ( ({ onClearAction={mockOnClearAction} onCloseModal={jest.fn()} onSelectAgent={jest.fn()} + onSuggestedQuestionsFetched={props.onSuggestedQuestionsFetched} onAgentEditorToggle={jest.fn()} questions={props.restoredQuestions} + restoredShouldShowLandingPage={props.restoredShouldShowLandingPage} retryQuestion={jest.fn()} sendQuestion={props.sendQuestion} shouldPreinitSession={props.shouldPreinitSession} @@ -69,6 +72,7 @@ describe('elements/content-sidebar/BoxAISidebar', () => { questions: [], agents: mockAgents, shouldShowLandingPage: true, + suggestedQuestions: [], }, createSessionRequest: jest.fn(() => ({ encodedSession: '1234' })), elementId: '123', @@ -208,6 +212,7 @@ describe('elements/content-sidebar/BoxAISidebar', () => { ], agents: mockAgents, shouldShowLandingPage: false, + suggestedQuestions: [], }, }); @@ -240,6 +245,28 @@ describe('elements/content-sidebar/BoxAISidebar', () => { expect(screen.getByText('Welcome to Box AI', { exact: false })).toBeInTheDocument(); }); + test('should render cached custom suggested questions', async () => { + await renderComponent( { + cache: { + encodedSession: '1234', + questions: [], + agents: mockAgents, + shouldShowLandingPage: true, + suggestedQuestions: [ + { + id: 'suggested-question-1', + prompt: 'Summarize this document', + label: 'Please summarize this document', + }, + ], + }, + getSuggestedQuestions: jest.fn(), + }); + + expect(screen.getByText('Summarize this document', { exact: false })).toBeInTheDocument(); + expect(screen.queryByText('Loading suggested questions', { exact: false })).not.toBeInTheDocument(); + }); + test('should not set questions that are in progress', async () => { await renderComponent({ cache: { @@ -258,6 +285,7 @@ describe('elements/content-sidebar/BoxAISidebar', () => { ], agents: mockAgents, shouldShowLandingPage: false, + suggestedQuestions: [], }, }); diff --git a/src/elements/content-sidebar/types/BoxAISidebarTypes.ts b/src/elements/content-sidebar/types/BoxAISidebarTypes.ts index a688f52da3..1e4aca38fb 100644 --- a/src/elements/content-sidebar/types/BoxAISidebarTypes.ts +++ b/src/elements/content-sidebar/types/BoxAISidebarTypes.ts @@ -1,4 +1,4 @@ -import { type QuestionType } from '@box/box-ai-content-answers'; +import { type QuestionType , type SuggestedQuestionType } from '@box/box-ai-content-answers'; import { type AgentState } from '@box/box-ai-agent-selector'; export type BoxAISidebarCache = { @@ -6,6 +6,7 @@ export type BoxAISidebarCache = { encodedSession: string | null, questions: QuestionType[], shouldShowLandingPage: boolean, + suggestedQuestions: SuggestedQuestionType[], }; -export type BoxAISidebarCacheSetter = (key: 'agents' | 'encodedSession' | 'questions' | 'shouldShowLandingPage', value: AgentState | QuestionType[] | string | boolean | null) => void; +export type BoxAISidebarCacheSetter = (key: 'agents' | 'encodedSession' | 'questions' | 'shouldShowLandingPage' | 'suggestedQuestions', value: AgentState | QuestionType[] | SuggestedQuestionType[] | string | boolean | null) => void; diff --git a/yarn.lock b/yarn.lock index 43f95c5fe0..cb4fd6547a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1498,10 +1498,10 @@ resolved "https://registry.yarnpkg.com/@box/box-ai-agent-selector/-/box-ai-agent-selector-0.31.0.tgz#a2ef6c3c7284529ae268b609d04b6000348bb294" integrity sha512-4+M/4g8LHJfZkP+7ISBKveQs2q5HeGvXv8B6/N8yFb9cpYuOjpKFxRvHyILdQWjwictHZbgY2XrNrpxbYGEXRQ== -"@box/box-ai-content-answers@^0.112.1": - version "0.112.1" - resolved "https://registry.yarnpkg.com/@box/box-ai-content-answers/-/box-ai-content-answers-0.112.1.tgz#1fd2b062e811ca20fd9911edd6b901c35e97abca" - integrity sha512-gMNi9CiJAEbtpttOpDLxqUJFKM6vMvIaaIpyZm3zNdri3nWuzF22X4c7WjND0ebm8Q9F1L0+NGLKdzyvH/avxw== +"@box/box-ai-content-answers@^0.113.0": + version "0.113.0" + resolved "https://registry.yarnpkg.com/@box/box-ai-content-answers/-/box-ai-content-answers-0.113.0.tgz#6bd92abac22e06ea067983b7f42cd91d8ea35f8b" + integrity sha512-vY70YANv2RAwkSEEsIbhJBlEOTKxo3hP5SZ71fgpVb+7jMKLjDBranUN/18uu3orri6q998E2vOhN0BwRO2GfA== "@box/cldr-data@^34.2.0": version "34.8.0" @@ -22393,8 +22393,7 @@ string-replace-loader@^3.1.0: loader-utils "^2.0.0" schema-utils "^3.0.0" -"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: - name string-width-cjs +"string-width-cjs@npm:string-width@^4.2.0": version "4.2.3" resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== @@ -22412,6 +22411,15 @@ string-width@^1.0.1: is-fullwidth-code-point "^1.0.0" strip-ansi "^3.0.0" +"string-width@^1.0.2 || 2 || 3 || 4", string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: + version "4.2.3" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" + integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== + dependencies: + emoji-regex "^8.0.0" + is-fullwidth-code-point "^3.0.0" + strip-ansi "^6.0.1" + string-width@^2.0.0, string-width@^2.1.0, string-width@^2.1.1: version "2.1.1" 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: resolved "https://registry.yarnpkg.com/stringify-package/-/stringify-package-1.0.1.tgz#e5aa3643e7f74d0f28628b72f3dad5cecfc3ba85" integrity sha512-sa4DUQsYciMP1xhKWGuFM04fB0LG/9DlluZoSVywUMRNvzid6XucHK0/90xGxRoHrAaROrcHK1aPKaijCtSrhg== -"strip-ansi-cjs@npm:strip-ansi@^6.0.1", strip-ansi@^6.0.0, strip-ansi@^6.0.1: - name strip-ansi-cjs +"strip-ansi-cjs@npm:strip-ansi@^6.0.1": version "6.0.1" resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== @@ -22579,6 +22586,13 @@ strip-ansi@^5.0.0, strip-ansi@^5.1.0, strip-ansi@^5.2.0: dependencies: ansi-regex "^4.1.0" +strip-ansi@^6.0.0, strip-ansi@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" + integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== + dependencies: + ansi-regex "^5.0.1" + strip-ansi@^7.0.1, strip-ansi@^7.1.0: version "7.1.0" 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: dependencies: errno "~0.1.7" -"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0", wrap-ansi@^7.0.0: - name wrap-ansi-cjs +"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0": version "7.0.0" resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== @@ -24827,6 +24840,15 @@ wrap-ansi@^6.2.0: string-width "^4.1.0" strip-ansi "^6.0.0" +wrap-ansi@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" + integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== + dependencies: + ansi-styles "^4.0.0" + string-width "^4.1.0" + strip-ansi "^6.0.0" + wrap-ansi@^8.1.0: version "8.1.0" resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-8.1.0.tgz#56dc22368ee570face1b49819975d9b9a5ead214"