-
Notifications
You must be signed in to change notification settings - Fork 925
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
AIChat: Add Welcome guide as a new opt-in UX #20750
Conversation
A Storybook has been deployed to preview UI for the latest push |
The security team is monitoring all repositories for certain keywords. This PR includes the word(s) "policy" and so security team members have been added as reviewers to take a look. |
A Storybook has been deployed to preview UI for the latest push |
A Storybook has been deployed to preview UI for the latest push |
A Storybook has been deployed to preview UI for the latest push |
components/ai_chat/resources/page/components/welcome_guide/index.tsx
Outdated
Show resolved
Hide resolved
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This needs to handle pending messages in the c++, i.e. messages sent from the location bar pre opt-in. When fixing that, perhaps also put your pending clientside message their instead of making a new frontend state field for it.
A Storybook has been deployed to preview UI for the latest push |
@@ -316,7 +316,7 @@ void AIChatTabHelper::MaybeGeneratePageText() { | |||
// Perf: make sure we're not doing this when the feature | |||
// won't be used (e.g. not opted in or no active conversation). | |||
if (is_page_text_fetch_in_progress_ || !article_text_.empty() || | |||
!HasUserOptedIn() || !is_conversation_active_ || | |||
!is_conversation_active_ || |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You removed HasUserOptedIn and the comment doesn't make sense anymore
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yes, i will revise the comment
@@ -336,7 +336,8 @@ void AIChatTabHelper::MaybeGeneratePageText() { | |||
FetchPageContent( | |||
web_contents(), | |||
base::BindOnce(&AIChatTabHelper::OnTabContentRetrieved, | |||
weak_ptr_factory_.GetWeakPtr(), current_navigation_id_)); | |||
weak_ptr_factory_.GetWeakPtr(), current_navigation_id_), | |||
HasUserOptedIn()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If HasUserOptedIn()
is false
then FetchPageContent
doesn't do anything (if it has to make a fetch). So in those cases it won't get content. So why not avoid that complication by not calling FetchPageContent
? As discussed, the opt-in UX doesn't need to know anything about the page content, it only needs to know if the page has content. At the moment all pages have content if they are http(s). Can't we just send that data to the page's opt-in UX so it can differ whether it shows the page content association or not? For example, SiteInfo
can simply get an { isPresent: boolean }
new property as well as title
becoming optional.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If the user hasn't opted in, FetchPageContent will still be called. Previously, we would gate the call with various conditions, including the user not having opted in. However, now we send that boolean through. We gate it prior to sending results, and in the case of video, we don't make a network request.
@@ -20,7 +20,8 @@ function ConversationList() { | |||
isGenerating, | |||
conversationHistory, | |||
suggestedQuestions, | |||
shouldDisableUserInput | |||
shouldDisableUserInput, | |||
hasAcceptedAgreement |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
shouldShowQuestions
to avoid non-relevant logic in here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
sorry, what are you referring to here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You have added a new prop to the ConverationList
component: hasAcceptedAgreement
. It means that the ConversationList
component now needs to know what to show before or after the user has accepted the agreement. I'm suggesting it's better to keep all that logic in one place, at a higher level, than spread it around lower-level components. Hence, putting a prop such as shouldShowQuestions
on this component instead.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
makes sense, added
380f638
to
afe1328
Compare
A Storybook has been deployed to preview UI for the latest push |
@@ -149,4 +149,5 @@ interface ChatUIPage { | |||
// |is_fetching| will be |true|. | |||
OnSiteInfoChanged(bool is_fetching, SiteInfo? info); | |||
OnFaviconImageDataChanged(array<uint8> favicon_image_data); | |||
OnRequestPending(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is too generic - how about it's named OnConversationEntryPending()
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
renamed
afe1328
to
23ba529
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
strings
++
Thanks, I've addressed the UI issues you mentioned. However, there are minor font spacing and line-height differences. For example, the main title and subtitle have a 40px line height, but Figma uses 36px. Nala is currently undergoing upgrades, and it's taking some time due to the font hierarchy reconstruction. Additionally, I've collaborated with @aguscruiz on graphic element positioning and font weights. He has made the necessary updates in Figma, so your screenshot may be outdated when reviewing this. The dialog component has been replaced with Nala's as well. |
A Storybook has been deployed to preview UI for the latest push |
A Storybook has been deployed to preview UI for the latest push |
650f051
to
7224310
Compare
A Storybook has been deployed to preview UI for the latest push |
A Storybook has been deployed to preview UI for the latest push |
// Trigger the observer because there might be a pending conversation entry. | ||
// In some cases, this page handler hasn't been created and remote might not | ||
// have been set yet, ensuring that we don't miss any UI updates, we trigger | ||
// the observer again. | ||
if (active_chat_tab_helper_ && | ||
active_chat_tab_helper_->HasPendingConversationEntry()) { | ||
OnConversationEntryPending(); | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This comment doesn't really make sense to me - I think it's simply something like "Get current state data" - i.e. we're getting the current state because we haven't been around to get events yet. This is probably where we should put everything that's needed initially...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
in essence, sure, it's getting "current state data" but that's obvious, right?
the not-so obvious part here is, why are we triggering OnConversationEntryPending
event, specifically because no other events are there.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
i have revised the comment which describes the scenario why this happens.
components/ai_chat/resources/page/state/data-context-provider.tsx
Outdated
Show resolved
Hide resolved
A Storybook has been deployed to preview UI for the latest push |
A Storybook has been deployed to preview UI for the latest push |
@@ -159,7 +164,8 @@ class ConversationDriver { | |||
mojom::APIError current_error_ = mojom::APIError::None; | |||
mojom::PremiumStatus last_premium_status_ = mojom::PremiumStatus::Inactive; | |||
|
|||
std::unique_ptr<mojom::ConversationTurn> pending_request_; | |||
std::unique_ptr<mojom::ConversationTurn> pending_conversation_entry_; | |||
bool is_pending_content_retreival_ = false; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we already have bool is_page_text_fetch_in_progress_
. How is this different? If there is reason to have both, then it would be clearer if they are next to each other and commented. I'm also wondering why ConversationDriver::HasPageContent
doesn't need to consider this new property? Perhaps we should simplify by storing something like a PageContentAssociation page_status
property.
@@ -102,7 +103,7 @@ function DataContextProvider (props: DataContextProviderProps) { | |||
getPageHandlerInstance().pageHandler.generateQuestions() | |||
} | |||
|
|||
const handleSiteInfo = (isFetching: boolean, siteInfo: mojom.SiteInfo | null) => { | |||
const handleSiteInfo = (isFetching: boolean, siteInfo: mojom.SiteInfo | undefined) => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This doesn't seem correct now that you've changed siteInfo to non-optional
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fixed: 87b88d3
void AIChatUIPageHandler::SubmitSummarizationRequestFromWelcomeView() { | ||
mojom::ConversationTurn turn = { | ||
CharacterType::HUMAN, ConversationTurnVisibility::VISIBLE, | ||
l10n_util::GetStringUTF8(IDS_CHAT_UI_SUMMARIZE_PAGE)}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This seems pretty fragile - we're using this specific string because we know that the ConversationDriver happens to treat it as a special summarization request. I think this decision should at least be contained within the same file. So, how about passing through SubmitSummarizationRequestFromWelcomeView
to the ConversationDriver
?
std::move(callback).Run(is_fetching_content, site_info.has_value() | ||
? site_info.value().Clone() | ||
: nullptr); | ||
std::move(callback).Run(is_fetching_content, site_info.Clone()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this would be less confusing now that SiteInfo is non-optional, to put the fetching status as a property on SiteInfo, for GetSiteInfo
and for OnSiteInfoChanged
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fixed: 87b88d3
site_info.is_content_truncated = | ||
active_chat_tab_helper_->IsPageContentsTruncated(); | ||
site_info.is_content_present = | ||
active_chat_tab_helper_->IsPageContentsPresent(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is so confusing now - we have both ConversationDriver::HasPageContent
and ConversationDriver::IsPageContentsPresent
and it's not clear why they would differ. Can we use the existing HasPageContent
? If we need it to do something else let's be explicit about the states that associated content can be in, e.g.
- Fetching (i.e. "finding out")
- Has Content
- No Content
- Other...?
I can see that IsPageContentsPresent is checking whether it can be present (based on the Url) and HasPageContent is checking whether we ended up getting content, but I think HasPageContent can change to do the check in IsPageContentsPresent.
We can also put the enum directly on SiteInfo if that's cleaner. Less to wonder about.
1b00c8b
to
389bae2
Compare
A Storybook has been deployed to preview UI for the latest push |
e120725
to
103342c
Compare
- dont send opt-in bool - siteinfo has a new prop - rename pending conversation entries - uses nala dialog - nala dialog width should work - flush welcome guide to bottom - introducing should_show_questions prop - added pending_message_needs_page_content_ - siteInfo is non-optional - added logic to show_suggestion bool - special summarization request
103342c
to
bf40c91
Compare
A Storybook has been deployed to preview UI for the latest push |
closing this in-lieu of: #20966 |
Resolves brave/brave-browser#33942
This PR introduces a new welcome guide for users who haven't agreed to the policy terms. Once the user has viewed and accepted the policy, the welcome guide will no longer be displayed.
Submitter Checklist:
QA/Yes
orQA/No
;release-notes/include
orrelease-notes/exclude
;OS/...
) to the associated issuenpm run test -- brave_browser_tests
,npm run test -- brave_unit_tests
wikinpm run lint
,npm run presubmit
wiki,npm run gn_check
,npm run tslint
git rebase master
(if needed)Reviewer Checklist:
gn
After-merge Checklist:
changes has landed on
Test Plan: