Skip to content

Improve slash menu desktop parity#357

Merged
appflowy merged 3 commits into
mainfrom
fix/slash-menu-parity
May 21, 2026
Merged

Improve slash menu desktop parity#357
appflowy merged 3 commits into
mainfrom
fix/slash-menu-parity

Conversation

@appflowy
Copy link
Copy Markdown
Contributor

@appflowy appflowy commented May 21, 2026

Summary

  • add desktop-style slash menu groups, aliases, and missing entries for PDF, date/reminder, Mermaid, chart, and linked chart
  • apply desktop parity restrictions for simple table cells and AI meeting blocks
  • keep slash menu keyboard navigation stable with empty results and add focused unit, BDD, and simple-table e2e coverage

Related to #53

Tests

  • pnpm exec bddgen test -c playwright.bdd.config.ts
  • pnpm exec jest src/components/editor/components/panels/slash-panel/tests/slash-menu-options.test.ts --no-coverage --runInBand
  • pnpm run lint
  • BASE_URL=http://localhost:3001 pnpm exec playwright test -c playwright.bdd.config.ts -g "Slash menu desktop grouping|Slash menu inside simple table|Slash menu no-result" --workers=1
  • BASE_URL=http://localhost:3001 pnpm exec playwright test -c playwright.config.ts playwright/e2e/page/simple-table.spec.ts -g "should support slash menu inside table cells" --workers=1

Summary by Sourcery

Align the editor slash menu with desktop behavior by introducing grouped, searchable options with new entries and contextual restrictions, and by improving panel triggering and keyboard handling for more robust navigation.

New Features:

  • Add grouped slash menu with desktop-style categories, aliases, shortcuts, and options for PDF, Mermaid, chart, linked chart, and date/reminder.
  • Support chart database views in slash-created databases and linked database blocks.

Enhancements:

  • Restrict slash menu options when invoked inside simple table cells and AI meeting blocks to match desktop limitations.
  • Stabilize slash menu keyboard navigation and selection when there are zero results, including Tab and NumpadEnter handling.
  • Improve panel triggering and positioning for slash, mention, and page reference panels, including better range-based fallbacks.
  • Refine simple table insertion to more reliably place the cursor at the start of the new table.

Tests:

  • Add unit tests for slash menu option matching, filtering, and grouping behavior.
  • Extend BDD and Playwright tests to cover slash menu grouping, contextual restrictions in simple tables, and no-result keyboard navigation behavior.

@sourcery-ai
Copy link
Copy Markdown

sourcery-ai Bot commented May 21, 2026

Reviewer's Guide

Refactors slash menu implementation to add desktop-style grouping, aliases, and new options (PDF, date/reminder, Mermaid, chart, linked chart), enforces desktop parity restrictions in simple table cells and AI meeting blocks, and improves keyboard interaction plus BDD/e2e coverage.

Sequence diagram for slash panel trigger handling

sequenceDiagram
  actor User
  participant SlateEditor
  participant PanelProvider
  participant PanelsContext

  User->>SlateEditor: type /
  SlateEditor->>PanelProvider: insertText /
  PanelProvider->>PanelProvider: panelTypeByTrigger[/]
  PanelProvider->>PanelsContext: openTriggerPanel PanelType.Slash
  PanelsContext->>PanelsContext: isSlashPanelBlocked selection
  alt slash panel allowed
    PanelsContext->>PanelsContext: getPanelPosition editor, selection
    PanelsContext->>PanelsContext: openPanel PanelType.Slash, position
    PanelsContext->>PanelsContext: set startSelection and endSelection
    PanelsContext-->>SlashPanel: activePanel = Slash
    SlashPanel->>SlashPanel: build options
    SlashPanel->>SlashPanel: filterSlashMenuOptions
    SlashPanel->>SlashPanel: groupSlashMenuOptions
    SlashPanel-->>User: render grouped slash menu
  else slash panel blocked
    PanelsContext-->>User: no panel opened
  end
Loading

Flow diagram for slash menu option filtering and grouping

flowchart LR
  A[Raw SlashMenuOption list] --> B[filterSlashMenuOptions]
  B -->|apply SIMPLE_TABLE_EXCLUDED_OPTION_KEYS
        when isInsideSimpleTableCell| B2[exclude simple-table and database options]
  B -->|apply AI_MEETING_EXCLUDED_OPTION_KEYS
        when isInsideAIMeeting| B3[exclude database and media options]
  B -->|matchesSlashMenuOption
        using searchText, keywords, aliases, shortcut| C[Filtered options]
  C --> D[groupSlashMenuOptions]
  D -->|use SLASH_MENU_GROUP_ORDER
        and option.group| E[Grouped options]
  E --> F[SlashPanel renders grouped buttons]
Loading

File-Level Changes

Change Details Files
Refactor slash panel options to support grouped desktop-style slash menu with aliases, shortcuts, and new block types (PDF, chart, linked chart, Mermaid, date/reminder).
  • Introduce SlashMenuOptionBase and SlashMenuGroupKey along with filterSlashMenuOptions and groupSlashMenuOptions helpers to own grouping, alias, and filtering logic.
  • Update SlashPanel to build a rich SlashMenuOption model including groups, aliases, and shortcuts and to render grouped sections with localized group labels.
  • Add new slash commands for PDF, chart, linked chart, Mermaid, and date/reminder, and extend existing commands with richer keyword/alias sets and database chart handling.
