Skip to content

Commit

Permalink
AI Chat storybook menu open responsiveness matches webui
Browse files Browse the repository at this point in the history
storybook context can use react hooks
  • Loading branch information
petemill committed Dec 13, 2024
1 parent 993d18f commit dd1e08f
Showing 1 changed file with 139 additions and 126 deletions.
265 changes: 139 additions & 126 deletions components/ai_chat/resources/page/stories/components_panel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,15 @@
* You can obtain one at https://mozilla.org/MPL/2.0/. */

import * as React from 'react'
import { useArgs, useState } from '@storybook/preview-api'
import { useArgs } from '@storybook/preview-api'
import { Meta, StoryObj } from '@storybook/react'
import '@brave/leo/tokens/css/variables.css'
import '$web-components/app.global.scss'
import { getKeysForMojomEnum } from '$web-common/mojomUtils'
import { InferControlsFromArgs } from '../../../../../.storybook/utils'
import * as Mojom from '../../common/mojom'
import { ActiveChatContext, SelectedChatDetails } from '../state/active_chat_context'
import { AIChatContext, AIChatReactContext } from '../state/ai_chat_context'
import { AIChatContext, AIChatReactContext, useIsSmall } from '../state/ai_chat_context'
import { ConversationContext, ConversationReactContext } from '../state/conversation_context'
import FeedbackForm from '../components/feedback_form'
import FullPage from '../components/full_page'
Expand Down Expand Up @@ -447,7 +447,7 @@ const args: CustomArgs = {
shouldShowRefinedWarning: false,
}

