Skip to content

feat: desktop Search UI revamp #7895

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

Merged
merged 25 commits into from
May 11, 2025
Merged

Conversation

asjqkkkk
Copy link
Collaborator

@asjqkkkk asjqkkkk commented May 8, 2025

Feature Preview


PR Checklist

  • My code adheres to AppFlowy's Conventions
  • I've listed at least one issue that this PR fixes in the description above.
  • I've added a test(s) to validate changes in this PR, or this PR only contains semantic changes.
  • All existing tests are passing.

Summary by Sourcery

Revamp the desktop search UI to improve the user experience and add new features for searching and interacting with AI

New Features:

  • Add AI-powered search overview
  • Implement enhanced search result preview
  • Add ability to ask AI follow-up questions directly from search

Enhancements:

  • Improve search result cell design
  • Add view path display in search results
  • Enhance text highlighting in search results
  • Improve command palette UI

Chores:

  • Refactor search-related components
  • Update search-related translations

Copy link
Contributor

sourcery-ai bot commented May 8, 2025

Reviewer's Guide

This PR overhauls the desktop Search UI by redesigning key components (SearchResultCell, SearchSummaryCell, SearchField, etc.) using AppFlowyThemeData for a consistent look and richer information display, including highlighted text, ancestor paths, and detailed previews. It introduces an "Ask AI" feature through the new SearchAskAiEntrance widget and updates to CommandPaletteBloc, enabling users to query AI, view summaries, and transition to a pre-filled AI chat. The command palette's toggling mechanism and state management were also enhanced to accept more contextual information.

Sequence Diagram: "Ask AI" - User Initiates Query to AI Chat

sequenceDiagram
    actor User
    participant CPM as CommandPaletteModal
    participant CPB as CommandPaletteBloc
    participant SAAE as SearchAskAiEntrance
    participant AICP as AI Chat Page (DesktopPromptInput)

    User->>CPM: Opens Command Palette & types query "Q"
    CPM->>CPB: Event.searchChanged("Q")
    CPB-->>SAAE: State updated (query="Q")
    SAAE-->>User: Shows "Ask AI for 'Q'"
    User->>SAAE: Clicks "Ask AI for 'Q'"
    SAAE->>CPB: Event.gointToAskAI(sources=null)
    CPB-->>CPB: Updates state (askAI=true)
    CPB-->>CPM: Signals to close
    CPM-->>User: Closes
    Note right of User: Navigates to AI Chat Page
    AICP->>AICP: checkForAskingAI() called
    AICP-->>CPB: Event.askedAI() (to reset askAI flag)
    AICP-->>User: AI Chat pre-filled with "Q"
Loading

Sequence Diagram: "Ask AI" - User Asks Follow-up from AI Overview

sequenceDiagram
    actor User
    participant CPM as CommandPaletteModal
    participant CPB as CommandPaletteBloc
    participant SAAE as SearchAskAiEntrance
    participant SummaryCell as SearchSummaryCell (in _AIOverview)
    participant AICP as AI Chat Page (DesktopPromptInput)

    User->>CPM: Opens Command Palette & types query "Q"
    CPM->>CPB: Event.searchChanged("Q")
    CPB-->>CPB: Generates AI summary (summary1 with sources S1)
    CPB-->>SAAE: State updated (resultSummaries=[summary1])
    SAAE-->>User: Shows AI Overview with summary1
    User->>SummaryCell: Clicks "Ask Follow-Up"
    SummaryCell->>CPB: Event.gointToAskAI(sources=S1)
    CPB-->>CPB: Updates state (askAI=true, askAISources=S1)
    CPB-->>CPM: Signals to close
    CPM-->>User: Closes
    Note right of User: Navigates to AI Chat Page
    AICP->>AICP: checkForAskingAI() called
    AICP-->>CPB: Event.askedAI() (to reset askAI flag)
    AICP-->>User: AI Chat pre-filled with "Q" and sources S1
Loading

Sequence Diagram: Updated Search Result Display with Hover Preview

sequenceDiagram
    actor User
    participant SF as SearchField
    participant CPB as CommandPaletteBloc
    participant SRL as SearchResultList
    participant SRC as SearchResultCell
    participant SCP as SearchCellPreview

    User->>SF: Types query "project plan"
    SF->>CPB: CommandPaletteEvent.searchChanged("project plan")
    CPB->>CPB: Performs search, updates state with results
    CPB-->>SRL: State updated (resultItems=[item1, item2])
    SRL-->>User: Displays list of SearchResultCells
    User->>SRC: Hovers over item1 (SearchResultCell)
    SRC->>SRL: Notifies SearchResultListBloc (onHoverResult item1)
    SRL-->>SRL: Updates its state (hoveredResult=item1)
    SRL-->>SCP: Shows SearchResultPreview for item1
    SCP-->>User: Displays detailed preview of item1 (title, path, dates, etc.)
Loading

Class Diagram: Updated SearchSummaryCell and new _TextInfo