src/components/editor/components/panels/slash-panel/SlashPanel.tsx
src/components/editor/components/panels/slash-panel/slash-menu-options.ts
src/components/editor/components/panels/slash-panel/__tests__/slash-menu-options.test.ts
Align slash menu behavior with desktop restrictions in simple table cells and AI meeting blocks while making keyboard navigation more robust.
  • Add helpers to detect when the selection is inside simple table cells or AI meeting blocks and use them to filter out disallowed slash commands, including media and database options, per context.
  • Ensure embedded database block types include chart, and expand PDF/file handling while keeping selection and scroll behavior consistent when inserting embeds.
  • Stabilize slash menu keyboard navigation by preserving selection when results change, supporting Tab/Shift-Tab cycling, handling NumpadEnter, and allowing empty-result states without closing the menu.
src/components/editor/components/panels/slash-panel/SlashPanel.tsx
Enhance panel context to centralize trigger handling and improve position calculation and key handling for slash and mention panels.
  • Introduce panelTypeByTrigger and getPanelPosition utilities plus openTriggerPanel to reuse trigger logic for '/', '+', '@', and '[[' across panels.
  • Track openRef and activePanelRef explicitly when opening/closing panels and block slash panels in non-supported blocks while computing robust fallback positions from DOM ranges or editor nodes.
  • Move keydown handling to a document-level listener that can open the slash panel from keyboard events (including physical slash key) while preserving Escape and Backspace behavior.
src/components/editor/components/panels/PanelsContext.tsx
Extend BDD and e2e coverage for slash menu grouping, simple table restrictions, and keyboard behavior.
  • Refactor BDD steps to use a shared openSlashMenuAtCurrentSelection helper and add steps for focusing specific simple table cells and asserting command/group visibility or hidden status.
  • Add BDD scenarios to validate desktop-style grouping and aliases, simple table restrictions (including availability of PDF and date/reminder), and resilience of the menu under no-result keyboard navigation.
  • Augment existing simple-table Playwright test to assert that restricted commands are hidden and allowed ones (PDF, date/reminder) remain available in table cells.
playwright/bdd/steps/editor-editing.steps.ts
playwright/bdd/features/editor/editor-editing.feature
playwright/e2e/page/simple-table.spec.ts

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
Copy Markdown

@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 - I've found 1 issue, and left some high level feedback:

  • The two exclusion sets in slash-menu-options.ts (SIMPLE_TABLE_EXCLUDED_OPTION_KEYS and AI_MEETING_EXCLUDED_OPTION_KEYS) duplicate a lot of values; consider factoring out a shared base set (e.g. EXCLUDED_DATABASE_AND_TABLE_KEYS) to make it clearer what differs between contexts and reduce the chance of them drifting out of sync.
  • The SlashMenuOptionBase.key is a plain string while the various exclusion sets and tests depend on specific literals; you could tighten this with a string-literal union type or an enum for option keys to catch typos and make it easier to reason about which keys are valid.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- The two exclusion sets in `slash-menu-options.ts` (`SIMPLE_TABLE_EXCLUDED_OPTION_KEYS` and `AI_MEETING_EXCLUDED_OPTION_KEYS`) duplicate a lot of values; consider factoring out a shared base set (e.g. `EXCLUDED_DATABASE_AND_TABLE_KEYS`) to make it clearer what differs between contexts and reduce the chance of them drifting out of sync.
- The `SlashMenuOptionBase.key` is a plain string while the various exclusion sets and tests depend on specific literals; you could tighten this with a string-literal union type or an enum for option keys to catch typos and make it easier to reason about which keys are valid.

## Individual Comments

### Comment 1
<location path="src/components/editor/components/panels/slash-panel/slash-menu-options.ts" line_range="87-91" />
<code_context>
+  });
+}
+
+export function groupSlashMenuOptions<T extends SlashMenuOptionBase>(options: T[]) {
+  return SLASH_MENU_GROUP_ORDER.map((group) => ({
+    group,
+    options: options.filter((option) => option.group === group),
+  })).filter(({ options }) => options.length > 0);
+}
</code_context>
<issue_to_address>
**suggestion (bug_risk):** Handle options whose group is not in SLASH_MENU_GROUP_ORDER to avoid silently dropping them

Currently, any option whose `group` is not in `SLASH_MENU_GROUP_ORDER` is never rendered. This works only if all callers always use known groups, but it’s easy to break when adding new groups.

To make this more robust, either:
- Validate/throw (at least in dev) when an option’s `group` is not in `SLASH_MENU_GROUP_ORDER`, or
- Add a catch‑all for unknown groups (e.g., collect options whose `group` isn’t in `SLASH_MENU_GROUP_ORDER` into extra groups and append them after the ordered ones).

This avoids new groups silently disappearing if `SLASH_MENU_GROUP_ORDER` isn’t updated in sync.
</issue_to_address>

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 +87 to +91
export function groupSlashMenuOptions<T extends SlashMenuOptionBase>(options: T[]) {
return SLASH_MENU_GROUP_ORDER.map((group) => ({
group,
options: options.filter((option) => option.group === group),
})).filter(({ options }) => options.length > 0);
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

suggestion (bug_risk): Handle options whose group is not in SLASH_MENU_GROUP_ORDER to avoid silently dropping them

Currently, any option whose group is not in SLASH_MENU_GROUP_ORDER is never rendered. This works only if all callers always use known groups, but it’s easy to break when adding new groups.

To make this more robust, either:

  • Validate/throw (at least in dev) when an option’s group is not in SLASH_MENU_GROUP_ORDER, or
  • Add a catch‑all for unknown groups (e.g., collect options whose group isn’t in SLASH_MENU_GROUP_ORDER into extra groups and append them after the ordered ones).

This avoids new groups silently disappearing if SLASH_MENU_GROUP_ORDER isn’t updated in sync.

@appflowy appflowy merged commit f7d933e into main May 21, 2026
11 of 13 checks passed
@appflowy appflowy deleted the fix/slash-menu-parity branch May 21, 2026 07:08
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant