Files
es24n-conf/modules/ui.py
scott cb1c23480e Rename es24n/ to modules/
Update sys.path reference in es24n_conf.py and all documentation
to reflect the new folder name.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-17 19:12:29 -04:00

121 lines
3.5 KiB
Python

"""
ui.py — ANSI colour helpers, display primitives, and input prompts.
Shared by all ES24N workflows.
"""
import ipaddress
import sys
# ── ANSI colour helpers ───────────────────────────────────────────────────────
class C:
RED = "\033[0;31m"
GRN = "\033[0;32m"
YEL = "\033[1;33m"
CYN = "\033[0;36m"
WHT = "\033[1;37m"
DIM = "\033[2m"
BOLD = "\033[1m"
RESET = "\033[0m"
CLEAR = "\033[2J\033[H"
def _c(colour: str, text: str) -> str:
return f"{colour}{text}{C.RESET}"
def info(msg: str): print(f" {_c(C.CYN, 'i')} {msg}")
def ok(msg: str): print(f" {_c(C.GRN, 'OK')} {msg}")
def warn(msg: str): print(f" {_c(C.YEL, '!')} {msg}")
def error(msg: str): print(f" {_c(C.RED, 'X')} {msg}")
def banner():
print(C.CLEAR, end="")
w = 60
print(_c(C.CYN, " +" + "-" * w + "+"))
print(_c(C.CYN, " |") + _c(C.WHT + C.BOLD,
" TrueNAS ES24N IOM Configuration Tool ") + _c(C.CYN, " |"))
print(_c(C.CYN, " |") + _c(C.DIM,
" Serial Config & Firmware Updates (stdlib only) ") + _c(C.CYN, " |"))
print(_c(C.CYN, " +" + "-" * w + "+"))
print()
def rule(title: str = ""):
width = 60
if title:
pad = max(0, width - len(title) - 2)
left = pad // 2
right = pad - left
line = f"{'-' * left} {title} {'-' * right}"
else:
line = "-" * width
print(f"\n {_c(C.YEL, line)}\n")
def draw_table(headers: list, rows: list, col_widths: list):
sep = " +-" + "-+-".join("-" * w for w in col_widths) + "-+"
def fmt_row(cells):
return " | " + " | ".join(
str(c).ljust(w) for c, w in zip(cells, col_widths)
) + " |"
print(_c(C.DIM, sep))
print(_c(C.BOLD, fmt_row(headers)))
print(_c(C.DIM, sep))
for row in rows:
print(fmt_row(row))
print(_c(C.DIM, sep))
def draw_box(lines: list, colour: str = C.CYN):
width = max(len(l) for l in lines) + 4
print(f" {_c(colour, '+' + '-' * width + '+')}")
for line in lines:
pad = width - len(line) - 2
print(f" {_c(colour, '|')} {line}{' ' * pad} {_c(colour, '|')}")
print(f" {_c(colour, '+' + '-' * width + '+')}")
# ── Input helpers ─────────────────────────────────────────────────────────────
def prompt(label: str, default: str = "") -> str:
display = f" {_c(C.CYN, label)}"
if default:
display += f" {_c(C.DIM, f'[{default}]')}"
display += ": "
sys.stdout.write(display)
sys.stdout.flush()
val = sys.stdin.readline().strip()
return val if val else default
def prompt_ip(label: str) -> str:
while True:
val = prompt(label)
try:
ipaddress.IPv4Address(val)
return val
except ValueError:
warn(f"'{val}' is not a valid IPv4 address — please try again.")
def prompt_yn(label: str, default: bool = True) -> bool:
hint = "Y/n" if default else "y/N"
val = prompt(f"{label} [{hint}]").strip().lower()
if not val:
return default
return val in ("y", "yes")
def prompt_password() -> str:
while True:
val = prompt(
"Admin password (BMC/chassis serial, e.g. MXE3000043CHA007)",
)
if val:
return val
warn("Password cannot be empty.")