classDiagram
    class SearchSummaryCell {
        +SearchSummaryPB summary
        +double maxWidth
        +AppFlowyThemeData theme
        +State~SearchSummaryCell~ createState()
        +initState() void
        +didUpdateWidget(SearchSummaryCell oldWidget) void
        +dispose() void
        +build(BuildContext context) Widget
        +buildReferenceIcon() Widget
        +showPopover() void
        +hidePopover() void
        +refreshTextPainter() void
    }
    class _SearchSummaryCellState {
        -TextPainter _painter
        -_TextInfo _textInfo
        -bool tappedShowMore
        -int maxLines
        -PopoverController popoverController
        +SearchSummaryPB summary
        +double maxWidth
        +AppFlowyThemeData theme
    }
    SearchSummaryCell --|> StatefulWidget
    SearchSummaryCell "1" *-- "1" _SearchSummaryCellState : creates
    _SearchSummaryCellState "1" *-- "1" _TextInfo : uses

    class _TextInfo {
        +String text
        +bool isOverflow
        +_TextInfo(String text, bool isOverflow)
        +_TextInfo.normal(String text)
        +_TextInfo.overflow(String text)
        +build(...) Widget
        -_buildHighLightSpan(...) TextSpan
    }
    note for SearchSummaryCell "Handles display of search summaries, including text truncation, highlighting, and a popover for sources. Changed to StatefulWidget."
Loading

Class Diagram: Redesigned SearchResultCell

classDiagram
    class SearchResultCell {
        +SearchResultItem item
        +String? query
        +bool isHovered
        +State~SearchResultCell~ createState()
    }
    class _SearchResultCellState {
        -FocusNode focusNode
        +String viewId
        +SearchResultItem item
        +dispose() void
        -_handleSelection() void
        +build(BuildContext context) Widget
        +buildIcon(AppFlowyThemeData theme) Widget
        +buildPath(AppFlowyThemeData theme) Widget
        +buildHighLightSpan(String content, TextStyle normal, TextStyle highlight) TextSpan
        +buildSummary(AppFlowyThemeData theme) List~Widget~
    }
    SearchResultCell --|> StatefulWidget
    SearchResultCell "1" *-- "1" _SearchResultCellState : creates
    _SearchResultCellState ..> SearchResultListBloc : reads
    _SearchResultCellState ..> ViewAncestorBloc : uses
    note for SearchResultCell "Redesigned to display individual search results with richer information like title, ancestor path, summary, and highlighting."
Loading

Class Diagram: New SearchAskAiEntrance and its States

classDiagram
    class SearchAskAiEntrance {
        +build(BuildContext context) Widget
    }
    SearchAskAiEntrance --|> StatelessWidget
    SearchAskAiEntrance ..> CommandPaletteBloc : reads state
    SearchAskAiEntrance ..> _AskAIFor : instantiates / shows
    SearchAskAiEntrance ..> _AISearching : instantiates / shows
    SearchAskAiEntrance ..> _AIOverview : instantiates / shows

    class _AskAIFor {
        +build(BuildContext context) Widget
        +buildText(BuildContext context) Widget
    }
    _AskAIFor --|> StatelessWidget
    _AskAIFor ..> CommandPaletteBloc : reads state & dispatches event

    class _AISearching {
        +build(BuildContext context) Widget
    }
    _AISearching --|> StatelessWidget

    class _AIOverview {
        +build(BuildContext context) Widget
        +buildHeader(BuildContext context) Widget
    }
    _AIOverview --|> StatelessWidget
    _AIOverview ..> CommandPaletteBloc : reads state & dispatches event
    _AIOverview ..> SearchSummaryCell : uses
    note for SearchAskAiEntrance "New widget for the 'Ask AI' feature, managing different UI states: initial prompt, searching, and displaying AI overview."
Loading

Class Diagram: DesktopPromptInput AI Integration Update

classDiagram
    class DesktopPromptInput {
        +void Function(String, PromptFormat?, Map<String, String>) onSubmitted
        +void Function(List<String>) onUpdateSelectedSources
        +checkForAskingAI() void
        <<Widget>>
    }
    DesktopPromptInput ..> CommandPaletteBloc : reads state & dispatches event
    DesktopPromptInput ..> AIPromptInputBloc : reads state & dispatches event
    note for DesktopPromptInput "Handles prompt input for AI. Added checkForAskingAI method to integrate with command palette's 'Ask AI' flow, pre-filling query and sources."
Loading

File-Level Changes

Change Details Files
Redesigned core search components with a new theme, improved layouts, and enhanced information display.
  • Applied AppFlowyThemeData for consistent styling across components.
  • Updated layouts for search results, recent views, and the search input field for better readability.
  • Improved NoSearchResultsHint with an icon and a direct link to the Trash.
frontend/appflowy_flutter/lib/workspace/presentation/command_palette/widgets/search_summary_cell.dart
frontend/appflowy_flutter/lib/workspace/presentation/command_palette/widgets/search_result_cell.dart
frontend/appflowy_flutter/lib/workspace/presentation/command_palette/widgets/search_field.dart
frontend/appflowy_flutter/lib/workspace/presentation/command_palette/widgets/recent_views_list.dart
frontend/appflowy_flutter/lib/workspace/presentation/command_palette/widgets/search_recent_view_cell.dart
frontend/appflowy_flutter/lib/workspace/presentation/command_palette/command_palette.dart
Integrated 'Ask AI' functionality into the command palette for AI-powered search and chat initiation.
  • Introduced SearchAskAiEntrance widget to provide UI for AI interactions (asking, searching, viewing overview).
  • Modified CommandPaletteBloc to manage AI query state and pass contextual sources.
  • Enabled transitioning from search/AI summary to a pre-filled AI chat session.
frontend/appflowy_flutter/lib/workspace/presentation/command_palette/widgets/search_ask_ai_entrance.dart
frontend/appflowy_flutter/lib/workspace/presentation/command_palette/command_palette.dart
frontend/appflowy_flutter/lib/workspace/application/command_palette/command_palette_bloc.dart
frontend/appflowy_flutter/lib/ai/widgets/prompt_input/desktop_prompt_input.dart
Improved display of search summaries and results with text truncation, source linking, detailed previews, and ancestor paths.
  • Added 'see more' functionality for long summaries and a popover for document sources in SearchSummaryCell.
  • Revamped SearchResultPreview to display detailed view metadata including timestamps and full path.
  • Implemented ancestor path display for views in search results and recent items.
  • Added query highlighting in titles and content snippets for better relevance.
frontend/appflowy_flutter/lib/workspace/presentation/command_palette/widgets/search_summary_cell.dart
frontend/appflowy_flutter/lib/workspace/presentation/command_palette/widgets/search_result_cell.dart
frontend/appflowy_flutter/lib/mobile/presentation/search/mobile_view_ancestors.dart
Refined command palette's toggling mechanism to include BLoC context for more informed operations.
  • Updated CommandPalette.toggle to accept UserWorkspaceBloc and SpaceBloc.
  • Modified the sidebar search button to provide this BLoC context when opening the palette.
frontend/appflowy_flutter/lib/workspace/presentation/command_palette/command_palette.dart
frontend/appflowy_flutter/lib/startup/tasks/app_widget.dart
frontend/appflowy_flutter/lib/workspace/presentation/home/menu/sidebar/sidebar.dart

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

Copy link
Contributor

@sourcery-ai sourcery-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey @asjqkkkk - I've reviewed your changes - here's some feedback:

  • Consider breaking down SearchSummaryCell and SearchResultCell further, as their responsibilities have significantly increased with the new UI and features.
  • The 'Ask AI' initiation in DesktopPromptInput using addPostFrameCallback might be more robust if triggered directly by a dedicated event from CommandPaletteBloc.
Here's what I looked at during the review
  • 🟡 General issues: 2 issues found
  • 🟢 Security: all looks good
  • 🟢 Testing: all looks good
  • 🟢 Complexity: all looks good
  • 🟢 Documentation: all looks good

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

Comment on lines +46 to +49
void toggle({
UserWorkspaceBloc? workspaceBloc,
SpaceBloc? spaceBloc,
}) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion: Expand toggle API with additional dependencies.

Add internal docs clarifying workspaceBloc and spaceBloc expectations for future callers.

Suggested change
void toggle({
UserWorkspaceBloc? workspaceBloc,
SpaceBloc? spaceBloc,
}) {
/// Toggles the command palette's open/close state.
///
/// The [workspaceBloc] dependency is expected to handle workspace-related actions
/// and state updates, while the [spaceBloc] dependency should manage space-related features.
///
/// Providing these dependencies allows consumers to extend the toggle functionality with
/// domain-specific behavior when necessary.
void toggle({
UserWorkspaceBloc? workspaceBloc,
SpaceBloc? spaceBloc,
}) {

Copy link

github-actions bot commented May 8, 2025

🥷 Ninja i18n – 🛎️ Translations need to be updated

Project /project.inlang

lint rule new reports level link
Missing translation 203 warning contribute (via Fink 🐦)

@asjqkkkk asjqkkkk force-pushed the feat/desktop/search branch from ed60efe to 76740b2 Compare May 8, 2025 02:41
@asjqkkkk asjqkkkk added the v0.9.2 label May 8, 2025
@asjqkkkk asjqkkkk force-pushed the feat/desktop/search branch from 76740b2 to 689a9b3 Compare May 8, 2025 03:16
@asjqkkkk asjqkkkk force-pushed the feat/desktop/search branch from 4129f43 to a34d7ec Compare May 8, 2025 05:59
@LucasXu0 LucasXu0 merged commit 014928c into AppFlowy-IO:main May 11, 2025
19 checks passed
@asjqkkkk asjqkkkk deleted the feat/desktop/search branch May 12, 2025 01:56
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants