feat: add Continue and Cancel buttons to Certificate Details form
Tab (or Down/Enter on a field) now cycles through the three text fields and then onto [ Continue ] and [ Cancel ] buttons at the bottom of the form. Enter or Space activates the focused button. Ctrl-G still confirms immediately from any position. Escape still cancels. The form window is trimmed from h=16 to h=13 since the buttons replace the now-redundant empty space below the password field. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -567,15 +567,22 @@ def show_cert_form(
|
||||
cn_readonly: bool = False,
|
||||
) -> CertFormResult:
|
||||
"""Modal cert-detail form.
|
||||
Tab / Shift-Tab / Up / Down cycle fields. F5 regenerates password.
|
||||
Enter on last field or Ctrl-S confirms. Escape cancels."""
|
||||
Tab / Shift-Tab / Up / Down cycle fields and buttons. F5 regenerates password.
|
||||
Enter or Space activates the focused button. Ctrl-G confirms immediately. Escape cancels."""
|
||||
sh, sw = stdscr.getmaxyx()
|
||||
h, w = 16, 62
|
||||
h, w = 13, 62
|
||||
win = curses.newwin(h, w, (sh - h) // 2, (sw - w) // 2)
|
||||
win.keypad(True)
|
||||
fw = w - 6 # field width
|
||||
|
||||
active = [n for n in _FORM_FIELDS if not (n == "cn" and cn_readonly)]
|
||||
_BTN_CONTINUE = "_continue"
|
||||
_BTN_CANCEL = "_cancel"
|
||||
_BTN_Y = 9
|
||||
_btn_x_cont = (w - 26) // 2 # "[ Continue ]"=12 + gap=4 + "[ Cancel ]"=10 = 26
|
||||
_btn_x_canc = _btn_x_cont + 16
|
||||
|
||||
active = ([n for n in _FORM_FIELDS if not (n == "cn" and cn_readonly)]
|
||||
+ [_BTN_CONTINUE, _BTN_CANCEL])
|
||||
fields: dict[str, InputField] = {
|
||||
"cn": InputField(win, _FORM_FIELD_Y["cn"], 3, fw, initial=cn),
|
||||
"email": InputField(win, _FORM_FIELD_Y["email"], 3, fw, initial=email),
|
||||
@@ -616,8 +623,33 @@ def show_cert_form(
|
||||
else:
|
||||
fields[name].draw()
|
||||
|
||||
fields[active[focus]].place_cursor()
|
||||
hint = "Tab=next F5=regen password Ctrl-G=confirm Esc=cancel"
|
||||
current = active[focus]
|
||||
for btn_label, btn_id, bx in (
|
||||
("Continue", _BTN_CONTINUE, _btn_x_cont),
|
||||
("Cancel", _BTN_CANCEL, _btn_x_canc),
|
||||
):
|
||||
btn_attr = (curses.color_pair(COLOR_SELECTED)
|
||||
if current == btn_id
|
||||
else curses.color_pair(COLOR_NORMAL))
|
||||
try:
|
||||
win.addstr(_BTN_Y, bx, f"[ {btn_label} ]", btn_attr | curses.A_BOLD)
|
||||
except curses.error:
|
||||
pass
|
||||
|
||||
if current == _BTN_CONTINUE:
|
||||
try:
|
||||
win.move(_BTN_Y, _btn_x_cont)
|
||||
except curses.error:
|
||||
pass
|
||||
elif current == _BTN_CANCEL:
|
||||
try:
|
||||
win.move(_BTN_Y, _btn_x_canc)
|
||||
except curses.error:
|
||||
pass
|
||||
else:
|
||||
fields[current].place_cursor()
|
||||
|
||||
hint = "Tab=next F5=regen pwd Ctrl-G=confirm Esc=cancel"
|
||||
try:
|
||||
win.addstr(h - 2, 2, hint[:w - 4], curses.color_pair(COLOR_DISABLED))
|
||||
except curses.error:
|
||||
@@ -632,16 +664,10 @@ def show_cert_form(
|
||||
if key == 0x07: # Ctrl-G: immediate submit
|
||||
curses.curs_set(0)
|
||||
return _submit()
|
||||
if key == 9: # Tab
|
||||
if key in (9, curses.KEY_DOWN): # Tab / Down: next
|
||||
focus = (focus + 1) % len(active)
|
||||
continue
|
||||
if key == curses.KEY_BTAB: # Shift-Tab
|
||||
focus = (focus - 1) % len(active)
|
||||
continue
|
||||
if key == curses.KEY_DOWN:
|
||||
focus = (focus + 1) % len(active)
|
||||
continue
|
||||
if key == curses.KEY_UP:
|
||||
if key in (curses.KEY_BTAB, curses.KEY_UP): # Shift-Tab / Up: prev
|
||||
focus = (focus - 1) % len(active)
|
||||
continue
|
||||
if key == curses.KEY_F5:
|
||||
@@ -650,13 +676,17 @@ def show_cert_form(
|
||||
initial=generate_password(), mask=True,
|
||||
)
|
||||
continue
|
||||
if key in (10, 13, curses.KEY_ENTER):
|
||||
if focus < len(active) - 1:
|
||||
focus += 1
|
||||
if current in (_BTN_CONTINUE, _BTN_CANCEL):
|
||||
if key in (10, 13, curses.KEY_ENTER, ord(" ")):
|
||||
curses.curs_set(0)
|
||||
if current == _BTN_CONTINUE:
|
||||
return _submit()
|
||||
return CertFormResult(cn=cn, email="", password="", confirmed=False)
|
||||
else:
|
||||
if key in (10, 13, curses.KEY_ENTER):
|
||||
focus = (focus + 1) % len(active)
|
||||
continue
|
||||
curses.curs_set(0)
|
||||
return _submit()
|
||||
fields[active[focus]].handle_key(key)
|
||||
fields[current].handle_key(key)
|
||||
|
||||
|
||||
# ============================================================
|
||||
|
||||
Reference in New Issue
Block a user