Repository navigation
Group knowledge bases named owner/name in the pickers - #1250
Conversation
Bumps Utopia to `0.1.0-re.3` (digest `sha256:30e899da…`). That's `re.2` plus deeplethe/utopia#1250: knowledge bases named `owner/name`, like the ones lore-api creates per repository, are grouped under the owner. The top-bar switcher and the chat input show `re-cinq ›` with a submenu, the token picker shows a `re-cinq` heading, and the My knowledge bases table gets a header row. Search still lists full names. The change is web-only, with no migrations (the database stays at 0113). Before pushing, I booted the image on a fresh database: health ok, web 200, no errors. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
WaylandYang
left a comment
There was a problem hiding this comment.
Thank you for writing up #1249 and following it with the PR. Keeping the rule in a pure kbGroups with tests is the right shape. A few things before it can land:
-
DCO. None of the 8 commits has a
Signed-off-byline, and CONTRIBUTING requires one on every commit.git rebase --signoff origin/dev && git push -ffixes it. -
Keyboard access. Before this change, every base in the chat scope menu could be reached with Tab. Now the submenu is portalled to the end of
<body>,onOpenAutoFocusis prevented (KbMenuList.tsx:124), and the Popover closes when focus moves outside it. So Enter on a group row opens the submenu, and the next Tab closes it again. The chat chip has no search to fall back on, so a keyboard user can no longer pickre-cinq/lorethere. Please:- Open the group with Enter, Space or ArrowRight and move focus to its first item.
- Close it with Escape or ArrowLeft and return focus to the row.
- Add
aria-haspopup="menu"andaria-expandedto the row. - Don't pass
active={open}to the row (:105), becauseRowturns it intoaria-current="true", which tells a screen reader the group is the current base.
DropdownMenuSubincomponents/ui/dropdown-menu.tsxalready does all of this. It also handles outside clicks across nested portals, so if it fits both hosts you could drop the[data-kb-submenu]exemption. -
Hover and click. Hovering opens the submenu and clicking toggles it (
:101,:112). On a touch screen a tap sends an emulated mouseenter and then a click, so the submenu opens and closes straight away. With a mouse, clicking a group row you're hovering on closes it on pointerdown and reopens it on click, so it flickers. Opening on hover only whenpointerType === "mouse", and having the click setopento true instead of toggling it, avoids both. The description says you haven't clicked through it yet, so please try it in a browser, including a touch viewport. -
Empty segments. The server accepts any 1–64 character name, so
/foo,foo/and/are all valid.kbGroupsturns them into a group with an empty name or an item with an empty label, which gives a blank row in the menus and a blank header in My knowledge bases; in the token picker,/fooshows up as plainfoo. Please group only when there is text on both sides of the first slash, trim the owner part sore-cinq /loreandre-cinq/floordon't become two identical-looking groups, and add a test for it.
One question: names that merely contain a slash (CI/CD, A/B tests) become a group with a single base. Is that intended for every user, or should a group need at least two bases?
Smaller points:
- The comment removed from
Chat.tsxexplained why the check mark has to go intrailing(an svg placed in the children drops to a second line).KbRowstill depends on that, so please move the comment there. - The chat scope rows now use the switcher's padding and font size, and the switcher now highlights the current base. If that's intended, a line in the description is enough.
- The My knowledge bases group header would work better as
<th scope="rowgroup" colSpan={6}>, so screen readers know which rows it labels.
The size is fine and there are no new UI strings. Thanks again.
d5ece27 to
a425a45
Compare
|
Thanks for the thorough review. Everything is in
On your question: a group now needs at least two bases. Smaller points: the check-mark comment now sits on One unrelated thing I noticed: in the switcher, Esc closes it but keeps the typed query for the next open. I haven't changed that here. |
Bumps Utopia from `re.5` to `0.1.0-re.6` (digest `sha256:ae962e7b…`). `re.6` is `re.5` plus the review fixes for deeplethe/utopia#1250 (knowledge bases grouped by owner): - a group needs two or more bases, so a lone `CI/CD` stays a plain row; names with an empty side of the slash aren't grouped, and owners are trimmed; - the keyboard works in both pickers (Enter, Space or → open; Esc or ← close; arrows move), with correct ARIA; - hover opens a group only with a mouse, and a click always opens it (no flicker, no tap open-then-close); - on screens under 640px a group expands in place instead of a side submenu that went off screen. It's web-only, with no migrations (still 0113). I booted the image on a fresh database before pushing (health ok, web 200), and the menus were clicked through in Chromium with Playwright, including a phone-sized touch screen (26/26 checks). 🤖 Generated with [Claude Code](https://claude.com/claude-code)
a425a45 to
3be9b1d
Compare
WaylandYang
left a comment
There was a problem hiding this comment.
Thank you for the quick and careful update. Everything from the review is addressed. I also appreciate the Playwright pass, and that you caught the narrow-screen problem while doing it. Requiring two bases before a group forms is a good answer to the CI/CD question.
Two small things left:
- Esc in the switcher.
onEscapeKeyDown={(e) => e.preventDefault()}(KbMenuList.tsx:234) cancels Escape even when focus isn't in the submenu. Radix only passes Escape to the topmost layer, which is the submenu. So if you hover a group in the top-bar switcher and press Esc while focus is still in the search box, nothing closes, and Esc used to close the switcher. Cancelling it only when focus is inside the submenu (the caseonSubmenuKeyalready handles) fixes it:onEscapeKeyDown={(e) => { if (submenu.current?.contains(document.activeElement)) e.preventDefault(); }}
- Size. The PR now adds 524 lines, a little over the 500 in CONTRIBUTING. A sentence in the description on why it stays as one PR is enough. Moving the My knowledge bases table to a follow-up would also work.
You're right about Esc keeping the switcher's query: onOpenChange={setOpen} skips dismiss(). That was there before this PR, so a separate small PR would be welcome. Thanks again.
… base switcher, the chat scope chip, the token picker and My knowledge bases Signed-off-by: Bogdan Szabo <bogdan@re-cinq.com>
3be9b1d to
05c7645
Compare
|
Thank you, and sorry this sat for two days.
I also squashed the branch into one signed commit; the old history had a long bulleted body and a stray I'll send the separate fix for Esc keeping the switcher's query once this one is in, to keep one PR open at a time. |
WaylandYang
left a comment
There was a problem hiding this comment.
Thank you, gedaiu! Esc now cancels only when focus is inside the submenu, so from the search box it closes as before, and inside the submenu it steps back to the group row. The size note in the description is clear, and keeping all the pickers on the same grouping in one PR makes sense, so no need to split out My knowledge bases. Merging.
Closes #1249
When two or more knowledge bases share the text before the first
/, they're grouped under it (re-cinq/lore,re-cinq/floor→re-cinq, shown asloreandfloor). Both sides of the slash must have text (both are trimmed), so/foo,foo/and/stay plain rows. A prefix only one base has (CI/CD,A/B tests) also stays a plain row with its full name. The rule is the purekbGroups/kbOptionsinweb/src/pages/kbGroups.ts.Top-bar switcher and the chat input's base chip share
KbMenuList. A group is one row,re-cinq ›, with the check mark when the current base is inside it. It opens a submenu to the right:aria-haspopup="menu"andaria-expanded, and noaria-current.re-cinq/lostill findsre-cinq/lore.I kept a Popover rather than
DropdownMenuSub. Sub needs a DropdownMenu root, and the switcher is a Popover with an autofocused search input that DropdownMenu's roving focus and typeahead would fight. The submenu is portalled, so the chat chip's outside-click handler ignores[data-kb-submenu].API token base picker:
SearchSelectOptiongains optionalgroupandshort. When the dropdown isn't filtered, it shows a heading wherever the group changes (withGroupHeadings), with the short names indented. Arrow keys skip the headings. While typing it's flat full names, and chips always show the full name.My knowledge bases: with the filter empty, each group gets a
<th scope="rowgroup">header row, and its bases show their short name (full name on hover).Side effects, both intended: the chat chip's rows now use the switcher's padding and font size, and the switcher highlights the current base the way the chat chip already did.
Tests:
kbGroups.test.ts(plain names, grouping, order and first-slash split, empty sides and trimming, a lone prefix stays plain, option shape),withGroupHeadings.test.ts,kbMenuKeys.test.ts(the key map). The web build and vitest pass.I checked it in Chromium with Playwright against a running server: hover, the keyboard path in both hosts, a click on a hovered group, picking from the submenu inside the chat chip, flat search results, and a Pixel 7 touch context where the group expands inline and is on screen. All 26 checks pass.
Size. This adds 527 lines, just over the 500 in CONTRIBUTING. It stays one PR because every picker uses the same grouping (
kbGroups,withGroupHeadings) and the same submenu (KbMenuList), and about a quarter of the additions are their tests. Shipping the grouping in some pickers and not others would make the base list look different depending on where it is opened. My knowledge bases is the one part that could move out (32 lines); I'm happy to split it into a follow-up if you prefer.🤖 Generated with Claude Code