From 1a0fd166a85cd0f7a56ca92971c52d0014ee656d Mon Sep 17 00:00:00 2001 From: Amolith Date: Sat, 28 Mar 2026 17:53:25 -0600 Subject: [PATCH] Add Gherkin feature files for interactive TUI session Specify the interactive session behaviour across four feature files: - session_shell: terminal session lifecycle, theme detection, colour palette, help bar, breadcrumb, screen titles, and Ctrl+C handling - navigation: Esc back-navigation, state retention, screen skipping when values are already resolved, and CLI-provided value handling - restore_flow: restore-specific screens for snapshot selection, file picking, target directory, and overwrite behaviour - command_preview: confirmation screen, command execution, and --show-command integration Add bubbletint/v2 dependency for terminal colour palette support. --- features/command_preview.feature | 34 +++++++++++++ features/navigation.feature | 68 ++++++++++++++++++++++++++ features/restore_flow.feature | 84 ++++++++++++++++++++++++++++++++ features/session_shell.feature | 82 +++++++++++++++++++++++++++++++ go.mod | 1 + go.sum | 2 + 6 files changed, 271 insertions(+) create mode 100644 features/command_preview.feature create mode 100644 features/navigation.feature create mode 100644 features/restore_flow.feature create mode 100644 features/session_shell.feature diff --git a/features/command_preview.feature b/features/command_preview.feature new file mode 100644 index 0000000000000000000000000000000000000000..7fece29c539dd832a14a5ce95b95bd45a15e65ff --- /dev/null +++ b/features/command_preview.feature @@ -0,0 +1,34 @@ +Feature: Command preview and execution + + Before handing off to restic, the session shows the resolved + command and asks the user to confirm. This gives the user a + chance to review what will run and go back to correct mistakes. + + Rule: The confirmation screen shows the resolved restic command + + Scenario: Reviewing the command before execution + Given the user has completed all required screens + When the confirmation screen is shown + Then it displays the resolved restic command line + And it displays any environment variables that will be set + And the user can confirm to proceed + + Scenario: Confirming execution + Given the confirmation screen is showing + When the user confirms + Then restic is executed with the resolved configuration + + Scenario: Going back from the confirmation screen + Given the confirmation screen is showing + When the user presses Esc + Then they return to the last visible screen of the flow + And their previous answers are preserved + + Rule: --show-command prints the command and exits without executing + + Scenario: --show-command in interactive mode + Given the user launched keld interactively with --show-command + When the confirmation screen would normally appear + Then the resolved command is printed as text + And the output format matches non-interactive --show-command + And the session exits without executing restic diff --git a/features/navigation.feature b/features/navigation.feature new file mode 100644 index 0000000000000000000000000000000000000000..24b7163553ca3e387913dd039f9e5b89b0d0dad6 --- /dev/null +++ b/features/navigation.feature @@ -0,0 +1,68 @@ +Feature: Navigation and state retention + + Users navigate forward through screens by making selections, and + backward with Esc. The session remembers previous answers so users + can review and revise without re-entering everything. + + Rule: Esc navigates back one visible screen at a time + + Scenario: Going back from a command-specific screen + Given the user is on the first screen of a command flow + When they press Esc + Then the preset selection screen is shown + And their previous preset choice is preserved + + Scenario: Going back from the preset selection + Given the user is on the preset selection screen + When they press Esc + Then the command menu is shown + And their previous command selection is highlighted + + Scenario: Going back step by step through a multi-screen flow + Given the user has progressed through several screens + When they press Esc repeatedly + Then they step back through each previously-visited screen + And each screen shows their earlier answer + + Scenario: Esc on the command menu exits the session + Given the user is on the command menu + When they press Esc + Then the session exits without executing restic + + Rule: Screens are skipped when the needed value is already resolved + + Scenario: Command provided on the command line + Given the user invokes keld with a command argument + Then the command menu is not shown + And the session begins at the preset selection + + Scenario: Preset provided on the command line + Given the user invokes keld with --preset + Then the preset selection screen is not shown + + Scenario: No presets defined in configuration + Given the configuration defines no presets + Then the preset selection screen is not shown + + Scenario: Exactly one preset defined + Given the configuration defines exactly one preset + Then that preset is selected automatically + And the preset selection screen is not shown + + Scenario: All required values already resolved + Given the command, preset, and all command-specific values are already provided + Then the session skips directly to the confirmation screen + + Rule: Skipped screens are also skipped during back navigation + + Scenario: Navigating back past a skipped screen + Given a screen was skipped because its value was already resolved + When the user navigates back from the screen after it + Then they land on the screen before the skipped one + + Rule: CLI-provided values are always skipped regardless of navigation + + Scenario: CLI-provided values cannot be reached via back navigation + Given the user provided a value on the command line + Then that value's screen is never shown + And back navigation passes over it in both directions diff --git a/features/restore_flow.feature b/features/restore_flow.feature new file mode 100644 index 0000000000000000000000000000000000000000..3bbad01fe9e8d9a7213590e2d8901b9b40848cc9 --- /dev/null +++ b/features/restore_flow.feature @@ -0,0 +1,84 @@ +Feature: Restore interactive flow + + The restore flow guides the user through selecting a snapshot, + optionally choosing specific files, setting a target directory, + and choosing overwrite behaviour. Each step is skipped when the + resolved configuration already provides the needed value. + + Background: + Given the user has selected the "restore" command + + Rule: A snapshot is selected from the repository or entered manually + + Scenario: Snapshots loaded from the repository + Given the repository is accessible + When the snapshot selection screen is reached + Then a spinner is shown while snapshots are fetched + And the fetched snapshots are presented in a filterable list + + Scenario: Snapshot listing fails + Given the repository is not accessible + When the snapshot selection screen is reached + Then an error notice is displayed + And the user is offered a text input for manual snapshot ID entry + + Scenario: No snapshots in the repository + Given the repository contains no snapshots + When the snapshot selection screen is reached + Then a notice indicates the repository is empty + And the user is offered a text input for manual snapshot ID entry + + Scenario: Snapshot ID already provided + Given a snapshot ID is already resolved + Then the snapshot selection screen is not shown + + Rule: The user may select specific files to restore from the snapshot + + Scenario: File listing loaded from the snapshot + Given a snapshot has been selected + When the file selection screen is reached + Then a spinner is shown while the file listing is fetched + And a file picker is presented for the snapshot's contents + + Scenario: Full restore when all files are selected + Given the file picker is showing + When the user confirms with all files selected + Then no include paths are added to the restore command + + Scenario: Partial restore when specific files are selected + Given the file picker is showing + When the user selects specific files and confirms + Then the selected paths are added as include paths + + Scenario: File listing fetch fails + Given a snapshot has been selected + When the file listing cannot be fetched + Then a notice is displayed + And the file picker is skipped + And the flow proceeds with a full restore + + Scenario: File selection already configured + Given include paths are already resolved + Then the file selection screen is not shown + + Rule: A target directory is specified for the restored files + + Scenario: Target directory prompted + Given no target directory is resolved + When the target directory screen is reached + Then a text input prompts for the restore destination + + Scenario: Target directory already configured + Given a target directory is already resolved + Then the target directory screen is not shown + + Rule: The overwrite behaviour is chosen before restoring + + Scenario: Overwrite behaviour prompted + Given no overwrite behaviour is resolved + When the overwrite screen is reached + Then a selector presents the available overwrite options + + Scenario: Overwrite behaviour already configured + Given an overwrite behaviour is already resolved + Then the overwrite screen is not shown diff --git a/features/session_shell.feature b/features/session_shell.feature new file mode 100644 index 0000000000000000000000000000000000000000..c060453356e9360a892db9ba5618486ddd52a7d4 --- /dev/null +++ b/features/session_shell.feature @@ -0,0 +1,82 @@ +Feature: Interactive session shell + + The interactive session provides a single, cohesive terminal interface + for all of keld's interactive flows. It manages the visual frame — + theme, help bar, breadcrumb, and cancellation — so that individual + screens do not have to. + + Rule: The interface runs as a single continuous terminal session + + Scenario: Transitioning between screens + Given the user launches keld interactively + When they progress from one screen to the next + Then the interface transitions directly without returning to the shell + + Rule: The terminal background is detected once and determines the colour palette + + Scenario: Dark terminal + Given the terminal has a dark background + When the session starts + Then the dark colour palette is used for all screens + + Scenario: Light terminal + Given the terminal has a light background + When the session starts + Then the light colour palette is used for all screens + + Scenario: Background detection is unavailable + Given the terminal background cannot be detected + When the session starts + Then the dark colour palette is used as a default + + Rule: Colour is used intentionally to highlight actionable elements + + Scenario: Body text uses the terminal's default foreground + Given any screen in the session + Then descriptive and body text is not styled with a custom colour + + Scenario: No text is rendered in a muted or dim style + Given any screen in the session + Then all text is rendered at full brightness + + Rule: A help bar at the bottom shows available key bindings for the current screen + + Scenario: Help bar reflects the current screen + Given the user is on any screen + Then the help bar shows the key bindings relevant to that screen + And the help bar uses the same visual format on every screen + + Rule: The highlighted item in any list is indicated with a consistent cursor + + Scenario: Cursor on a selectable list + Given any screen with a selectable list + Then the highlighted item is marked with a consistent visual indicator + + Rule: A breadcrumb at the top shows the path of selections made so far + + Scenario: No breadcrumb on the first screen + Given the user is on the command menu + Then no breadcrumb is displayed + + Scenario: Breadcrumb builds as selections are made + Given the user has selected a command and a preset + When they reach a command-specific screen + Then the breadcrumb shows their prior selections in order + + Scenario: Breadcrumb updates on back navigation + Given the user has progressed several screens into a flow + When they navigate back one step + Then the breadcrumb removes the most recent selection + + Rule: The current screen's title is displayed below the breadcrumb + + Scenario: Screen title is always visible + Given the user is on any screen + Then the screen's title is displayed below the breadcrumb + + Rule: Ctrl+C exits the session cleanly from any screen + + Scenario: Cancelling during a flow + Given the user is on any screen + When they press Ctrl+C + Then the session exits without executing restic diff --git a/go.mod b/go.mod index 7a99d622d0285c59e9743c25afb780a045c3b65a..36b467eb7a7f38e75c061cf9b99fa4b99b0e2f99 100644 --- a/go.mod +++ b/go.mod @@ -28,6 +28,7 @@ require ( github.com/clipperhouse/uax29/v2 v2.7.0 // indirect github.com/dustin/go-humanize v1.0.1 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect + github.com/lrstanley/bubbletint/v2 v2.0.1 // indirect github.com/lucasb-eyer/go-colorful v1.3.0 // indirect github.com/mattn/go-runewidth v0.0.20 // indirect github.com/mitchellh/hashstructure/v2 v2.0.2 // indirect diff --git a/go.sum b/go.sum index 14d284e6586cdeefc1bd5cbeadf75cca9d4b5d12..b9c9e7509302e2e51a49a743624977723a7a33ae 100644 --- a/go.sum +++ b/go.sum @@ -57,6 +57,8 @@ github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkp github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= +github.com/lrstanley/bubbletint/v2 v2.0.1 h1:ELxRFzrm9X5DIz7Y1Yp0gfGhsJo+4U3w8WJe6x/Beso= +github.com/lrstanley/bubbletint/v2 v2.0.1/go.mod h1:fL833lvIEbec7VBi9F8wZ/1008jBiDrvQtuIac9AG/k= github.com/lucasb-eyer/go-colorful v1.3.0 h1:2/yBRLdWBZKrf7gB40FoiKfAWYQ0lqNcbuQwVHXptag= github.com/lucasb-eyer/go-colorful v1.3.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0= github.com/mattn/go-runewidth v0.0.20 h1:WcT52H91ZUAwy8+HUkdM3THM6gXqXuLJi9O3rjcQQaQ=