mirror of
https://github.com/PR0M3TH3AN/SeedPass.git
synced 2026-11-06 12:52:04 +00:00
tui2: fix selection sync and sensitive panel UX glitches
This commit is contained in:
1 parent
367cad6a04
commit
26b9b6d31f
3 files changed
+70
-6
No files matched your search
@@ -528,3 +528,23 @@
|
||||
- `scripts/tui2_check_smoke.sh` => `tui2 --check smoke: ok`
|
||||
- `bash -n scripts/tui2_check_smoke.sh scripts/run_ci_tests.sh` => clean
|
||||
- `.venv/bin/pytest -q src/tests/test_tui_v2_textual_interactions.py src/tests/test_tui_v2_action_matrix.py src/tests/test_tui_v2_helpers.py src/tests/test_typer_cli.py` => `86 passed`.
|
||||
|
||||
## 2026-03-02 TUI v2 UX fixes: stale selection panel, clipped nav/help, and sensitive feedback clarity
|
||||
- Reproduced screenshot-reported UX issues in TUI v2:
|
||||
- Left panel could show stale `Selected: (none)` even while entry details were loaded.
|
||||
- Left panel command text could clip/wrap aggressively and hide actionable hints.
|
||||
- Sensitive reveal/QR confirmation paths could appear like no-op when only status line changed.
|
||||
- QR output could become visually distorted by line wrapping in the secret panel.
|
||||
- Fixes implemented in `src/seedpass/tui_v2/app.py`:
|
||||
- `_show_entry(...)` now refreshes the filters panel immediately so selected state is always in sync.
|
||||
- Added `on_list_view_highlighted(...)` to keep selected entry aligned with list highlight navigation.
|
||||
- Left filters pane now uses `height: 1fr` + `overflow: auto` to prevent clipping.
|
||||
- Secret panel now sets `text-wrap: nowrap` to preserve QR matrix geometry.
|
||||
- Footer top border removed to avoid visual crowding at the bottom status/footer region.
|
||||
- Filters/nav action copy trimmed to avoid forced line wraps in narrow terminals.
|
||||
- Confirmation-required reveal/QR actions now also write explicit instructions into `#secret-detail`.
|
||||
- Added regression coverage in `src/tests/test_tui_v2_textual_interactions.py`:
|
||||
- `test_tui2_textual_filters_panel_tracks_selected_entry` ensures left-panel selected summary updates after opening a different entry.
|
||||
- Validation:
|
||||
- `pytest -q src/tests/test_tui_v2_textual_interactions.py src/tests/test_tui_v2_action_matrix.py src/tests/test_tui_v2_helpers.py` -> `33 passed`.
|
||||
- `python scripts/ai_tui2_agent_test.py --scenario core --verbose` -> `[PASS] core`.
|
||||
@@ -138,7 +138,6 @@ def launch_tui2(
|
||||
Footer {
|
||||
background: #0b0f13;
|
||||
color: #97b8a6;
|
||||
border-top: solid #274533;
|
||||
}
|
||||
Input {
|
||||
background: #0d1114;
|
||||
@@ -181,6 +180,10 @@ def launch_tui2(
|
||||
#left { width: 34; border: solid #1a3024; padding: 1; background: #0d1114; }
|
||||
#center { width: 1fr; border: solid #1a3024; padding: 1; background: #0d1114; }
|
||||
#right { width: 1fr; border: solid #1a3024; padding: 1; background: #0d1114; }
|
||||
#filters {
|
||||
height: 1fr;
|
||||
overflow: auto;
|
||||
}
|
||||
#search { margin-bottom: 1; }
|
||||
#quick-jump { margin-bottom: 1; }
|
||||
#entry-list { height: 1fr; }
|
||||
@@ -203,6 +206,7 @@ def launch_tui2(
|
||||
border: solid #58f29d;
|
||||
padding: 1;
|
||||
margin-top: 1;
|
||||
text-wrap: nowrap;
|
||||
}
|
||||
#totp-board {
|
||||
height: 1fr;
|
||||
@@ -608,12 +612,11 @@ def launch_tui2(
|
||||
"- Ctrl+S save doc",
|
||||
"- Ctrl+P command palette",
|
||||
"- add-* create entries",
|
||||
"- add-seed/add-ssh/add-pgp/add-nostr/add-managed-account",
|
||||
"- notes-set/notes-clear, tag-add/tag-rm/tags-set/tags-clear",
|
||||
"- field-add/field-rm, set-field/clear-field, doc-export",
|
||||
"- tags/notes/fields via palette",
|
||||
"- docs: edit/save/export",
|
||||
"- 6 toggle dedicated 2FA board",
|
||||
"- profile/relay/sync + setting-* commands",
|
||||
"- checksum/db/totp export + parent seed backup commands",
|
||||
"- profile/relay/sync/settings",
|
||||
"- checksum/db/totp/seed backup",
|
||||
"- l cycle link relation",
|
||||
"- [ / ] select link",
|
||||
"- o open link target",
|
||||
@@ -764,6 +767,7 @@ def launch_tui2(
|
||||
"Sensitive data hidden. Use 'v' to reveal 🔑 or 'g' for QR ▦."
|
||||
)
|
||||
self._update_links_panel()
|
||||
self._update_filters_panel()
|
||||
self._set_status(f"Selected entry {entry_index}")
|
||||
except Exception as exc:
|
||||
self.query_one("#entry-detail", Static).update(
|
||||
@@ -1092,10 +1096,20 @@ def launch_tui2(
|
||||
and not confirm
|
||||
):
|
||||
if include_qr:
|
||||
self._set_secret_panel(
|
||||
"Sensitive QR hidden.\n"
|
||||
"Confirmation required for this action.\n"
|
||||
"Run: qr private confirm"
|
||||
)
|
||||
self._set_status(
|
||||
"Sensitive QR requires confirmation. Run: qr private confirm"
|
||||
)
|
||||
else:
|
||||
self._set_secret_panel(
|
||||
"Sensitive reveal hidden.\n"
|
||||
"Confirmation required for this action.\n"
|
||||
"Run: reveal confirm"
|
||||
)
|
||||
self._set_status(
|
||||
"Sensitive reveal requires confirmation. Run: reveal confirm"
|
||||
)
|
||||
@@ -3336,6 +3350,13 @@ def launch_tui2(
|
||||
if isinstance(item, EntryListItem):
|
||||
self._show_entry(item.entry_index)
|
||||
|
||||
def on_list_view_highlighted(self, event: ListView.Highlighted) -> None:
|
||||
if self.editing_document:
|
||||
return
|
||||
item = event.item
|
||||
if isinstance(item, EntryListItem):
|
||||
self._show_entry(item.entry_index)
|
||||
|
||||
app = SeedPassTuiV2()
|
||||
if callable(app_hook):
|
||||
app_hook(app)
|
||||
|
||||
@@ -712,6 +712,29 @@ async def test_tui2_textual_reveal_and_qr_flow() -> None:
|
||||
assert "TOTP #3 QR" in _widget_text(app, "#secret-detail")
|
||||
|
||||
|
||||
@pytest.mark.anyio
|
||||
async def test_tui2_textual_filters_panel_tracks_selected_entry() -> None:
|
||||
service = FakeEntryService(
|
||||
[
|
||||
{"id": 1, "kind": "password", "label": "Login 1", "length": 16},
|
||||
{"id": 2, "kind": "managed_account", "label": "Acct 2", "index": 2},
|
||||
]
|
||||
)
|
||||
app = _build_app(service)
|
||||
|
||||
async with app.run_test() as pilot:
|
||||
await pilot.pause()
|
||||
filters_text = _widget_text(app, "#filters")
|
||||
assert "Selected: #1" in filters_text
|
||||
assert "Login 1" in filters_text
|
||||
|
||||
app._run_palette_command("open 2")
|
||||
await pilot.pause()
|
||||
filters_text = _widget_text(app, "#filters")
|
||||
assert "Selected: #2" in filters_text
|
||||
assert "Acct 2" in filters_text
|
||||
|
||||
|
||||
@pytest.mark.anyio
|
||||
async def test_tui2_textual_sensitive_confirm_and_secret_mode_clipboard() -> None:
|
||||
service = FakeEntryService(
|
||||
|
||||
Reference in new issue
Block a user