Repository navigation
feat(content-answers): Upgrade Content Answers - #3658
Conversation
a6cb441 to
fc6826c
Compare
| isCitationsEnabled?: boolean; | ||
| isMarkdownEnabled?: boolean; | ||
| isResetChatEnabled?: boolean; | ||
| onAsk?: () => void; |
There was a problem hiding this comment.
I think onAsk will always exist here since the upper level ContentAnswers.tsx will always pass down handleAsk() as onAsk, also same as onRequestClose
There was a problem hiding this comment.
its separated like that because a customer can submit onAsk and onRequestClose from the root lvl via contentAnswersProps
| isCompleted: true, | ||
| isLoading: false, | ||
| }; | ||
| setIsLoading(false); |
There was a problem hiding this comment.
we don't need this line since setIsLoading(false); will be called after the try catch in handleAsk() function
| created_at: q.created_at, | ||
| })); | ||
|
|
||
| const nextQuestions = [...(isRetry ? questions.slice(0, -1) : questions)]; |
There was a problem hiding this comment.
should this be more like prevQuestions instead
7eff2e4 to
f216c82
Compare
…ox#3626) * fix(docgen-sidebar): add collapsible component to hide nested tags * fix(docgen-sidebar): nesting of tags in tag tree * fix(docgen-tags): update styles to use blueprint tokens * fix(docgen-tags): replace bdl tokens with blueprint tokens * fix(docgen-tags): convert test from enzyme to rtl * fix(docgen-tags): remove snapshots, reuse blueprint loader * fix(docgen-tags): address code review comments * fix(docgen-tags): remove the sidebar test file * fix(docgen-tags): file with updated name * Update src/elements/content-sidebar/__tests__/DocGenSidebar.test.tsx Co-authored-by: greg-in-a-box <103291617+greg-in-a-box@users.noreply.github.com> * Update src/elements/content-sidebar/__tests__/DocGenSidebar.test.tsx Co-authored-by: greg-in-a-box <103291617+greg-in-a-box@users.noreply.github.com> * fix(docgen-sidebar): address code review comments * fix(docgen-sidebar): address code review comments * fix(docgen-sidebar): remove unused mock --------- Co-authored-by: greg-in-a-box <103291617+greg-in-a-box@users.noreply.github.com> Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
f216c82 to
de0375f
Compare
| * @param dialogueHistory | ||
| * @param {Array<object>} items - Array of items to ask about |
There was a problem hiding this comment.
suggestion: switch order to match actual params
| * @param dialogueHistory | |
| * @param {Array<object>} items - Array of items to ask about | |
| * @param {Array<object>} items - Array of items to ask about | |
| * @param dialogueHistory |
| question: QuestionType, | ||
| items: Array<BoxItem>, | ||
| dialogueHistory: Array<QuestionType> = [], | ||
| options: { include_citations: boolean } = {}, |
There was a problem hiding this comment.
is this supposed to be
| options: { include_citations: boolean } = {}, | |
| options: { include_citations?: boolean } = {}, |
? if it's defaulted to {}
| const errorMessage = error ? error.message || '' : ''; | ||
| const isRateLimitingError = | ||
| (error && error.response && error.response.status === 429) || rateLimitingRegex.test(errorMessage); |
There was a problem hiding this comment.
could use optional chaining here if you prefer. non-blocking, totally up to you
| const errorMessage = error ? error.message || '' : ''; | |
| const isRateLimitingError = | |
| (error && error.response && error.response.status === 429) || rateLimitingRegex.test(errorMessage); | |
| const errorMessage = error?.message || ''; | |
| const isRateLimitingError = | |
| (error?.response?.status === 429) || rateLimitingRegex.test(errorMessage); |
| const handleAsk = useCallback( | ||
| async (question: QuestionType, aiAgent: AgentType, isRetry = false) => { | ||
| !!onAsk && onAsk(); | ||
| const id = file && file.id; |
There was a problem hiding this comment.
when can file be falsy? what happens here if file is falsy?
| submitQuestion={handleAsk} | ||
| suggestedQuestions={suggestedQuestions || localizedQuestions} | ||
| warningNotice={spreadsheetNotice} | ||
| warningNoticeAriaLabel={formatMessage(messages.welcomeMessageSpreadsheetNoticeAriaLabel)} |
There was a problem hiding this comment.
should this also be conditional on isSpreadsheet?
There was a problem hiding this comment.
warningNotice controls if the ariaLabel is used.
| onModalClose={handleOnRequestClose} | ||
| open={isOpen} | ||
| onOpenChange={handleOnRequestClose} | ||
| onClearAction={handleClearConversation} |
There was a problem hiding this comment.
idk if you were going for alphabetizing here, but if so, these should be reordered
| ); | ||
| }; | ||
|
|
||
| export default withAPIContext(withCurrentUser(ContentAnswersModal)); |
There was a problem hiding this comment.
withCurrentUser already has withAPIContext, is it needed here?
There was a problem hiding this comment.
yea we need this here for the name and avatar url
There was a problem hiding this comment.
i think we talked about this but can you remind me what's happening here? shouldn't the props forwarded from withAPIContext be passed through withCurrentUser to this component?
279f2bc to
b4a3884
Compare
b4a3884 to
773c509
Compare
| expect(modal).toBeInTheDocument(); | ||
|
|
||
| const textArea = screen.getByRole('textbox', { name: 'Ask anything about this doc' }); | ||
| fireEvent.change(textArea, { target: { value: prompt } }); |
There was a problem hiding this comment.
the prompt here seems not defined in this file.
And could we try using userEvent.type(textArea, 'question prompt'). Same for ones used in ContentAnswersModal.test.tsx file.
Example https://github.com/box/box-ui-elements/blob/master/src/elements/content-explorer/__tests__/RenameDialog.test.tsx#L59-L62
|
|
||
| type Props = { | ||
| file: BoxItem; | ||
| }; |
There was a problem hiding this comment.
should the prop types above changed to interface like below
export interface contentAnswersProps extends ContentAnswersModalExternalProps {
show?: boolean;
file: BoxItem;
}
| onOpenChange={handleOnRequestClose} | ||
| onModalClose={handleOnRequestClose} |
There was a problem hiding this comment.
m comes before o in the alphabet!
4fc491f to
e04c240
Compare
e71ae24 to
57f2a49
Compare
| <Notification.Provider> | ||
| <Notification.Viewport /> | ||
| <TooltipProvider> |
There was a problem hiding this comment.
internal apps will likely have these providers already. any concerns with nested providers?
|
|
||
| const currentExtension = getProp(file, 'extension'); | ||
| return ( | ||
| <div className="bdl-ContentAnswers"> |
There was a problem hiding this comment.
this class name is no longer used i think. or should be changed to be-ContentAnswers
| | sharedLink | string | | *See the [developer docs](https://developer.box.com/docs/box-content-preview#section-options).* | | ||
| | sharedLinkPassword | string | | *See the [developer docs](https://developer.box.com/docs/box-content-preview#section-options).* | | ||
| | showAnnotations | boolean | `true` | *See the [developer docs](https://developer.box.com/docs/box-content-preview#section-options).* | | ||
| | shouldProvide | boolean | `true` | Decide if it should wrap the element with the `Notification` and `Tooltip` Provider. Set this to false if you already wrap your app with both of these providers. | |
There was a problem hiding this comment.
if this is a boolean then maybe hasProviders?
alternate approach:
or what about an array/object that specifies providers? that way it's more configurable depending on the providers that the consumer already has
for example:
// in consuming app
const providers = ['date-picker', 'notification', 'tooltip']; // Blueprint DatePicker has a provider we'll eventually need to include
<ContentPreview providers={providers} ... />
// in new providers component
const ElementProviders = ({ children, providers = ['notification', 'tooltip'] }) => {
let element = children;
providers.forEach(provider => {
switch (provider) {
case 'date-picker':
...
break;
case 'notification':
element = <Notification.Provider>...</Notification.Provider>;
break;
case 'tooltip':
element = <TooltipProvider>{element}</TooltipProvider>;
break;
}
});
return element;
};
| const [questions, setQuestions] = useState<QuestionType[]>([]); | ||
| let localizedQuestions: SuggestedQuestionType[] = []; | ||
|
|
||
| if (!suggestedQuestions) { |
There was a problem hiding this comment.
fyi an empty array for suggestedQuestions is truthy so this only enters the if statement for undefined. is that okay?
my guess is that it could render empty space but that seems out of scope for this component and more of something that should be handled by the shared-feature
| let localizedQuestions: SuggestedQuestionType[] = []; | ||
|
|
||
| if (!suggestedQuestions) { | ||
| localizedQuestions = DOCUMENT_SUGGESTED_QUESTIONS.map(question => ({ |
There was a problem hiding this comment.
is this something the webapp is doing for all file extensions?
There was a problem hiding this comment.
i feel like uses of useCallback in this file are unnecessary:
https://react.dev/reference/react/useCallback#should-you-add-usecallback-everywhere
| ); | ||
| }; | ||
|
|
||
| export default withAPIContext(withCurrentUser(ContentAnswersModal)); |
There was a problem hiding this comment.
i think we talked about this but can you remind me what's happening here? shouldn't the props forwarded from withAPIContext be passed through withCurrentUser to this component?
| // Note, you can still specify the more | ||
| // specific options listed in the section above |
There was a problem hiding this comment.
what does "section above" refer to?
There was a problem hiding this comment.
it looks like this file/object is used once, what about adding viewport property directly to preview.tsx?
There was a problem hiding this comment.
nit: Provide sounds a little odd to me as a component because of the verb. Providers sounds a little clearer
There was a problem hiding this comment.
related to conversation about granular providers, we might need to consider how customers can enable/disable providers like Theme, Router (react-router upgrade)
There was a problem hiding this comment.
yes for theme, but router no since that is more universal, unless the backwards compat guide says we need one
| import { render } from '../../../test-utils/testing-library'; | ||
| import Provide from '../Provide'; | ||
|
|
||
| describe('Provide component', () => { |
There was a problem hiding this comment.
should be path to component
| | sharedLink | string | | *See the [developer docs](https://developer.box.com/docs/box-content-preview#section-options).* | | ||
| | sharedLinkPassword | string | | *See the [developer docs](https://developer.box.com/docs/box-content-preview#section-options).* | | ||
| | showAnnotations | boolean | `true` | *See the [developer docs](https://developer.box.com/docs/box-content-preview#section-options).* | | ||
| | hasProviders | boolean | `true` | Decide if it should wrap the element with the `Notification` and `Tooltip` Provider. Set this to false if you already wrap your app with both of these providers. | |
| responseInterceptor?: Function, | ||
| sharedLink?: string, | ||
| sharedLinkPassword?: string, | ||
| hasProviders?: boolean, |
| expect(screen.getByRole('region', { name: 'Notifications (F8)' })).toBeInTheDocument(); | ||
| }); | ||
|
|
||
| test('renders only children when shouldProvide is false', () => { |
There was a problem hiding this comment.
| test('renders only children when shouldProvide is false', () => { | |
| test('renders only children when hasProviders is false', () => { |
| expect(screen.queryByRole('region', { name: 'Notifications (F8)' })).not.toBeInTheDocument(); | ||
| }); | ||
|
|
||
| test('throws an error if more than one child is provided when shouldProvide is false', () => { |
There was a problem hiding this comment.
| test('throws an error if more than one child is provided when shouldProvide is false', () => { | |
| test('throws an error if more than one child is provided when hasProviders is false', () => { |
| ).toThrow(); | ||
| }); | ||
|
|
||
| test('renders children within Notification and TooltipProvider by default when shouldProvide is not provided', () => { |
There was a problem hiding this comment.
| test('renders children within Notification and TooltipProvider by default when shouldProvide is not provided', () => { | |
| test('renders children within Notification and TooltipProvider by default when hasProviders is not provided', () => { |
| renderComponent({ fileExtension: 'invalid', onClick }); | ||
| expect(onClick).toBeCalledTimes(0); | ||
| const button = screen.getByRole('button'); | ||
| await userEvent.click(button, { pointerEventsCheck: 0 }); |
There was a problem hiding this comment.
what's pointerEventsCheck for? is this optimization?
There was a problem hiding this comment.
it throws an error like this Error: Unable to perform pointer interaction as the element has pointer-events: none if that flag isnt there, the button from blueprint set pointer-events to none
| test('should display not allowed tooltip', async () => { | ||
| renderComponent({ fileExtension: 'invalid' }); | ||
| const button = screen.getByRole('button', { name: 'Box AI' }); | ||
| await userEvent.hover(button, { pointerEventsCheck: 0 }); |
There was a problem hiding this comment.
is hover using pointer events?
| * @param {QuestionType} question - Object should at least contain the prompt, which is the question to ask | ||
| * @param {Array<object>} items - Array of items to ask about | ||
| * @param dialogueHistory | ||
| * @param options | ||
| * @param {Array<QuestionType>} dialogueHistory - Array of previous questions object that already have answers |
There was a problem hiding this comment.
naming QuestionType with a -Type suffix instead of Question is like naming something FooInterface instead of Foo, right? is that an existing naming convention in this repo? if not, can we rename QuestionType to Question?
is it possible to make these types stronger, eg. define a QuestionWithAnswer type that is Question & { answer... }
There was a problem hiding this comment.
that type is coming from the shared-feature, its the name they are using
| expect(answer).toBeInTheDocument(); | ||
|
|
||
| expect(modal.getByText('Based on:')).toBeInTheDocument(); | ||
| expect(modal.queryByText('Based on:')).not.toBeInTheDocument(); |
There was a problem hiding this comment.
where is the text 'Based on:' actually rendered from? does it come from the api response or is it hardcoded in the repo?
There was a problem hiding this comment.
part of the citation feature that appears in the answer if the citations are present via the shared-features
* fix(docgen-sidebar): add collapsible component to hide nested tags (box#3626) * fix(docgen-sidebar): add collapsible component to hide nested tags * fix(docgen-sidebar): nesting of tags in tag tree * fix(docgen-tags): update styles to use blueprint tokens * fix(docgen-tags): replace bdl tokens with blueprint tokens * fix(docgen-tags): convert test from enzyme to rtl * fix(docgen-tags): remove snapshots, reuse blueprint loader * fix(docgen-tags): address code review comments * fix(docgen-tags): remove the sidebar test file * fix(docgen-tags): file with updated name * Update src/elements/content-sidebar/__tests__/DocGenSidebar.test.tsx Co-authored-by: greg-in-a-box <103291617+greg-in-a-box@users.noreply.github.com> * Update src/elements/content-sidebar/__tests__/DocGenSidebar.test.tsx Co-authored-by: greg-in-a-box <103291617+greg-in-a-box@users.noreply.github.com> * fix(docgen-sidebar): address code review comments * fix(docgen-sidebar): address code review comments * fix(docgen-sidebar): remove unused mock --------- Co-authored-by: greg-in-a-box <103291617+greg-in-a-box@users.noreply.github.com> Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com> * chore(storybook): Added global types for storybook * feat(content-answers): Upgrade Content Answers * feat(content-answers): fix tests * feat(content-answers): Enabled some new features * feat(content-answers): Feedback * chore(content-answers): feedback * feat(content-answers): Feedback * feat(content-answers): Feedback * feat(content-answers): Feedback * feat(content-answers): vrt width * feat(content-answers): Feedback * feat(content-answers): Feedback * feat(content-answers): Providers * feat(content-answers): Providers * feat(content-answers): Feedback * feat(content-answers): Feedback * feat(content-answers): tests * feat(content-answers): Feedback * feat(content-answers): Feedback --------- Co-authored-by: rustam-e <6816931+rustam-e@users.noreply.github.com> Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
Updated Content Answer with the latest features