const preview: Meta<CustomArgs> = {
const meta: Meta<CustomArgs> = {
title: 'Chat/Chat',
parameters: {
layout: 'centered'
Expand All @@ -474,135 +474,148 @@ const preview: Meta<CustomArgs> = {
decorators: [
(Story, options) => {
const [, setArgs] = useArgs()

const siteInfo = options.args.hasSiteInfo ? SITE_INFO : new Mojom.SiteInfo()
const suggestedQuestions = options.args.hasSuggestedQuestions
? SAMPLE_QUESTIONS
: siteInfo
? [SAMPLE_QUESTIONS[0]]
: []

const currentError = Mojom.APIError[options.args.currentErrorState]
const apiHasError = currentError !== Mojom.APIError.None
const currentModel = MODELS.find(m => m.displayName === options.args.model)

const switchToBasicModel = () => {
const nonPremiumModel = MODELS.find(model => model.options.leoModelOptions?.access === Mojom.ModelAccess.BASIC)
setArgs({ model: nonPremiumModel })
}

const setInputText = (inputText: string) => {
setArgs({ inputText })
}

const [showSidebar, setShowSidebar] = useState(false)
const aiChatContext: AIChatContext = {
conversationEntriesComponent: StorybookConversationEntries,
initialized: options.args.initialized,
editingConversationId: options.args.editingConversationId,
visibleConversations: CONVERSATIONS.slice(0, options.args.visibleConversationListCount),
isStoragePrefEnabled: options.args.isStoragePrefEnabled,
hasAcceptedAgreement: options.args.hasAcceptedAgreement,
isPremiumStatusFetching: false,
isPremiumUser: options.args.isPremiumUser,
isPremiumUserDisconnected: options.args.isPremiumUserDisconnected,
isStorageNoticeDismissed: options.args.isStorageNoticeDismissed,
canShowPremiumPrompt: options.args.canShowPremiumPrompt,
isMobile: options.args.isMobile,
isHistoryFeatureEnabled: options.args.isHistoryEnabled,
isStandalone: options.args.isStandalone,
allActions: ACTIONS_LIST,
goPremium: () => {},
managePremium: () => {},
handleAgreeClick: () => {},
enableStoragePref: () => {},
markStorageNoticeViewed: () => {},
dismissStorageNotice: () => {},
dismissPremiumPrompt: () => {},
userRefreshPremiumSession: () => {},
setEditingConversationId: (id: string | null) => setArgs({ editingConversationId: id }),
showSidebar: showSidebar,
toggleSidebar: () => setShowSidebar(s => !s)
}

const activeChatContext: SelectedChatDetails = {
selectedConversationId: CONVERSATIONS[0].uuid,
updateSelectedConversationId: () => {},
callbackRouter: undefined!,
conversationHandler: undefined!,
createNewConversation: () => {},
isTabAssociated: options.args.isDefaultConversation
}

const inputText = options.args.inputText

const conversationContext: ConversationContext = {
conversationUuid: CONVERSATIONS[1].uuid,
conversationHistory: options.args.hasConversation ? HISTORY : [],
associatedContentInfo: siteInfo,
allModels: MODELS,
currentModel,
suggestedQuestions,
isGenerating: true,
suggestionStatus: Mojom.SuggestionGenerationStatus[options.args.suggestionStatus],
currentError,
apiHasError,
isFeedbackFormVisible: options.args.isFeedbackFormVisible,
shouldDisableUserInput: false,
shouldShowLongPageWarning: options.args.shouldShowLongPageWarning,
shouldShowLongConversationInfo: options.args.shouldShowLongConversationInfo,
shouldSendPageContents: siteInfo?.isContentAssociationPossible,
inputText,
actionList: ACTIONS_LIST,
selectedActionType: undefined,
isToolsMenuOpen: false,
isCurrentModelLeo: true,
isCharLimitApproaching: inputText.length > 64,
isCharLimitExceeded: inputText.length > 70,
inputTextCharCountDisplay: `${inputText.length} / 70`,
setInputText,
setCurrentModel: () => {},
switchToBasicModel,
generateSuggestedQuestions: () => {},
dismissLongConversationInfo: () => {},
updateShouldSendPageContents: () => {},
retryAPIRequest: () => {},
handleResetError: () => {},
submitInputTextToAPI: () => {},
resetSelectedActionType: () => {},
handleActionTypeClick: () => {},
setIsToolsMenuOpen: () => {},
handleFeedbackFormCancel: () => {},
handleFeedbackFormSubmit: () => {}
}

const conversationEntriesContext: UntrustedConversationContext = {
conversationHistory: conversationContext.conversationHistory,
isGenerating: conversationContext.isGenerating,
isLeoModel: conversationContext.isCurrentModelLeo,
contentUsedPercentage: (options.args.shouldShowLongPageWarning || options.args.shouldShowRefinedWarning)
? 48 : 100,
isContentRefined: options.args.shouldShowRefinedWarning,
canSubmitUserEntries: !conversationContext.shouldDisableUserInput,
isMobile: aiChatContext.isMobile
}

return (
<AIChatReactContext.Provider value={aiChatContext}>
<ActiveChatContext.Provider value={activeChatContext}>
<ConversationReactContext.Provider value={conversationContext}>
<UntrustedConversationReactContext.Provider value={conversationEntriesContext}>
<Story />
</UntrustedConversationReactContext.Provider>
</ConversationReactContext.Provider>
</ActiveChatContext.Provider>
</AIChatReactContext.Provider>
<StoryContext args={options.args} setArgs={setArgs}>
<Story/>
</StoryContext>
)
}
]
}

export default preview
function StoryContext(props: React.PropsWithChildren<{args: CustomArgs, setArgs: (newArgs: Partial<CustomArgs>) => void}>) {
const isSmall = useIsSmall()

const options = { args: props.args }
const { setArgs } = props

const siteInfo = options.args.hasSiteInfo ? SITE_INFO : new Mojom.SiteInfo()
const suggestedQuestions = options.args.hasSuggestedQuestions
? SAMPLE_QUESTIONS
: siteInfo
? [SAMPLE_QUESTIONS[0]]
: []

const currentError = Mojom.APIError[options.args.currentErrorState]
const apiHasError = currentError !== Mojom.APIError.None
const currentModel = MODELS.find(m => m.displayName === options.args.model)

const switchToBasicModel = () => {
const nonPremiumModel = MODELS.find(model => model.options.leoModelOptions?.access === Mojom.ModelAccess.BASIC)
setArgs({ model: nonPremiumModel?.key })
}

const setInputText = (inputText: string) => {
setArgs({ inputText })
}

const [showSidebar, setShowSidebar] = React.useState(isSmall)

const aiChatContext: AIChatContext = {
conversationEntriesComponent: StorybookConversationEntries,
initialized: options.args.initialized,
editingConversationId: options.args.editingConversationId,
visibleConversations: CONVERSATIONS.slice(0, options.args.visibleConversationListCount),
isStoragePrefEnabled: options.args.isStoragePrefEnabled,
hasAcceptedAgreement: options.args.hasAcceptedAgreement,
isPremiumStatusFetching: false,
isPremiumUser: options.args.isPremiumUser,
isPremiumUserDisconnected: options.args.isPremiumUserDisconnected,
isStorageNoticeDismissed: options.args.isStorageNoticeDismissed,
canShowPremiumPrompt: options.args.canShowPremiumPrompt,
isMobile: options.args.isMobile,
isHistoryFeatureEnabled: options.args.isHistoryEnabled,
isStandalone: options.args.isStandalone,
allActions: ACTIONS_LIST,
goPremium: () => {},
managePremium: () => {},
handleAgreeClick: () => {},
enableStoragePref: () => {},
markStorageNoticeViewed: () => {},
dismissStorageNotice: () => {},
dismissPremiumPrompt: () => {},
userRefreshPremiumSession: () => {},
setEditingConversationId: (id: string | null) => setArgs({ editingConversationId: id }),
showSidebar: showSidebar,
toggleSidebar: () => setShowSidebar(s => !s)
}

const activeChatContext: SelectedChatDetails = {
selectedConversationId: CONVERSATIONS[0].uuid,
updateSelectedConversationId: () => {},
callbackRouter: undefined!,
conversationHandler: undefined!,
createNewConversation: () => {},
isTabAssociated: options.args.isDefaultConversation
}

const inputText = options.args.inputText

const conversationContext: ConversationContext = {
conversationUuid: CONVERSATIONS[1].uuid,
conversationHistory: options.args.hasConversation ? HISTORY : [],
associatedContentInfo: siteInfo,
allModels: MODELS,
currentModel,
suggestedQuestions,
isGenerating: true,
suggestionStatus: Mojom.SuggestionGenerationStatus[options.args.suggestionStatus],
currentError,
apiHasError,
isFeedbackFormVisible: options.args.isFeedbackFormVisible,
shouldDisableUserInput: false,
shouldShowLongPageWarning: options.args.shouldShowLongPageWarning,
shouldShowLongConversationInfo: options.args.shouldShowLongConversationInfo,
shouldSendPageContents: siteInfo?.isContentAssociationPossible,
inputText,
actionList: ACTIONS_LIST,
selectedActionType: undefined,
isToolsMenuOpen: false,
isCurrentModelLeo: true,
isCharLimitApproaching: inputText.length > 64,
isCharLimitExceeded: inputText.length > 70,
inputTextCharCountDisplay: `${inputText.length} / 70`,
setInputText,
setCurrentModel: () => {},
switchToBasicModel,
generateSuggestedQuestions: () => {},
dismissLongConversationInfo: () => {},
updateShouldSendPageContents: () => {},
retryAPIRequest: () => {},
handleResetError: () => {},
submitInputTextToAPI: () => {},
resetSelectedActionType: () => {},
handleActionTypeClick: () => {},
setIsToolsMenuOpen: () => {},
handleFeedbackFormCancel: () => {},
handleFeedbackFormSubmit: () => {}
}

const conversationEntriesContext: UntrustedConversationContext = {
conversationHistory: conversationContext.conversationHistory,
isGenerating: conversationContext.isGenerating,
isLeoModel: conversationContext.isCurrentModelLeo,
contentUsedPercentage: (options.args.shouldShowLongPageWarning || options.args.shouldShowRefinedWarning)
? 48 : 100,
isContentRefined: options.args.shouldShowRefinedWarning,
canSubmitUserEntries: !conversationContext.shouldDisableUserInput,
isMobile: aiChatContext.isMobile
}

return (
<AIChatReactContext.Provider value={aiChatContext}>
<ActiveChatContext.Provider value={activeChatContext}>
<ConversationReactContext.Provider value={conversationContext}>
<UntrustedConversationReactContext.Provider value={conversationEntriesContext}>
{props.children}
</UntrustedConversationReactContext.Provider>
</ConversationReactContext.Provider>
</ActiveChatContext.Provider>
</AIChatReactContext.Provider>
)
}

export default meta

type Story = StoryObj<CustomArgs>

Expand Down

0 comments on commit dd1e08f

Please sign in to comment.