Repository navigation
feat(webui): let the settings page rebind the composer's send and newline keys - #265
Merged
Merged
Conversation
…line keys The 快捷键 tab was a label with `disabled: true` behind it, and the composer decided in code what Enter meant. The tab is now a page: it lists the composer's keyboard actions, shows the key each one is bound to, and changes the binding. - The notation is one canonical string (`Control+Shift+Enter`) shared by the page and the composer, in `client/projection/common/shortcuts.ts`. - 发送消息 (built-in `Enter`) and 换行 (built-in `Shift+Enter`) are rebindable; 停止生成 is listed as 仅按钮,无快捷键, because `Escape` is already claimed by the menus it closes. - The binding is stored under `webui-shortcuts.v1`, a key of its own, and the composer reads it when a key is pressed, so a rebinding takes effect at once. - A capture refuses a bare modifier and a combination another action already holds, and names the action that holds it. - `resolveWebuiComposerEnterAction` is retired: the rule it encoded is the default configuration, expressed as the values the page shows. ADR 0026 records the decision.
The settings shortcut storage key reads like a credential to gitleaks' generic-api-key rule, so the release audit rejected this branch. It is a localStorage key name, not a secret, so allowlist it next to the other documented non-credentials.
The webui baseline's own gates are green again after #266, so this branch is brought up to it before its own checks run.
The shortcuts tab is enabled now, so the settings dialog renders differently: its nav row is no longer greyed out. The baseline was recorded on the gate's Linux environment, the same way the other nine baselines in this folder were.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What this changes
The settings page's 快捷键 tab was a label with
disabled: truebehind it, and the composer decided in code whatEntermeant. This PR makes the tab a real page:Enter) and 换行 (break the line, built-inShift+Enter) are rebindable.Escapeis already claimed by the mention menu, the slash menu, the permission menu, goal mode and plan mode, so a shortcut for it would fight them. NoEscbinding was added, per the task book.webui-shortcuts.v1— a key of its own, so it cannot collide with feat(webui): let the settings page switch between Chinese and English #250'smavis-locale.The built-in behaviour is unchanged: with nothing stored,
Entersends andShift+Enterbreaks the line.How it is put together
packages/webui/src/client/projection/common/shortcuts.ts— one canonical string (Control+Shift+Enter) that the page stores, shows and the composer matches againstpackages/webui/src/client/features/settings/projection/settings-shortcuts.tspackages/webui/src/client/features/settings/ui/ShortcutsSettings.tsxresolveWebuiComposerShortcutActioninpackages/webui/src/client/features/composer/projection/composer-state.tsresolveWebuiComposerEnterActionis retired: the rule it encoded is the default configuration, expressed as the values the page shows. The three-valued answer (submit/newline/ignore) is what lets a press that names no binding fall through to the browser's own behaviour — which is how a key the user unbound stops doing the composer's business.ADR
packages/webui/docs/adr/0026-the-composer-follows-the-bindings-the-settings-page-stores.mdrecords the decision.Evidence
pnpm --filter @mavis/webui typecheck:client/pnpm typecheck:webuipnpm exec vitest run … settings-shortcuts.test.ts composer-intent.test.ts settings-modal.test.tsx browser-settings-page.test.tsxpnpm exec playwright test … settings-shortcuts.spec.mjspnpm exec playwright test packages/webui/test/browsernode-ptycannot spawn, and the Linux-only visual baselines)pnpm exec playwright test … settings-account-tab.spec.mjs settings-theme.spec.mjs composer.spec.mjspnpm build:webuinode scripts/source-inventory.mjs --write+pnpm check:sourcepnpm check:webui-dependencyThe browser suite covers the six acceptance points one by one: the tab opens and lists the actions with their current keys; a captured combination becomes the binding the page shows; the binding survives closing the settings and coming back; the binding survives a reload; the composer sends on the new key and no longer on the old one (the draft keeps the text and the line break, and nothing was sent for it); 恢复默认 returns to
Enterand the behaviour follows it back. A seventh case covers a newline bound to a key the browser does not break the line on (Control+J), which the composer breaks itself.Negative controls (mutation, then restore)
Control+J"webui-shortcuts.v1Control+JnewlineBoth mutations were reverted and the suite was re-run green.
CI
changesverify (windows-latest, 24)verify (ubuntu-latest, 24)fullprofile, including the real-browser suiteverify (macos-latest, 24)platformprofileverificationsuccesssource-history-artifact(Release audit)no leaks foundon all three gitleaks stepsperformancedocsEvery green run is on this branch's final head
9daf9cf8:Source verification,
Release audit,
Performance.
The baseline's own gates were red, and are fixed separately
This branch inherited a baseline that failed on its own. Two pull requests, both
merged into
webuibefore this one, carry the repair:check:webui-dependencyreached fordocumentdirectly(
WorkspacePanels.tsx:528and:573); the wait moved behind the browserplatform seam. The same pull request brought the stale expectations back in
line with the terminal and browser work (six test files, the fixture's
terminal bridge, and one recorded Linux screenshot).
provider had already replaced, and the service refused it.
Neither pull request touches a file this pull request changes, so the diff here
is still only the shortcut page.
The gitleaks failure was mine, and it is fixed
The first run of the Release audit failed with
leaks found: 1. It was thisbranch's commit, not somebody else's:
webui-shortcuts.v1is a localStorage key name, but it is high-entropy enough(
generic-api-keywants entropy > 3.5; this one is 3.84) to read as acredential to gitleaks'
generic-api-keyrule. The fix is the one thisrepository already uses for exactly this class of false positive: a documented
entry in
.gitleaks.toml, next to the other "not a credential" entries:The release audit scans the history of every branch, so the entry has to be on
the baseline as well as here — which is why #266 carries the same entry. A
re-run of the official
gitleaks v8.24.3(the version the release audit pins)against this branch's history and against the whole
originref set:no leaks found.Pre-existing failures on the baseline (not this PR)
pnpm test:webuion this branch, locally: 6 failed / 3340 passed / 34skipped. Every failure is
No Chrome executable was found(
browser-core-agent-actions×5,agent-transcript×1): this machine has nosystem Chrome, and the CI runners do. The same suite is green on the runners.
Two assertions that said 快捷键 was still disabled were updated, because it no
longer is:
packages/webui/test/unit/settings-modal.test.tsxandpackages/webui/test/browser/settings-account-tab.spec.mjs.Scope, and the boundary with #250
packages/webuiis touched, no new dependency, no i18n framework. The one file outsidepackages/webuiis.gitleaks.toml, which only gains an allowlist entry (above).settings-view.ts(the tab table, onedisabled: trueremoved) andSettingsModal.public.tsx(the page mount, the state and the storage write) — and both changes are mechanical to reconcile.The one visual baseline this PR changes
settings-dialog-linux.pngis re-recorded here. The shortcuts tab is enabled,so the settings dialog's nav renders that row in the active colour instead of
the greyed-out one — the picture changes, the code does not.
The recording was done on Linux, on the gate's own image, the same way the
other nine baselines in that folder were. Re-recording all ten produced nine
files that are byte-identical to the ones already in the repository and one
that is not, so the difference is this PR's change and not a drifted
environment.
The launcher's baseline also changed, but that was #266's doing, and it landed
on the baseline before this branch was updated with it.
Not verified here
*-linux.pngonly), so the re-recorded picture was verified on the gate's Linux environment, not locally.