From 0a88f2078960052a542de8df88605d2c413faea8 Mon Sep 17 00:00:00 2001 From: MateuszMamczarz Date: Fri, 14 Feb 2025 19:14:04 +0100 Subject: [PATCH] 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 --- src/elements/content-sidebar/BoxAISidebar.tsx | 41 ++++--- .../content-sidebar/BoxAISidebarContent.tsx | 115 +++++++++--------- src/elements/content-sidebar/SidebarPanels.js | 11 +- .../__tests__/BoxAISidebar.test.tsx | 13 +- .../context/BoxAISidebarContext.ts | 7 +- .../types/BoxAISidebarTypes.js.flow | 18 +++ .../types/BoxAISidebarTypes.ts | 10 ++ 7 files changed, 133 insertions(+), 82 deletions(-) create mode 100644 src/elements/content-sidebar/types/BoxAISidebarTypes.js.flow create mode 100644 src/elements/content-sidebar/types/BoxAISidebarTypes.ts diff --git a/src/elements/content-sidebar/BoxAISidebar.tsx b/src/elements/content-sidebar/BoxAISidebar.tsx index fe8106d4f2..621e0ec8c7 100644 --- a/src/elements/content-sidebar/BoxAISidebar.tsx +++ b/src/elements/content-sidebar/BoxAISidebar.tsx @@ -4,17 +4,18 @@ */ import * as React from 'react'; import { useIntl } from 'react-intl'; -import { type ItemType, type QuestionType } from '@box/box-ai-content-answers'; -import { RecordActionType } from '@box/box-ai-agent-selector'; +import { type ItemType } from '@box/box-ai-content-answers'; +import { AgentsProvider , RecordActionType } from '@box/box-ai-agent-selector'; import BoxAISidebarContent from './BoxAISidebarContent'; import { BoxAISidebarContext } from './context/BoxAISidebarContext'; import { DOCUMENT_SUGGESTED_QUESTIONS, SPREADSHEET_FILE_EXTENSIONS } from '../common/content-answers/constants'; +import type { BoxAISidebarCache, BoxAISidebarCacheSetter } from './types/BoxAISidebarTypes'; import messages from '../common/content-answers/messages'; export interface BoxAISidebarProps { contentName: string; - cache: { encodedSession?: string | null; questions?: QuestionType[] }; + cache: BoxAISidebarCache; createSessionRequest: (payload: Record, itemID: string) => Promise; elementId: string; fetchTimeout: Record; @@ -51,7 +52,7 @@ export interface BoxAISidebarProps { itemSize?: string; userInfo: { name: string; avatarURL: string }; recordAction: (params: RecordActionType) => void; - setCacheValue: (key: 'encodedSession' | 'questions', value: string | null | QuestionType[]) => void; + setCacheValue: BoxAISidebarCacheSetter; } const BoxAISidebar = (props: BoxAISidebarProps) => { @@ -127,21 +128,23 @@ const BoxAISidebar = (props: BoxAISidebarProps) => { return ( // BoxAISidebarContent is using withApiWrapper that is not passing all provided props, // that's why we need to use provider to pass other props - - - + + + + + ); }; diff --git a/src/elements/content-sidebar/BoxAISidebarContent.tsx b/src/elements/content-sidebar/BoxAISidebarContent.tsx index 845d7ef3ad..653919fe25 100644 --- a/src/elements/content-sidebar/BoxAISidebarContent.tsx +++ b/src/elements/content-sidebar/BoxAISidebarContent.tsx @@ -6,7 +6,7 @@ import * as React from 'react'; import flow from 'lodash/flow'; import { useIntl } from 'react-intl'; import classNames from 'classnames'; -import { AgentsProvider, BoxAiAgentSelectorWithApi } from '@box/box-ai-agent-selector'; +import { BoxAiAgentSelectorWithApi, useAgents } from '@box/box-ai-agent-selector'; import { IconButton, Tooltip } from '@box/blueprint-web'; import { ArrowsExpand } from '@box/blueprint-web-assets/icons/Fill'; import { @@ -65,6 +65,7 @@ function BoxAISidebarContent(props: ApiWrapperProps) { setCacheValue, userInfo, } = React.useContext(BoxAISidebarContext); + const { agents, requestState, selectedAgent } = useAgents(); const { questions: cacheQuestions } = cache; if (cache.encodedSession !== encodedSession) { @@ -75,6 +76,10 @@ function BoxAISidebarContent(props: ApiWrapperProps) { setCacheValue('questions', questions); } + if (cache.agents.selectedAgent !== selectedAgent) { + setCacheValue('agents', { agents, requestState, selectedAgent }); + } + const handleModalClose = () => { setIsModalOpen(false); }; @@ -152,61 +157,59 @@ function BoxAISidebarContent(props: ApiWrapperProps) { ); return ( - - <> - -
- -
-
- - -
+ <> + +
+ +
+
+ + ); } diff --git a/src/elements/content-sidebar/SidebarPanels.js b/src/elements/content-sidebar/SidebarPanels.js index e42a08dbcb..48c0767362 100644 --- a/src/elements/content-sidebar/SidebarPanels.js +++ b/src/elements/content-sidebar/SidebarPanels.js @@ -8,7 +8,6 @@ import * as React from 'react'; import flow from 'lodash/flow'; import noop from 'lodash/noop'; import { matchPath, Redirect, Route, Switch, type Location } from 'react-router-dom'; -import { type QuestionType } from '@box/box-ai-content-answers'; import SidebarUtils from './SidebarUtils'; import withSidebarAnnotations from './withSidebarAnnotations'; import { withAnnotatorContext } from '../common/annotator-context'; @@ -42,6 +41,7 @@ import type { VersionsSidebarProps } from './versions'; import type { User, BoxItem } from '../../common/types/core'; import type { Errors } from '../common/flowTypes'; import type { FeatureConfig } from '../common/feature-checking'; +import type { BoxAISidebarCache } from './types/BoxAISidebarTypes'; type Props = { activitySidebarProps: ActivitySidebarProps, @@ -133,7 +133,12 @@ class SidebarPanels extends React.Component { versionsSidebar: ElementRefType = React.createRef(); - boxAiSidebarCache: { encodedSession?: string | null, questions?: QuestionType[] } = { + boxAiSidebarCache: BoxAISidebarCache = { + agents: { + agents: [], + selectedAgent: null, + requestState: 'not_started', + }, encodedSession: null, questions: [], }; @@ -166,7 +171,7 @@ class SidebarPanels extends React.Component { } }; - setBoxAiSidebarCacheValue = (key: 'encodedSession' | 'questions', value: any) => { + setBoxAiSidebarCacheValue = (key: 'agents' | 'encodedSession' | 'questions', 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 ff679f11da..8970c975d0 100644 --- a/src/elements/content-sidebar/__tests__/BoxAISidebar.test.tsx +++ b/src/elements/content-sidebar/__tests__/BoxAISidebar.test.tsx @@ -50,9 +50,19 @@ jest.mock('@box/box-ai-content-answers', () => ({ jest.mock('../BoxAISidebarTitle', () => () =>
); describe('elements/content-sidebar/BoxAISidebar', () => { + const mockAgents = { + agents: [], + requestState: 'success', + selectedAgent: null, + }; + const mockProps = { contentName: 'testName.txt', - cache: { encodedSession: '', questions: [] }, + cache: { + encodedSession: '', + questions: [], + agents: mockAgents, + }, createSessionRequest: jest.fn(() => ({ encodedSession: '1234' })), elementId: '123', fetchTimeout: {}, @@ -200,6 +210,7 @@ describe('elements/content-sidebar/BoxAISidebar', () => { prompt: 'not completed question', }, ], + agents: mockAgents, }, }); diff --git a/src/elements/content-sidebar/context/BoxAISidebarContext.ts b/src/elements/content-sidebar/context/BoxAISidebarContext.ts index f568923573..1390898027 100644 --- a/src/elements/content-sidebar/context/BoxAISidebarContext.ts +++ b/src/elements/content-sidebar/context/BoxAISidebarContext.ts @@ -2,7 +2,8 @@ import * as React from 'react'; import noop from 'lodash/noop'; import { RecordActionType as AgentSelectorRecordActionType } from '@box/box-ai-agent-selector'; import { RecordActionType as ContentAnswersRecordActionType } from '@box/box-ai-content-answers'; -import type { ItemType, QuestionType } from '@box/box-ai-content-answers'; +import type { ItemType } from '@box/box-ai-content-answers'; +import type { BoxAISidebarCache, BoxAISidebarCacheSetter } from '../types/BoxAISidebarTypes'; type BoxAISidebarRecordActionType = | AgentSelectorRecordActionType @@ -14,7 +15,7 @@ type BoxAISidebarRecordActionType = }); export interface BoxAISidebarContextValues { - cache: { encodedSession?: string | null; questions?: QuestionType[] }; + cache: BoxAISidebarCache; contentName: string; elementId: string; fileExtension: string; @@ -23,7 +24,7 @@ export interface BoxAISidebarContextValues { items: Array; itemSize?: string; recordAction: (params: BoxAISidebarRecordActionType) => void; - setCacheValue: (key: 'encodedSession' | 'questions', value: string | null | QuestionType[]) => void; + setCacheValue: BoxAISidebarCacheSetter; userInfo: { name: string; avatarURL: string }; } diff --git a/src/elements/content-sidebar/types/BoxAISidebarTypes.js.flow b/src/elements/content-sidebar/types/BoxAISidebarTypes.js.flow new file mode 100644 index 0000000000..e4a05d986c --- /dev/null +++ b/src/elements/content-sidebar/types/BoxAISidebarTypes.js.flow @@ -0,0 +1,18 @@ +/** + * Flowtype definitions for BoxAISidebarTypes.ts + * Generated by Flowgen from a Typescript Definition + * Flowgen v1.21.0 + */ + +import { type, QuestionType } from "@box/box-ai-content-answers"; +import { type, AgentState } from "@box/box-ai-agent-selector"; +export type BoxAISidebarCache = { + agents: AgentState, + encodedSession: string | null, + questions: QuestionType[], + ... +}; +export type BoxAISidebarCacheSetter = ( + key: "agents" | "encodedSession" | "questions", + value: AgentState | QuestionType[] | string | null +) => void; diff --git a/src/elements/content-sidebar/types/BoxAISidebarTypes.ts b/src/elements/content-sidebar/types/BoxAISidebarTypes.ts new file mode 100644 index 0000000000..b17187e987 --- /dev/null +++ b/src/elements/content-sidebar/types/BoxAISidebarTypes.ts @@ -0,0 +1,10 @@ +import { type QuestionType } from '@box/box-ai-content-answers'; +import { type AgentState } from '@box/box-ai-agent-selector'; + +export type BoxAISidebarCache = { + agents: AgentState, + encodedSession: string | null, + questions: QuestionType[], +}; + +export type BoxAISidebarCacheSetter = (key: 'agents' | 'encodedSession' | 'questions', value: AgentState | QuestionType[] | string | null) => void;