Skip to content

[#10] Added reveal toggle and confirmation mode to the password widget.#25

Merged
AlexSkrypnyk merged 3 commits into
mainfrom
feature/10-password-options
Jul 10, 2026
Merged

[#10] Added reveal toggle and confirmation mode to the password widget.#25
AlexSkrypnyk merged 3 commits into
mainfrom
feature/10-password-options

Conversation

@AlexSkrypnyk

@AlexSkrypnyk AlexSkrypnyk commented Jul 10, 2026

Copy link
Copy Markdown
Member

Closes #10

Summary

Adds two opt-in enhancements to PasswordWidget, both off by default so the existing masked-only behaviour is unchanged unless a consumer asks for them: a reveal toggle that cycles the live editor display between hidden, masked and plaintext, and a confirmation mode that prompts for the value twice and rejects a mismatch before accepting. Both flags are threaded through Field, FieldBuilder and WidgetFactory and exposed as fluent revealable() / confirm() builder methods. The panel row and summary always stay masked regardless of the live editor display.

Changes

  • Added the PasswordDisplay enum (Hidden / Masked / Plaintext) with a next() method that cycles Hidden → Masked → Plaintext → Hidden.
  • PasswordWidget gained revealable and confirm constructor flags: Tab cycles PasswordDisplay when revealable, and Enter drives a two-step confirm flow (stash first entry, clear the buffer, compare on the second Enter, restart with an error on mismatch, revalidate the matched value before accepting).
  • PasswordWidget::view() now renders extra footer lines for the confirm re-prompt, the reveal hint (enter accept · tab reveal · esc cancel) and any error, and a new renderLine() helper renders the buffer according to the current PasswordDisplay.
  • Added PasswordWidget::rendersHint(), returning true only when revealable is enabled.
  • Field gained revealable and confirm bool properties (default FALSE).
  • FieldBuilder gained fluent revealable() and confirm() methods, wired into build().
  • WidgetFactory passes $field->revealable and $field->confirm through when constructing a PasswordWidget.
  • Documented both options in the README Password section with a revealable()->confirm() example.
  • Added a widget-password-reveal playground demo and generated docs/assets/widget-password-reveal.svg (via docs/util/update-assets.php), shown under the README Password grid so the reveal toggle and its tab reveal hint are visible.
  • Added PasswordDisplayTest for the display cycle, extended PasswordWidgetTest with reveal-toggle, hint-visibility and confirm-flow coverage, and extended FormTest and WidgetFactoryTest for the builder and factory wiring.

Before / After

BEFORE (mask only, no options)              AFTER (both opt-in, off by default)
┌───────────────────────────┐               ┌─────────────────────────────────────────┐
│ API key                   │               │ API key                                  │
│ ••••••█                   │               │ ••••••█                                  │
│                           │               │ enter accept · tab reveal · esc cancel   │
└───────────────────────────┘               └─────────────────────────────────────────┘
  always masked                               revealable(): Tab cycles the live display

                                                 ••••••█  Masked (default)
                                                    │ Tab
                                                    ▼
                                                 sekret█  Plaintext
                                                    │ Tab
                                                    ▼
                                                 █        Hidden
                                                    │ Tab
                                                    └────► back to Masked

                                               confirm(): Enter requires a second entry
                                               ┌─────────────────────────────────────────┐
                                               │ API key                                  │
                                               │ ••••••█                                  │
                                               │ re-enter to confirm                      │
                                               └─────────────────────────────────────────┘
                                               mismatch -> "Passwords do not match." + restart
                                               match     -> accepted, panel row/summary stay masked

CONFIG SURFACE
  $p->password('api_key', 'API key');                              // before: mask only
  $p->password('api_key', 'API key')->revealable()->confirm();     // after: both opt-in

@coderabbitai

coderabbitai Bot commented Jul 10, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

Password fields now support opt-in reveal cycling and confirmation entry. Configuration flows from builders through Field and WidgetFactory into PasswordWidget, with updated rendering, validation behavior, documentation, demonstrations, and PHPUnit coverage.

Changes

Password widget enhancements

Layer / File(s) Summary
Password configuration and wiring
src/Builder/FieldBuilder.php, src/Config/Field.php, src/Widget/WidgetFactory.php, tests/phpunit/Unit/Builder/FormTest.php, tests/phpunit/Unit/Widget/WidgetFactoryTest.php, README.md
Builder methods and Field flags enable revealable and confirmation behavior, which WidgetFactory passes to PasswordWidget; defaults, usage, and the reveal example are covered.
Reveal display flow
src/Widget/PasswordDisplay.php, src/Widget/PasswordWidget.php, playground/3-widgets/widget-password-reveal.php, docs/util/update-assets.php, tests/phpunit/Unit/Widget/PasswordDisplayTest.php, tests/phpunit/Unit/Widget/PasswordWidgetTest.php
Tab cycles hidden, masked, and plaintext display states, updates rendering and hints, preserves the submitted password value, and includes an interactive demonstration and captured asset.
Confirmation submission flow
src/Widget/PasswordWidget.php, tests/phpunit/Unit/Widget/PasswordWidgetTest.php
Confirmation mode stores the first entry, rejects mismatches, resets state, and revalidates matching entries before completion.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Sequence Diagram(s)

sequenceDiagram
  participant User
  participant PasswordWidget
  participant PasswordDisplay
  User->>PasswordWidget: Press Tab
  PasswordWidget->>PasswordDisplay: Cycle display mode
  PasswordDisplay-->>PasswordWidget: Return next mode
  PasswordWidget-->>User: Render hidden, masked, or plaintext input
  User->>PasswordWidget: Submit first password
  PasswordWidget-->>User: Prompt for confirmation
  User->>PasswordWidget: Submit second password
  PasswordWidget->>PasswordWidget: Compare and validate entries
  PasswordWidget-->>User: Complete or show an error
Loading

Possibly related PRs

  • drevops/tui#3: Both changes modify PasswordWidget rendering, including view() behavior.
  • drevops/tui#21: Both changes modify password rendering and caret/error composition in PasswordWidget::view().
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 22.22% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Linked Issues check ✅ Passed The implementation and tests satisfy issue #10's requirements for reveal toggling, confirmation, defaults, masking, and README documentation.
Out of Scope Changes check ✅ Passed The added playground demo, asset generation job, documentation, and tests are all in scope for the password widget enhancements.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly matches the main change: adding reveal toggle and confirmation mode to the password widget.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feature/10-password-options

Comment @coderabbitai help to get the list of available commands.

@AlexSkrypnyk AlexSkrypnyk added the A1 Board worker 1 label Jul 10, 2026
@github-actions

This comment has been minimized.

@codecov

codecov Bot commented Jul 10, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 98.92%. Comparing base (637d2e6) to head (efc3668).
✅ All tests successful. No failed tests found.

Additional details and impacted files
@@            Coverage Diff             @@
##             main      #25      +/-   ##
==========================================
+ Coverage   98.88%   98.92%   +0.03%     
==========================================
  Files          56       57       +1     
  Lines        1349     1395      +46     
==========================================
+ Hits         1334     1380      +46     
  Misses         15       15              

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

@github-actions

Copy link
Copy Markdown
Code Coverage Report:
  2026-07-10 09:55:24

 Summary:
  Classes: 89.47% (51/57)
  Methods: 96.88% (342/353)
  Lines:   98.92% (1380/1395)

DrevOps\Tui\Answers\Answer
  Methods: 100.00% ( 1/ 1)   Lines: 100.00% (  1/  1)
DrevOps\Tui\Answers\Answers
  Methods: 100.00% ( 9/ 9)   Lines: 100.00% ( 20/ 20)
DrevOps\Tui\Answers\SummaryFormatter
  Methods: 100.00% ( 3/ 3)   Lines: 100.00% ( 20/ 20)
DrevOps\Tui\Builder\FieldBuilder
  Methods:  87.50% (14/16)   Lines:  92.16% ( 47/ 51)
DrevOps\Tui\Builder\Form
  Methods: 100.00% (13/13)   Lines: 100.00% ( 49/ 49)
DrevOps\Tui\Builder\PanelBuilder
  Methods: 100.00% (16/16)   Lines: 100.00% ( 28/ 28)
DrevOps\Tui\Condition\CompositeCondition
  Methods: 100.00% ( 4/ 4)   Lines: 100.00% ( 19/ 19)
DrevOps\Tui\Condition\Condition
  Methods: 100.00% (10/10)   Lines: 100.00% ( 38/ 38)
DrevOps\Tui\Config\Config
  Methods: 100.00% ( 5/ 5)   Lines: 100.00% ( 17/ 17)
DrevOps\Tui\Config\Field
  Methods: 100.00% ( 2/ 2)   Lines: 100.00% (  2/  2)
DrevOps\Tui\Config\Option
  Methods: 100.00% ( 1/ 1)   Lines: 100.00% (  1/  1)
DrevOps\Tui\Config\Panel
  Methods: 100.00% ( 1/ 1)   Lines: 100.00% (  1/  1)
DrevOps\Tui\Derive\Derive
  Methods: 100.00% ( 4/ 4)   Lines: 100.00% ( 14/ 14)
DrevOps\Tui\Derive\Deriver
  Methods: 100.00% ( 1/ 1)   Lines: 100.00% ( 13/ 13)
DrevOps\Tui\Derive\Transform
  Methods: 100.00% ( 3/ 3)   Lines: 100.00% (  7/  7)
DrevOps\Tui\Discovery\AbstractDiscover
  Methods: 100.00% ( 1/ 1)   Lines: 100.00% (  1/  1)
DrevOps\Tui\Discovery\Dotenv
  Methods: 100.00% ( 3/ 3)   Lines: 100.00% ( 19/ 19)
DrevOps\Tui\Discovery\JsonValue
  Methods: 100.00% ( 4/ 4)   Lines: 100.00% ( 16/ 16)
DrevOps\Tui\Discovery\PathExists
  Methods: 100.00% ( 3/ 3)   Lines: 100.00% (  3/  3)
DrevOps\Tui\Discovery\Scan
  Methods: 100.00% ( 3/ 3)   Lines: 100.00% ( 20/ 20)
DrevOps\Tui\Engine\Engine
  Methods: 100.00% (12/12)   Lines: 100.00% ( 89/ 89)
DrevOps\Tui\Handler\HandlerRegistry
  Methods:  85.71% ( 6/ 7)   Lines:  95.45% ( 21/ 22)
DrevOps\Tui\Input\ArrayKeyStream
  Methods: 100.00% ( 3/ 3)   Lines: 100.00% ( 12/ 12)
DrevOps\Tui\Input\Key
  Methods: 100.00% ( 5/ 5)   Lines: 100.00% (  5/  5)
DrevOps\Tui\Input\KeyParser
  Methods: 100.00% ( 6/ 6)   Lines: 100.00% ( 68/ 68)
DrevOps\Tui\Render\Ansi
  Methods: 100.00% ( 4/ 4)   Lines: 100.00% (  5/  5)
DrevOps\Tui\Render\Box
  Methods: 100.00% ( 3/ 3)   Lines: 100.00% ( 15/ 15)
DrevOps\Tui\Render\Navigator
  Methods: 100.00% ( 6/ 6)   Lines: 100.00% ( 15/ 15)
DrevOps\Tui\Render\PanelController
  Methods: 100.00% (16/16)   Lines: 100.00% ( 87/ 87)
DrevOps\Tui\Render\Scroller
  Methods: 100.00% ( 4/ 4)   Lines: 100.00% ( 12/ 12)
DrevOps\Tui\Render\Terminal
  Methods: 100.00% (12/12)   Lines: 100.00% ( 35/ 35)
DrevOps\Tui\Render\TerminalControl
  Methods: 100.00% ( 9/ 9)   Lines: 100.00% (  9/  9)
DrevOps\Tui\Render\Viewport
  Methods: 100.00% ( 1/ 1)   Lines: 100.00% (  1/  1)
DrevOps\Tui\Resolver\InputResolver
  Methods: 100.00% ( 6/ 6)   Lines: 100.00% ( 27/ 27)
DrevOps\Tui\Schema\AgentHelp
  Methods: 100.00% ( 2/ 2)   Lines: 100.00% ( 16/ 16)
DrevOps\Tui\Schema\SchemaGenerator
  Methods: 100.00% ( 3/ 3)   Lines: 100.00% ( 25/ 25)
DrevOps\Tui\Schema\SchemaValidator
  Methods: 100.00% ( 7/ 7)   Lines: 100.00% ( 40/ 40)
DrevOps\Tui\Theme\DefaultTheme
  Methods:  91.80% (56/61)   Lines:  96.77% (180/186)
DrevOps\Tui\Theme\ThemeManager
  Methods: 100.00% ( 2/ 2)   Lines: 100.00% (  8/  8)
DrevOps\Tui\Tui
  Methods: 100.00% (12/12)   Lines: 100.00% ( 26/ 26)
DrevOps\Tui\Widget\AbstractWidget
  Methods: 100.00% (10/10)   Lines: 100.00% ( 20/ 20)
DrevOps\Tui\Widget\ConfirmWidget
  Methods: 100.00% ( 6/ 6)   Lines: 100.00% ( 23/ 23)
DrevOps\Tui\Widget\MultiSearchWidget
  Methods: 100.00% ( 1/ 1)   Lines: 100.00% (  1/  1)
DrevOps\Tui\Widget\MultiSelectWidget
  Methods: 100.00% ( 9/ 9)   Lines: 100.00% ( 64/ 64)
DrevOps\Tui\Widget\NumberWidget
  Methods: 100.00% ( 2/ 2)   Lines: 100.00% (  7/  7)
DrevOps\Tui\Widget\PasswordDisplay
  Methods: 100.00% ( 1/ 1)   Lines: 100.00% (  5/  5)
DrevOps\Tui\Widget\PasswordWidget
  Methods: 100.00% ( 7/ 7)   Lines: 100.00% ( 38/ 38)
DrevOps\Tui\Widget\PauseWidget
  Methods: 100.00% ( 3/ 3)   Lines: 100.00% (  6/  6)
DrevOps\Tui\Widget\SearchWidget
  Methods:  80.00% ( 4/ 5)   Lines:  94.59% ( 35/ 37)
DrevOps\Tui\Widget\SelectWidget
  Methods: 100.00% ( 4/ 4)   Lines: 100.00% ( 19/ 19)
DrevOps\Tui\Widget\SuggestWidget
  Methods: 100.00% ( 5/ 5)   Lines: 100.00% ( 37/ 37)
DrevOps\Tui\Widget\TextWidget
  Methods: 100.00% ( 6/ 6)   Lines: 100.00% ( 29/ 29)
DrevOps\Tui\Widget\TextareaWidget
  Methods: 100.00% ( 4/ 4)   Lines: 100.00% ( 34/ 34)
DrevOps\Tui\Widget\WidgetFactory
  Methods: 100.00% ( 3/ 3)   Lines: 100.00% ( 25/ 25)
DrevOps\Tui\Widget\WidgetRunner
  Methods: 100.00% ( 1/ 1)   Lines: 100.00% (  5/  5)

@AlexSkrypnyk AlexSkrypnyk merged commit 861bb75 into main Jul 10, 2026
9 checks passed
@AlexSkrypnyk AlexSkrypnyk deleted the feature/10-password-options branch July 10, 2026 10:08
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

A1 Board worker 1

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add a reveal toggle and confirmation mode to the password widget

1 participant