Skip to content

LT-22693: Show a button per hotlink command on the active section - #1232

Open
thejambi wants to merge 4 commits into
mainfrom
LT-22693-per-command-hotlinks
Open

thejambi wants to merge 4 commits into
mainfrom
LT-22693-per-command-hotlinks

Conversation

@thejambi

@thejambi thejambi commented Nov 5, 2026 •

Copy link
Copy Markdown
Contributor

In the New UI detail view, a section that offers commands (a sense, Variants, Allomorphs, a Notebook record's Subrecords and others) now shows one small button per command at the right of its header line, such as "Insert Example" and "Insert Sense" on the sense being edited. The buttons appear on the section holding the current field, as WinForms shows its blue links only on the active section. A section that is empty or collapsed shows them all the time, since it has no field to click or Tab into. Each button is a Tab stop, reached with Shift+Tab from the section's first field.

Until now each such header carried a single "Field Options" link that opened a menu of the commands, so the commands could not be seen at a glance and every insert took two clicks.

The active Sense 2 shows Insert Example and Insert Sense; Sense 1 shows none
Headless control-level capture, not FLEx. Only the section holding the caret shows its buttons.

Reviewer notes

Why one section at a time. WinForms sets SummarySlice.Active from Slice.SetCurrentState, so its links show only on the current section. Showing buttons on every section was considered and rejected as visual noise on long entries. The rule is recorded as UX-9 in Docs/ux/README.md (provisional, superseding UX-2 and UX-3); user testing asking for buttons everywhere is the trigger to revisit it.

Deliberate rules.

  • The section a field belongs to is its nearest enclosing header with hotlinks (DetailVisibility.GetHotlinksHeaderIndex), passing over headers without any. The Avalonia Header kind also covers group headers and sequence banners, where passing over matches WinForms. WinForms stops at the first header="true" slice, so a nested header="true" section with no hotlinks of its own would differ; no shipped layout is known to have one.
  • The buttons are Tab stops, unlike WinForms' painted links. The section header and its "..." button are not Tab stops (LT-22688), and the main Insert menu lacks some of these commands (Insert Example, Insert Reversal Subentry), so the buttons are the keyboard's only way to them inside the view. The "Field Options" link they replace was a Tab stop for the same reason.
  • An empty or collapsed section shows its buttons at all times (DataTree.UpdateHotlinks, re-run after every visibility change and every change of section), since focus cannot enter it to bring them. An independent review after preflight found that an empty Variants or Subentries section had lost its keyboard route; fixed in 2d76c31.
  • Commands are fetched when a section's buttons are shown, not on every focus change within it, so a button is never rebuilt under the pointer. Enabled state is not refreshed while focus stays in the section; WinForms re-checks on a timer. Accepted as a known difference.
  • Lexicon hotlink menus are answered by the native command authorities, with live enabled state. Menus no authority owns yet (Notebook's) are listed from configuration, shown as enabled, and resolved on click through the hidden command adapter by label, with the same "not available" message WinForms shows. That listing includes submenu commands and is not filtered by display handlers; no shipped hotlinks menu is affected.
  • Buttons that do not fit are dropped from the right and leave the Tab order, rather than wrapping or clipping half a label. They stay in the UI Automation tree at zero size, so a screen reader could list them; hiding them needs a custom automation peer and is deferred.
  • The tint overrides Semi's ButtonDefault*Background keys on each enabled button. Semi draws a disabled button with its resting fill, so an unavailable command keeps the neutral grey. A Semi rename of those keys would drop the tint silently; Hotlinks_AreTinted_... would catch it.
  • Leaving an edited field autosaves and re-shows the view. Focus memory brings back the remembered button's section, then its focus and focus ring (0a53649, 4d6fcf1).
  • The two new strings, ksHotlinkCommandUnavailable and ksHotlinkCommandDisabled, copy the wording of DetailControlsStrings.ksCmdUnavailable and ksCmdDisabled, which are internal to DetailControls. They show in English until Crowdin translates them.
  • API: DataTree and DetailHostControl.ShowDetail gain an optional trailing hotlinkItems parameter. New theme tokens DataTree.HotlinkGap, HotlinkPadding and HotlinkCornerRadius. Automation ids: <row>.Hotlinks names the strip and <row>.Hotlinks.<n> each button; nothing in the repo automated the old single link.

The look. Five candidates were captured headlessly, all in the same place; the tinted buttons (3) were chosen. WinForms draws underlined links (1). Plain links (2) read as text, outlined chips (4) were less obviously primary, and a plus with a label (5) implies "add", which does not fit commands such as Show Concordance. Keeping the "Field Options" link beside the buttons was rejected, since its menu would repeat them on the same line.

Five candidate looks, each idle and with keyboard focus on the first button
Headless control-level captures of a throwaway restyling; only look 3 exists in the code.

Insert Example under the pointer is a deeper tint; Insert Sense, unavailable, is grey
Headless control-level capture. Pointer over the first button; the second command cannot run.

Tests. DetailHotlinkTests covers the section rule, buttons following focus between sections and staying put within one, one button per command with its enabled state, click, Shift+Tab then Enter, Tab into a section landing on its first field, empty and collapsed sections showing their buttons (Tab reaches them, and focusing one does not rebuild it), overflow leaving view and Tab order, tint, hover and unavailable states, and position on the header line. DetailFocusMemoryTests.ReshowWithNoRequest_KeepsFocusOnTheRememberedHotlink fails without 0a53649 and checks the focus ring. LexiconMenuExecutionTests runs Insert Sense from the button's own item and checks where the sense lands, plus the unowned-menu listing. Not covered: the Notebook click path through the hidden adapter (manual test 1). FwAvaloniaTests: 974 passed, 1 pre-existing skip. xWorksTests menu and command fixtures: 171 passed. Comment and token hygiene are clean.

Manual tests. Done, with New UI mode on:

  1. Notebook: the Subrecords section's "Insert Subrecord" button adds a subrecord.
  2. Lexicon Edit: type in a Gloss and press Shift+Tab; after the view refreshes, "Insert Sense" (the last button) has keyboard focus and its focus ring, and Enter adds a sense.

Not done: on an entry with no variants, Tab from the field before Variants onto "Insert Variant" (covered headlessly by AnEmptySection_ShowsItsHotlinks_WithoutFocus_AndTabReachesThem).

Out of scope. commandVisible="true" (the Words tool's wordform header, not yet on this view); refreshing enabled state while focus stays in a section; insert speed, since each insert recomposes the entry and rebuilds the view (a follow-up).

🤖 Generated with Claude Code


This change is Reviewable

Zachary Burnham and others added 2 commits November 4, 2026 22:51
In the New UI detail view, a section header with hotlinks shows one
small tinted button per command, right-aligned on the header's own
line, where WinForms shows one link per command. Until now the header
had a single "Field Options" link that opened a menu of those commands.

The buttons show only on the section that holds the focused field, and
stay put while focus moves within it. A command that cannot run is grey
on a neutral fill, and buttons that do not fit the width are left out.
They are Tab stops, reached with Shift+Tab from the section's first
field, since they are the keyboard's only way to some of these commands.

Lexicon commands are answered natively, with their live enabled state.
Commands in menus the detail view does not own yet, such as Notebook's,
are looked up on click; one that turns out unavailable shows the same
message the WinForms view shows.

The UX decision register records this as UX-9, superseding UX-2 and
UX-3.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Pressing Shift+Tab from an edited field onto a section's hotlink button
autosaves the edit, and the detail view is rebuilt. The new view showed
no buttons until focus entered a section, so the remembered button was
gone and the keyboard left the view.

Restoring focus now first shows the remembered button's section, then
focuses the same button.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@github-actions

github-actions Bot commented Nov 5, 2026 •

Copy link
Copy Markdown

NUnit Tests

    1 files  ± 0      1 suites  ±0   14m 13s ⏱️ -4s
7 078 tests +27  6 993 ✅ +27  85 💤 ±0  0 ❌ ±0 
7 087 runs  +27  7 002 ✅ +27  85 💤 ±0  0 ❌ ±0 

Results for commit 2d76c31. ± Comparison against base commit 9c931ec.

This pull request removes 4 and adds 31 tests. Note that renamed tests count towards both.
FwAvaloniaTests.DetailMenuRequestTests ‑ HotlinksStrip_Activating_RaisesTheSameHotlinksRequest_AsTheKebab
FwAvaloniaTests.DetailMenuRequestTests ‑ HotlinksStrip_AppearsForHotlinkHeader_IsAlwaysVisible_AndKeepsTheKebab
FwAvaloniaTests.DetailMenuRequestTests ‑ HotlinksStrip_IsAbsent_ForHeaderWithoutHotlinks
FwAvaloniaTests.DetailViewingParityTests ‑ SectionHeaderAndFieldOptionsText_TakeTheirOwnSizeAndColour
FwAvaloniaTests.DetailFocusMemoryTests ‑ ReshowWithNoRequest_KeepsFocusOnTheRememberedHotlink
FwAvaloniaTests.DetailHotlinkStripTests ‑ ACollapsedSection_ShowsItsHotlinks_UntilItIsExpanded
FwAvaloniaTests.DetailHotlinkStripTests ‑ AHeaderWhoseMenuOffersNoCommand_ShowsNoLinks
FwAvaloniaTests.DetailHotlinkStripTests ‑ AnEmptySection_ShowsItsHotlinks_WithoutFocus_AndTabReachesThem
FwAvaloniaTests.DetailHotlinkStripTests ‑ ClickingAHotlink_RunsItsCommand
FwAvaloniaTests.DetailHotlinkStripTests ‑ Hotlinks_AreReachedWithShiftTab_FromTheSectionsFirstField_AndRunWithEnter
FwAvaloniaTests.DetailHotlinkStripTests ‑ Hotlinks_AreShown_OnlyWhileFocusIsInTheirSection
FwAvaloniaTests.DetailHotlinkStripTests ‑ Hotlinks_AreTinted_AndDeepenTheTintUnderThePointer_ButNotWhenDisabled
FwAvaloniaTests.DetailHotlinkStripTests ‑ Hotlinks_FollowFocus_FromOneSectionToTheNext
FwAvaloniaTests.DetailHotlinkStripTests ‑ Hotlinks_RenderCleanly_OnTheActiveSensesLine
…

♻️ This comment has been updated with latest results.

@codecov-commenter

codecov-commenter commented Nov 5, 2026 •

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 83.73984% with 40 lines in your changes missing coverage. Please review.
✅ Project coverage is 40.54%. Comparing base (8afbeb5) to head (2d76c31).
⚠️ Report is 3 commits behind head on main.

Files with missing lines Patch % Lines
...xWorks/Avalonia/Hosting/RecordEditView.Avalonia.cs 37.83% 21 Missing and 2 partials ⚠️
Src/Common/FwAvalonia/Detail/DetailHotlinkStrip.cs 93.69% 2 Missing and 5 partials ⚠️
Src/Common/FwAvalonia/Detail/DataTree.cs 91.22% 1 Missing and 4 partials ⚠️
Src/Common/FwAvalonia/Detail/DetailVisibility.cs 83.33% 1 Missing and 2 partials ⚠️
Src/Common/FwAvalonia/Detail/DetailFocusMemory.cs 90.90% 0 Missing and 1 partial ⚠️
Src/Common/FwAvalonia/DetailHostControl.cs 50.00% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #1232      +/-   ##
==========================================
+ Coverage   40.50%   40.54%   +0.03%     
==========================================
  Files        1559     1560       +1     
  Lines      356085   356279     +194     
  Branches    41584    41626      +42     
==========================================
+ Hits       144243   144446     +203     
+ Misses     182531   182510      -21     
- Partials    29311    29323      +12     
Files with missing lines Coverage Δ
Src/Common/FwAvalonia/FwAvaloniaDensity.cs 97.29% <100.00%> (+0.28%) ⬆️
...AvaloniaTheme/Tokens/DataTree/DataTreeTokens.axaml 100.00% <100.00%> (ø)
Src/Common/FwAvalonia/Detail/DetailFocusMemory.cs 74.05% <90.90%> (+0.78%) ⬆️
Src/Common/FwAvalonia/DetailHostControl.cs 70.27% <50.00%> (+0.82%) ⬆️
Src/Common/FwAvalonia/Detail/DetailVisibility.cs 88.88% <83.33%> (-1.24%) ⬇️
Src/Common/FwAvalonia/Detail/DataTree.cs 92.48% <91.22%> (-0.63%) ⬇️
Src/Common/FwAvalonia/Detail/DetailHotlinkStrip.cs 93.69% <93.69%> (ø)
...xWorks/Avalonia/Hosting/RecordEditView.Avalonia.cs 62.05% <37.83%> (-1.26%) ⬇️

... and 15 files with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Zachary Burnham and others added 2 commits November 5, 2026 09:11
A hotlink button reached with Shift+Tab kept keyboard focus across the
autosave re-show but lost its focus ring, so focus looked gone even
though Enter still ran the command. Focus memory now records whether
the focused control showed its keyboard indicator and restores it the
same way. A text box is still focused plainly, so its caret is kept.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A section showing no field, because it is empty (an entry with no
variants yet) or collapsed, has no row to take focus, so its hotlink
buttons never appeared and its commands could not be reached from the
keyboard. Insert Reversal Subentry has no other route. Such a section
now shows its buttons at all times, as Tab stops, and they go back to
following focus once the section shows a field.

The hotlinks of a menu no native authority owns are noted as listing
submenu commands too, unfiltered by display handlers.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@thejambi
thejambi marked this pull request as ready for review November 5, 2026 19:22
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.

2 participants