Repository navigation
ux: consistent keys, confirmations, input, status and connectivity from the repository review - #606
Merged
Merged
Conversation
…uristic (#577) Every main-page panel's status_message (communities, identity, vetting, inbox, relationships, credentials, settings, capabilities) and the device access view's message are now a typed Status { severity, text }. The producer that knows whether its operation worked sets the severity; the renderer colours by severity only. The string-prefix/marker heuristic in components/status.rs is deleted. Severity and Status move from main_page/repos.rs to main_page/status.rs (re-exported where they were) so rooms, elections and repos share one type and one style table (severity_style). Actions that carried a status string (VettingAction::Status, SettingsAction::ClipboardCopied) carry a Status. Signed-off-by: Glenn Gore <glenn.g@affinidi.com>
#579) Destructive and outward-facing actions are armed by their key and committed by y alone; Enter, the key that opened the view, now cancels like any other key. Shared in ui/pages/main/confirm.rs (is_yes, KEYS, prompt) and used by every prompt, which now reads 'y: confirm · any other key: cancel'. Changed to y-only: community delete/leave/withdraw, device-grant revoke, inbox dismiss/clear-all, relationship and credential remove, invitation credential delete/purge, agent-name remove, persona confirmations, capability toggle, vetting abandon/delete-ticket/withdraw/decline. Now confirmed (previously sent on one key): Inbox reject (sent to the peer), Settings remove passphrase, Communities m (issue VMC) and R (renew). Typed-word confirmation stays for WIPE and RESET. Signed-off-by: Glenn Gore <glenn.g@affinidi.com>
…eedback (#580) Every main-page view now builds its keys as a list of Bindings (ui/pages/main/keymap.rs) and draws them with keymap::footer, which also advertises them for the frame. The ? overlay lists exactly the advertised keys of the focused view plus the global ones; the footer row and the Help / Status shortcut list are generated from the same global table. - one label vocabulary (Enter, Esc, Tab, Shift+Tab, arrows, Space, Del, Ctrl+X) parsed into the key codes it names, so a label cannot name a key it does not match; one format 'key: does · key: does' - a key a view does not take shows 'x does nothing here — ? lists this panel's keys' in the footer row instead of vanishing; a text field keeps ←/→/Tab rather than switching panels; Ctrl/Alt chords reach a view only where it lists them - consistent keys: archive is x (VTA invitations too), show archived is v (was i on the VTA panel), refresh is r (was Tab on the VTA panel); Communities joins with n, and j/k move there as in rooms, elections and the menu - TSP Relationships gets a key handler (↑/↓, Esc) - silent swallows removed (inbox a, credential d, VTA u, persona d, identity read-only overlays and pickers); local-face delete, make reusable and forget-contact now confirm with y only - keymap_tests checks, per view, that the footer lists exactly the keys the handler takes (inbox, relationships, credentials, VTA, communities, settings, help, TSP, identity tabs, capabilities) Signed-off-by: Glenn Gore <glenn.g@affinidi.com>
Every string field on the main page (relationship request, alias and witness; credential reason; settings name, export/import path and the typed WIPE/RESET words; vetting text fields; the device-grant form; the context-delete word; the repos forms; ballot text answers) is listed once in ui/pages/main/text_input.rs and edited there through tui_input, the editor the setup and join screens use: - a visible cursor; ←/→, Ctrl+←/→, Home/End move within the field instead of switching panels; Backspace/Del delete either side; Ctrl+A/E/U/W/K edit; no Ctrl or Alt chord types its letter (a chord the view lists as its own, such as Ctrl+A 'add owner', stays the view's) - a paste is inserted at the cursor in every field that takes one (it was appended on the main page); the typed confirmation words take no paste - the masked passphrase length counts characters, not bytes - ballot text answers get a BallotText action so they edit like any field - the append-only edit_text helper and the per-panel paste code go Tests: editor semantics (insert at cursor, arrows, deletes, chords, non-ASCII), cursor drawing, ← then type, paste at Home, Ctrl+U/Ctrl+T. Signed-off-by: Glenn Gore <glenn.g@affinidi.com>
- the activity log takes 4 rows instead of 8 below 32 rows, so all twelve menu items fit at 24 rows; the menu also scrolls to keep the selection on screen on anything shorter - the menu is at least 23 columns wide (its longest item and a badge), so 'My Relationships', 'TSP Relationships', 'My Credentials' and 'Help / Status' are no longer cut at 80 columns - the footer row is built from the global key table with F10 quit and ? first, and keeps only whole hints that fit - setup step 1 (Run the PNM command): the actions-and-commands body scrolls with ↑/↓ and PgUp/PgDn, the footer says so when it can, and the copy result takes the footer row instead of the end of the body - tests: 80x24 TestBackend renders of the main page (every menu item and 'F10: quit' visible) and setup step 1 (scrolls to the F4 command; copy result in the footer row) Signed-off-by: Glenn Gore <glenn.g@affinidi.com>
…g results (#584) - the Inbox badge counts what was sent to the user (requests, issued credentials, information, vetting), not their own outbound requests or pings; Communities shows its actions-required count and Vetting the requests on the desk, as badges of their own - activity-log entries carry a severity: errors (log_error) and warnings are drawn in their colour with a glyph (✗ / !), routine lines stay dim - a pong is reported in the Relationships panel ('Pong from X (N ms) — they are reachable.'), not only in the log; a ping with no pong in 30 s says so there ('No reply to the ping after 30 s …'), is logged as a warning, and its outbound task is expired so it does not sit in the Inbox - tests: badge counts inbound only; log keeps each entry's severity Signed-off-by: Glenn Gore <glenn.g@affinidi.com>
- MediatorStatus::Failed carries a ConnectionFailure { reason, class }
with the typed openvtc_core::errors::ErrorClass; ReconnectOutcome::Failed
carries the class too (class_of the listener error; a listener that never
connects is a Timeout)
- the header shows the class ('✗ mediator unreachable', 'mediator refused
us', 'mediator incompatible', 'mediator not answering', …) and 'see
Help' instead of 17 characters of error text; Help / Status shows the
class, the full reason and the class's remedy, and r there reconnects
- SettingsAction::ReconnectMediator is live: Enter on the Settings mediator
row ('[Enter to reconnect]') and r on Help / Status; its
#[allow(dead_code)] is gone
- 'Messaging unavailable — cannot X right now.' now names the class and
the remedy, and points at the retry
- the identity pane's agent errors are typed (AgentError { text, class }):
the holder-grant hint is offered only for a refusal (AuthRejected /
Refused) whose text names the holder credential, never for an
unreachable agent; other failures show their class's remedy
- tests: header per class, Help / Status cause + r, mediator row Enter
Signed-off-by: Glenn Gore <glenn.g@affinidi.com>
…#588) - Esc goes back a page on every setup page that has one (setup_flow::navigation::previous_page), instead of clearing the field: ConfigImport and VTA DID go back to the start, step 1 (PNM command) to the VTA DID, the context-occupied warning to step 1, the unlock-code pages to the unlock-code choice, the token pages to the page before. Back stops at the VTA once its one-time grant is spent. Step 2 keeps its own back (it carries the reason for step 1's banner). Choice pages and the no-code warning say '[ESC] to go back'; the input pages' '[ESC] to clear input' now reads '[ESC] to go back'. - going back keeps what was typed and the setup DID: the ephemeral setup key is minted once per run, so a PNM grant already made for it still applies after going back and forward (it is still new each relaunch: it is never written to disk) - one progress indicator: the header's 'Section n/4'; the boxes are named ('Run the PNM command', 'Connect to the VTA', 'Enter unlock code', …) instead of carrying their own 'Step x/y' counters that disagreed with it - test: Esc walks back from step 1 to the start keeping the context id Signed-off-by: Glenn Gore <glenn.g@affinidi.com>
- British spelling in the user-visible strings that were American:
unauthorised (unlock-code page), recognised (token scan),
'Initialising:' (header, Inbox, Help / Status), 'not initialised',
'Finalised'. Protocol and SDK text keeps its own spelling (the VTA's
'is not authorized on' is matched verbatim; theme 'color' keys and
'organization' JSON are formats).
- the profile's secret is the 'unlock code' everywhere: Settings →
Protection ('Set an unlock code', 'Remove the unlock code (keyring
only)', 'Unlock code:'), its log lines, and the CLI unlock prompt and
--unlock-code-file errors. An export file's 'passphrase' is a different
secret and keeps its name.
- README gains a Glossary (persona, community/VTC, unlock code, Inbox,
Help / Status); CONTRIBUTING states the wording convention (British
spelling, one name per concept, one key vocabulary via keymap::Binding).
- Persisted identifiers and theme ids are unchanged.
Signed-off-by: Glenn Gore <glenn.g@affinidi.com>
Setup's text fields replaced their whole content with a paste while the main page appended it; both now insert at the cursor. Signed-off-by: Glenn Gore <glenn.g@affinidi.com>
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.
One pass over the UX findings from the repository review: one confirmation rule, one key table per view (drawn as the footer, listed by a new
?overlay, checked against the handler by tests), one text-input behaviour, typed status severity, a layout that fits 80x24, honest notifications, classified connectivity failures with a retry, a wizard you can step back through, and consistent wording.Commits are split by concern and each builds and passes the tests on its own:
ux(status)— bug(ui): many failure messages render in success green — status colour is decided by a string-prefix heuristic #577ux(confirm)— ux(confirm): three different confirmation patterns, Enter commits destructive actions, and some outward-facing actions have no confirmation #579ux(keys)— ux(keys): inconsistent key map across panels, no?help overlay, and a focusable panel with no key handler #580ux(input)— ux(input): main-page text fields have no cursor, arrow keys steal focus, Ctrl-combos insert letters; paste and Esc behave differently per screen #578 (+ a follow-up commit for setup paste)ux(layout)— ux(layout): at 80x24 the Quit menu item, the<F10> quithint and the setup PNM commands are clipped #576ux(notifications)— ux(notifications): the Inbox badge counts the user's own outbound tasks, other panels have no badge, and a ping never reports its result #584ux(connectivity)— ux(connectivity): the header shows 17 characters of failure cause, cannot tell unreachable from rejected, and offers no retry #585ux(setup)— ux(setup): the setup wizard has no way back, and Esc clears the field instead of going back #588docs(ui)— docs(ui): mixed British/American spelling in UI strings and inconsistent names for the same concept #554docs(changelog)Per issue
#577 — typed status (rest of the issue)
status_message(communities, identity, vetting, inbox, relationships, credentials, settings, capabilities) and the device-accessmessageare a typedStatus { severity, text }.Severity/Statusmoved tostate_handler/main_page/status.rs(re-exported where repos/rooms/elections had them) with one style table,components::status::severity_style.Warning, in-flight sends areProgress, refusals/failuresError).VettingAction::StatusandSettingsAction::ClipboardCopiedcarry aStatus.FAILURE_MARKERS/status_style) is deleted; nothing decides colour from text any more. Forms'errorfields render throughpush_error(the field is named for its severity).#579 — confirmations
ui/pages/main/confirm.rs:is_yes(plainyonly),KEYS("y: confirm · any other key: cancel") andprompt(); every prompt uses them.yor Enter: community delete/leave/cancel-join, device-access revoke, Inbox dismiss/clear-all, relationship and credential remove, invitation credential delete/purge, agent-name remove, all persona confirmations, capability toggle, vetting abandon / delete-ticket / withdraw / decline (Enter on the decline note now just leaves the note), local-face delete, make-reusable, forget-contact.rreject (sent to the peer), Settings "Remove the unlock code", Communitiesm(issue VMC) andR(renew).#580 — key map and
?ui/pages/main/keymap.rs: a view declares its keys asBindings (k("d/Del", "delete"));keymap::footerdraws them in one format (key: does · …, wrapping rather than clipping) and advertises them for the frame. Labels use one vocabulary parsed into theKeyCodes they name, so a label cannot disagree with the key matched.?opens an overlay listing exactly the focused view's advertised keys plus the global table (any key closes it); the footer row and Help / Status's shortcut list are generated from the same global table.x(wasr), show-archived isv(wasi), refresh isr(was Tab); Communities joins withn(wasj) andj/kmove there and in the menu. TSP Relationships gets a handler (↑/↓, Esc).a, credentiald, VTAu, personad, identity read-only views and pickers).keymap_tests.rsasserts, for each view, that the footer lists exactly the keys the handler takes (inbox list/detail, relationships list/detail/alias/new-request ×4 fields, credentials list/detail ×2, VTA ×4, communities ×4, settings ×2, Help/Status, TSP, all six identity tabs, capabilities loading/failed).#578 — text input
ui/pages/main/text_input.rslists every main-page string field once and edits it throughtui_input(as setup/join do): visible cursor; ←/→, Ctrl+←/→, Home/End move inside the field; Backspace/Del; Ctrl+A/E/U/W/K edit; no chord types its letter (a chord the view lists, e.g. Ctrl+A "add owner", stays the view's).BallotTextaction so they edit like any field.edit_textand the per-panel paste code are gone.#576 — 80x24
F10: quitand?: keysand keeps only whole hints.#584 — notifications
#585 — connectivity
MediatorStatus::Failed(ConnectionFailure { reason, class: ErrorClass }); core'sReconnectOutcome::Failed { reason, class }(class_ofthe listener error; a listener that never connects isTimeout).ErrorClass::remedy(), andrreconnects. Enter on the Settings mediator row reconnects.SettingsAction::ReconnectMediatorno longer#[allow(dead_code)].AgentError { text, class }); the holder-grant command is offered only for a refusal whose text names it — never for an unreachable agent (the old string-only decision).#588 — setup
navigation::previous_page); back stops at the VTA once its one-time grant is spent; step 2 keeps its own back (it carries step 1's banner reason). Choice pages and the no-code warning say "[ESC] to go back".#554 — wording
--unlock-code-fileerrors (export passphrases keep their name).User-visible behaviour changes
ydoes, and any other key (Enter included) cancels.yconfirmations before: rejecting an Inbox request, removing the unlock code in Settings, issuing a VMC (m) and renewing a membership (R).y; Enter on the decline note moves off the note.y(were Enter).?opens a key overlay on the main page (outside text fields).Enter, not⏎).x(wasr), show archived isv(wasi), refresh isr(was Tab).n(wasj);j/kmove the selection; same in the menu.F10: quit · ?: keys.rto reconnect; Enter on Settings' mediator row reconnects.Tests added
ydoes; Inbox reject arms; remove-unlock-code arms.?help overlay, and a focusable panel with no key handler #580;?lists the focused view's keys and the global ones and any key closes it; an unused key gives feedback; label parsing; footer wrapping.F10: quit/?: keys; short terminal scrolls to Quit; setup step 1 at 80x24 scrolls to the F4 command and shows the copy result in the footer.rreconnects; Settings mediator row reconnects.Verified locally (rustc 1.100):
cargo fmt --all --check;cargo clippy --workspace --all-targets --locked -- -D warningsand with--no-default-features;cargo clippy -p openvtc --all-targets --features dev-overrides -- -D warnings;cargo test --workspace --lockedand with--no-default-features;RUSTDOCFLAGS='-D warnings' cargo doc --workspace --no-deps;cargo machete.Not done here (follow-ups)
?help overlay, and a focusable panel with no key handler #580: exactness tests do not yet cover the vetting forms/desk, repos, rooms, elections and the overlays; their footers are converted to the key table but vetting forms take Tab/arrows uniformly. Repos' "this machine" keys (c e E s S u w f F R) are still taken where they do not apply (the handler answers with a status saying why) and only the applicable ones are listed.j/kare movement in lists that do not use them as verbs; identity (kwho it knows you as) and the vetting desk (kget tokens) keep theirs. Repos archive staysA(it archives the forge repository,xis revoke there).tui_input(cursor movement works) but still draw the caret at the end of the field.Closes #576
Closes #577
Closes #579
Closes #584
Closes #585
Closes #588
Part of #578
Part of #580
Part of #554
Pre-merge checklist (vti-stack-development-guide §9)