summaryrefslogtreecommitdiff
path: root/docs/TUI-GUIDELINES.md
diff options
context:
space:
mode:
authorAnders Betts <anders.betts@gmail.com>2026-09-17 19:55:36 +0200
committerAnders Betts <anders.betts@gmail.com>2026-09-17 19:55:36 +0200
commit380195f7cd5e57acf2c1cf2bc41069e6b0b979ed (patch)
tree32a88fb22a7fbe8f1fd5c105156d1f928c93950d /docs/TUI-GUIDELINES.md
downloadbokf-0.1.0.tar.gz
bokf-0.1.0.zip
Initial commit: daemon, clients, docs, Docker deploy pipelinev0.1.0
Diffstat (limited to 'docs/TUI-GUIDELINES.md')
-rw-r--r--docs/TUI-GUIDELINES.md108
1 files changed, 108 insertions, 0 deletions
diff --git a/docs/TUI-GUIDELINES.md b/docs/TUI-GUIDELINES.md
new file mode 100644
index 0000000..180c72b
--- /dev/null
+++ b/docs/TUI-GUIDELINES.md
@@ -0,0 +1,108 @@
+# bokftui guidelines
+
+Rules for the ncurses client so every view behaves the same. When in doubt,
+copy the behaviour of the voucher list / voucher form; they are the reference
+implementations. Inspired by Midnight Commander, htop, mutt and calcurse.
+
+## Session start
+
+After login the org picker ("Välj organisation att representera") is always
+shown; the selected org is fixed for the session (`--org ID` bypasses it for
+scripts). The fiscal year is chosen from the dashboard and is changeable
+during the session.
+
+## Universal keys
+
+| Key | Meaning |
+|---|---|
+| `Ctrl+N` | Add: new verifikat (dashboard, voucher list/detail), new mall (Mallar), new fiscal year (year picker), open editor (IB), upload file (Underlag) |
+| `F5` | Refresh the view |
+| `Esc` / `q` | Back one level. At the dashboard it does nothing — Esc never exits the app |
+| `Ctrl+C` | Quit the application (closes the session). The only key that exits |
+| `1`–`9` | In lists: jump to that row. In menus: activate that item |
+| `g` | Live goto: "Gå till rad/nummer:" updates the selection as you type digits (backspace steps back); Enter closes the prompt without opening anything |
+| arrows, PgUp/PgDn, Home/End | Move/scroll; selection always stays visible |
+| `e` | Edit the shown object (IB, where applicable) |
+| `a` | Add/upload (Underlag) |
+| `c` | Correct (voucher detail) |
+| `Ctrl+F` | Attach a file (voucher form) / pick a file (Underlag) via the file browser |
+| `F7` | Clear the current row — only inside row editors (never "new") |
+| `F9` | Save/post the current form |
+
+Every screen prints its keys in the footer via `hints()`. If a key exists, the
+footer shows it; if the footer shows it, the key works.
+
+## Lists (`select_list`, `menu`)
+
+- Rows are numbered `NN. text`, right-aligned so 2- and 3-digit numbers line up.
+- Verifikation ids are shown concatenated as `series+number` (`V-8`, `A8`),
+ using the org's `default_series` (Inställningar) for new vouchers.
+- The last row may be an action (e.g. `+ Nytt verifikat (Ctrl+N)`); selecting it
+ runs the action instead of opening a detail view.
+- Selection memory: lists remember the selected row by identity (voucher id),
+ not index, across detail round-trips, refreshes and screen re-entry.
+- Digits move the highlight; only Enter activates. Menus are the exception:
+ digits activate directly (they are shortcuts).
+- Empty lists are never a dead end: show a message or keep the add-row.
+
+## Forms
+
+- Layout: bold header fields at the top, then a bold column header, then rows;
+ footer hints carry the keys.
+- Field navigation: `Tab` / `Shift-Tab` forward/back, arrows Up/Down between
+ rows. `Enter` advances in simple forms; it never saves unless the screen is
+ a one-line prompt.
+- The active field is drawn reverse-video and holds the hardware cursor at the
+ caret. The caret is a real position: ←/→/Home/End/Del work inside the field,
+ `Ctrl+U` clears it (see `field_edit`).
+- First keystroke in a freshly focused field replaces its content
+ (`field_fresh`), so prefilled values like dates can be typed over.
+- Date fields (`date_field_edit`, `date_prompt`) accept digits only and insert
+ the dashes themselves: type `20260315` and the field shows `2026-03-15`.
+ Backspace deletes a digit (with its separator), ←/→/Home/End move by digit,
+ and the caret renders like in any other field. Validation (`util_parse_iso_date`)
+ happens on F5/F9.
+- Derived values (account names, balances) are dim and non-editable.
+- Row tables: always exactly one empty trailing row; entering data appends a
+ new empty row; an empty row followed by another empty row collapses.
+ `F7` clears the selected row.
+- Validation: `F5` validates without writing and reports exactly what is wrong
+ (field, row number). Server `dry_run` is used where available.
+- Saving: `F9` writes, shows a confirmation message, and returns to the
+ previous view. `Esc` cancels without saving.
+- File browser (`file_browser`): starts in the org's `attachment_dir` (or
+ `$HOME`; a leading `~` is expanded to `$HOME`), `.. (uppåt)` is the first row, directories sort first with a
+ trailing `/`, hidden files are skipped. Enter enters a directory or picks a
+ file; `Esc` cancels. Selected files are uploaded immediately as unlinked
+ underlag and linked when the voucher is posted.
+
+## Messages
+
+- Info/confirmation: `message(title, ...)` box, dismissed with Enter.
+- Quitting: only `Ctrl+C` (from anywhere) or "Logga ut / avsluta" ends the
+ app; `Esc`/`q` only navigate. After `Ctrl+C` every screen unwinds, the
+ session is closed and the terminal restored.
+- Errors: `show_error(title, resp)` prints `CODE: message` from the server
+ error object; if the response is missing/empty it says
+ "Inget svar från servern (kör daemonen?)". Never render an empty error.
+- Irreversible actions (close year, lock, archive) ask first.
+
+## Layout and text
+
+- Screen frame: title top-left, dim status line under it
+ (`org | label start - end | role | user`), hints in the last line.
+- Columns are padded with `pad_field()` (UTF-8 display width) and truncated to
+ their column; amounts right-aligned via `kr_format()`; never pad with `%s`
+ widths directly on user text.
+- Selection = reverse video, headers = bold, derived data = dim.
+- All user-visible TUI text is Swedish; server messages are English.
+
+## Adding a view — checklist
+
+1. Data comes from public protocol commands only.
+2. Wrap the screen in `frame()`/`hints()`; return `Esc`/`q` to the parent.
+3. Use `menu()` or `select_list()` instead of writing a new loop; pass
+ `allow_new`/`allow_refresh` so the universal keys apply.
+4. Forms use the shared editor (`field_edit`) and the row-normalising helpers.
+5. Support `F5` if the data can change elsewhere.
+6. Update `PROTOCOL.md` §8 and this file if you add a new key or interaction.