Refactor hosts TUI application: remove main entry point, enhance modal styles, and unify button classes
- Deleted the main entry point file for the hosts application. - Updated the Add Entry Modal to improve section titles and input styles. - Refactored HostsManagerApp layout to use common pane styles for left and right sections. - Enhanced Config, Delete Confirmation, and Help modals with consistent button labels and styles. - Improved Password Modal layout and removed unnecessary parameters. - Consolidated common CSS styles for buttons, inputs, and sections to ensure consistent styling across the application.
This commit is contained in:
parent
54a2e00e29
commit
502bbd87f3
10 changed files with 155 additions and 1218 deletions
File diff suppressed because it is too large
Load diff
|
@ -1,17 +0,0 @@
|
|||
"""
|
||||
Main entry point for the hosts TUI application.
|
||||
|
||||
This module contains the main application entry point function.
|
||||
"""
|
||||
|
||||
from .tui.app import HostsManagerApp
|
||||
|
||||
|
||||
def main():
|
||||
"""Main entry point for the hosts application."""
|
||||
app = HostsManagerApp()
|
||||
app.run()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
|
@ -36,47 +36,48 @@ class AddEntryModal(ModalScreen):
|
|||
with Vertical(classes="add-entry-container"):
|
||||
yield Static("Add New Host Entry", classes="add-entry-title")
|
||||
|
||||
with Vertical(classes="add-entry-section"):
|
||||
yield Label("IP Address:")
|
||||
with Vertical(classes="default-section") as ip_address:
|
||||
ip_address.border_title = "IP Address"
|
||||
yield Input(
|
||||
placeholder="e.g., 192.168.1.1 or 2001:db8::1",
|
||||
id="ip-address-input",
|
||||
classes="add-entry-input",
|
||||
classes="default-input",
|
||||
)
|
||||
yield Static("", id="ip-error", classes="validation-error")
|
||||
|
||||
with Vertical(classes="add-entry-section"):
|
||||
yield Label("Hostnames (comma-separated):")
|
||||
with Vertical(classes="default-section") as hostnames:
|
||||
hostnames.border_title = "Hostnames"
|
||||
yield Input(
|
||||
placeholder="e.g., example.com, www.example.com",
|
||||
id="hostnames-input",
|
||||
classes="add-entry-input",
|
||||
classes="default-input",
|
||||
)
|
||||
yield Static("", id="hostnames-error", classes="validation-error")
|
||||
|
||||
with Vertical(classes="add-entry-section"):
|
||||
yield Label("Comment (optional):")
|
||||
with Vertical(classes="default-section") as comment:
|
||||
comment.border_title = "Comment (optional)"
|
||||
yield Input(
|
||||
placeholder="e.g., Development server",
|
||||
id="comment-input",
|
||||
classes="add-entry-input",
|
||||
classes="default-input",
|
||||
)
|
||||
|
||||
with Vertical(classes="add-entry-section"):
|
||||
yield Checkbox("Active (enabled)", value=True, id="active-checkbox")
|
||||
with Vertical(classes="default-section") as active:
|
||||
active.border_title = "Activate Entry"
|
||||
yield Checkbox("Active", value=True, id="active-checkbox", classes="default-checkbox")
|
||||
|
||||
with Horizontal(classes="button-row"):
|
||||
yield Button(
|
||||
"Add Entry",
|
||||
"Add Entry (CTRL+S)",
|
||||
variant="primary",
|
||||
id="add-button",
|
||||
classes="add-entry-button",
|
||||
classes="default-button",
|
||||
)
|
||||
yield Button(
|
||||
"Cancel",
|
||||
"Cancel (ESC)",
|
||||
variant="default",
|
||||
id="cancel-button",
|
||||
classes="add-entry-button",
|
||||
classes="default-button",
|
||||
)
|
||||
|
||||
def on_mount(self) -> None:
|
||||
|
|
|
@ -82,12 +82,12 @@ class HostsManagerApp(App):
|
|||
|
||||
with Horizontal(classes="hosts-container"):
|
||||
# Left pane - entries table
|
||||
with Vertical(classes="left-pane") as left_pane:
|
||||
with Vertical(classes="common-pane left-pane") as left_pane:
|
||||
left_pane.border_title = "Host Entries"
|
||||
yield DataTable(id="entries-table")
|
||||
|
||||
# Right pane - entry details or edit form
|
||||
with Vertical(classes="right-pane") as right_pane:
|
||||
with Vertical(classes="common-pane right-pane") as right_pane:
|
||||
right_pane.border_title = "Entry Details"
|
||||
yield DataTable(
|
||||
id="entry-details-table",
|
||||
|
|
|
@ -51,10 +51,10 @@ class ConfigModal(ModalScreen):
|
|||
"Save", variant="primary", id="save-button", classes="config-button"
|
||||
)
|
||||
yield Button(
|
||||
"Cancel",
|
||||
"Cancel (ESC)",
|
||||
variant="default",
|
||||
id="cancel-button",
|
||||
classes="config-button",
|
||||
classes="default-button",
|
||||
)
|
||||
|
||||
def on_button_pressed(self, event: Button.Pressed) -> None:
|
||||
|
|
|
@ -55,13 +55,13 @@ class DeleteConfirmationModal(ModalScreen):
|
|||
"Delete",
|
||||
variant="error",
|
||||
id="delete-button",
|
||||
classes="delete-button",
|
||||
classes="default-button",
|
||||
)
|
||||
yield Button(
|
||||
"Cancel",
|
||||
"Cancel (ESC)",
|
||||
variant="default",
|
||||
id="cancel-button",
|
||||
classes="delete-button",
|
||||
classes="default-button",
|
||||
)
|
||||
|
||||
def on_mount(self) -> None:
|
||||
|
|
|
@ -32,85 +32,84 @@ class HelpModal(ModalScreen):
|
|||
with Vertical(classes="help-container"):
|
||||
yield Static("/etc/hosts Manager - Help", classes="help-title")
|
||||
|
||||
with ScrollableContainer(classes="help-content"):
|
||||
# Navigation section
|
||||
with Vertical(classes="help-section"):
|
||||
yield Static("Navigation", classes="help-section-title")
|
||||
yield Static("↑ ↓ - Navigate entries", classes="help-item")
|
||||
yield Static("Enter - Select entry", classes="help-item")
|
||||
yield Static("Tab - Navigate between panes", classes="help-item")
|
||||
# Navigation section
|
||||
with Vertical(classes="help-section"):
|
||||
yield Static("Navigation", classes="help-section-title")
|
||||
yield Static("↑ ↓ - Navigate entries", classes="help-item")
|
||||
yield Static("Enter - Select entry", classes="help-item")
|
||||
yield Static("Tab - Navigate between panes", classes="help-item")
|
||||
|
||||
# Main Commands section
|
||||
with Vertical(classes="help-section"):
|
||||
yield Static("Main Commands", classes="help-section-title")
|
||||
yield Static(
|
||||
"[bold]r[/bold] Reload [bold]h[/bold] Help [bold]c[/bold] Config [bold]q[/bold] Quit",
|
||||
classes="help-item",
|
||||
)
|
||||
yield Static(
|
||||
"[bold]i[/bold] Sort by IP [bold]n[/bold] Sort by hostname",
|
||||
classes="help-item",
|
||||
)
|
||||
# Main Commands section
|
||||
with Vertical(classes="help-section"):
|
||||
yield Static("Main Commands", classes="help-section-title")
|
||||
yield Static(
|
||||
"[bold]r[/bold] Reload [bold]h[/bold] Help [bold]c[/bold] Config [bold]q[/bold] Quit",
|
||||
classes="help-item",
|
||||
)
|
||||
yield Static(
|
||||
"[bold]i[/bold] Sort by IP [bold]n[/bold] Sort by hostname",
|
||||
classes="help-item",
|
||||
)
|
||||
|
||||
# Edit Mode section
|
||||
with Vertical(classes="help-section"):
|
||||
yield Static("Edit Mode Commands", classes="help-section-title")
|
||||
yield Static(
|
||||
"[bold]Ctrl+E[/bold] - Toggle edit mode (requires sudo)",
|
||||
classes="help-item",
|
||||
)
|
||||
yield Static(
|
||||
"[italic]Edit mode commands:[/italic] [bold]Space[/bold] Toggle [bold]a[/bold] Add [bold]d[/bold] Delete [bold]e[/bold] Edit",
|
||||
classes="help-item",
|
||||
)
|
||||
yield Static(
|
||||
"[bold]Shift+↑/↓[/bold] Move entry [bold]Ctrl+S[/bold] Save file",
|
||||
classes="help-item",
|
||||
)
|
||||
# Edit Mode section
|
||||
with Vertical(classes="help-section"):
|
||||
yield Static("Edit Mode Commands", classes="help-section-title")
|
||||
yield Static(
|
||||
"[bold]Ctrl+E[/bold] - Toggle edit mode (requires sudo)",
|
||||
classes="help-item",
|
||||
)
|
||||
yield Static(
|
||||
"[italic]Edit mode commands:[/italic] [bold]Space[/bold] Toggle [bold]a[/bold] Add [bold]d[/bold] Delete [bold]e[/bold] Edit",
|
||||
classes="help-item",
|
||||
)
|
||||
yield Static(
|
||||
"[bold]Shift+↑/↓[/bold] Move entry [bold]Ctrl+S[/bold] Save file",
|
||||
classes="help-item",
|
||||
)
|
||||
|
||||
# Form Navigation section
|
||||
with Vertical(classes="help-section"):
|
||||
yield Static(
|
||||
"Form & Modal Navigation", classes="help-section-title"
|
||||
)
|
||||
yield Static(
|
||||
"[bold]Tab/Shift+Tab[/bold] Navigate fields [bold]Enter[/bold] Confirm/Save [bold]Escape[/bold] Cancel/Exit",
|
||||
classes="help-item",
|
||||
)
|
||||
# Form Navigation section
|
||||
with Vertical(classes="help-section"):
|
||||
yield Static(
|
||||
"Form & Modal Navigation", classes="help-section-title"
|
||||
)
|
||||
yield Static(
|
||||
"[bold]Tab/Shift+Tab[/bold] Navigate fields [bold]Enter[/bold] Confirm/Save [bold]Escape[/bold] Cancel/Exit",
|
||||
classes="help-item",
|
||||
)
|
||||
|
||||
# Special Commands section
|
||||
with Vertical(classes="help-section"):
|
||||
yield Static(
|
||||
"Special Dialog Commands", classes="help-section-title"
|
||||
)
|
||||
yield Static(
|
||||
"[bold]s[/bold] Save changes [bold]d[/bold] Discard changes",
|
||||
classes="help-item",
|
||||
)
|
||||
# Special Commands section
|
||||
with Vertical(classes="help-section"):
|
||||
yield Static(
|
||||
"Special Dialog Commands", classes="help-section-title"
|
||||
)
|
||||
yield Static(
|
||||
"[bold]s[/bold] Save changes [bold]d[/bold] Discard changes",
|
||||
classes="help-item",
|
||||
)
|
||||
|
||||
# Status and Tips section
|
||||
with Vertical(classes="help-section"):
|
||||
yield Static("Entry Status & Tips", classes="help-section-title")
|
||||
yield Static(
|
||||
"✓ Active (enabled) ✗ Inactive (commented out)",
|
||||
classes="help-item",
|
||||
)
|
||||
yield Static(
|
||||
"• Edit mode commands require [bold]Ctrl+E[/bold] first",
|
||||
classes="help-item",
|
||||
)
|
||||
yield Static(
|
||||
"• Search supports partial matches in IP, hostname, or comment",
|
||||
classes="help-item",
|
||||
)
|
||||
yield Static(
|
||||
"• Edit mode creates automatic backups • System entries cannot be modified",
|
||||
classes="help-item",
|
||||
)
|
||||
# Status and Tips section
|
||||
with Vertical(classes="help-section"):
|
||||
yield Static("Entry Status & Tips", classes="help-section-title")
|
||||
yield Static(
|
||||
"✓ Active (enabled) ✗ Inactive (commented out)",
|
||||
classes="help-item",
|
||||
)
|
||||
yield Static(
|
||||
"• Edit mode commands require [bold]Ctrl+E[/bold] first",
|
||||
classes="help-item",
|
||||
)
|
||||
yield Static(
|
||||
"• Search supports partial matches in IP, hostname, or comment",
|
||||
classes="help-item",
|
||||
)
|
||||
yield Static(
|
||||
"• Edit mode creates automatic backups • System entries cannot be modified",
|
||||
classes="help-item",
|
||||
)
|
||||
|
||||
with Horizontal(classes="button-row"):
|
||||
yield Button(
|
||||
"Close", variant="primary", id="close-button", classes="help-button"
|
||||
"Close", variant="primary", id="close-button", classes="default-button"
|
||||
)
|
||||
|
||||
def on_mount(self) -> None:
|
||||
|
|
|
@ -11,7 +11,7 @@ from textual.binding import Binding
|
|||
HOSTS_MANAGER_BINDINGS = [
|
||||
Binding("q", "quit", "Quit"),
|
||||
Binding("r", "reload", "Reload"),
|
||||
Binding("h", "help", "Help"),
|
||||
Binding("question_mark", "help", "Help", key_display="?"),
|
||||
Binding("i", "sort_by_ip", "Sort by IP"),
|
||||
Binding("n", "sort_by_hostname", "Sort by Hostname"),
|
||||
Binding("c", "config", "Config"),
|
||||
|
|
|
@ -27,38 +27,27 @@ class PasswordModal(ModalScreen):
|
|||
Binding("enter", "submit", "Submit"),
|
||||
]
|
||||
|
||||
def __init__(self, message: str = "Enter your password for sudo access:"):
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.message = message
|
||||
self.error_message = ""
|
||||
|
||||
def compose(self) -> ComposeResult:
|
||||
"""Create the password modal layout."""
|
||||
with Vertical(classes="password-container"):
|
||||
yield Static("Sudo Authentication", classes="password-title")
|
||||
yield Static(self.message, classes="password-message")
|
||||
|
||||
yield Input(
|
||||
placeholder="Password",
|
||||
password=True,
|
||||
id="password-input",
|
||||
classes="password-input",
|
||||
)
|
||||
with Vertical(classes="default-section") as password_input:
|
||||
password_input.border_title = "Enter sudo Password"
|
||||
yield Input(
|
||||
placeholder="Password",
|
||||
password=True,
|
||||
id="password-input",
|
||||
classes="default-input",
|
||||
)
|
||||
|
||||
# Error message placeholder (initially empty)
|
||||
yield Static("", id="error-message", classes="error-message")
|
||||
|
||||
with Horizontal(classes="button-row"):
|
||||
yield Button(
|
||||
"OK", variant="primary", id="ok-button", classes="password-button"
|
||||
)
|
||||
yield Button(
|
||||
"Cancel",
|
||||
variant="default",
|
||||
id="cancel-button",
|
||||
classes="password-button",
|
||||
)
|
||||
|
||||
def on_mount(self) -> None:
|
||||
"""Focus the password input when modal opens."""
|
||||
password_input = self.query_one("#password-input", Input)
|
||||
|
|
|
@ -5,8 +5,48 @@ This module contains all CSS definitions for consistent styling
|
|||
across the application.
|
||||
"""
|
||||
|
||||
# Common CSS classes shared across components
|
||||
COMMON_CSS = """
|
||||
.default-button {
|
||||
margin: 0 1;
|
||||
min-width: 10;
|
||||
}
|
||||
|
||||
.default-checkbox {
|
||||
height: 1fr;
|
||||
margin: 0 2;
|
||||
border: none;
|
||||
}
|
||||
|
||||
.default-input {
|
||||
height: 1fr;
|
||||
width: 1fr;
|
||||
margin: 0 2;
|
||||
border: none;
|
||||
}
|
||||
|
||||
.default-section {
|
||||
border: round $primary;
|
||||
height: 3;
|
||||
padding: 0;
|
||||
margin: 1 0;
|
||||
}
|
||||
|
||||
.button-row {
|
||||
margin-top: 2;
|
||||
height: 3;
|
||||
align: center middle;
|
||||
}
|
||||
|
||||
.hidden {
|
||||
display: none;
|
||||
}
|
||||
"""
|
||||
|
||||
# CSS styles for the hosts manager application
|
||||
HOSTS_MANAGER_CSS = """
|
||||
HOSTS_MANAGER_CSS = (
|
||||
COMMON_CSS
|
||||
+"""
|
||||
.search-container {
|
||||
border: round $primary;
|
||||
height: 3;
|
||||
|
@ -16,28 +56,27 @@ HOSTS_MANAGER_CSS = """
|
|||
}
|
||||
|
||||
.search-input {
|
||||
height: 1fr;
|
||||
width: 1fr;
|
||||
height: 1;
|
||||
border: none;
|
||||
}
|
||||
|
||||
.hosts-container {
|
||||
# height: 1fr;
|
||||
height: 1fr;
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
.common-pane {
|
||||
border: round $primary;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.left-pane {
|
||||
width: 60%;
|
||||
border: round $primary;
|
||||
margin: 0;
|
||||
padding: 1;
|
||||
}
|
||||
|
||||
.right-pane {
|
||||
width: 40%;
|
||||
border: round $primary;
|
||||
margin: 0;
|
||||
padding: 1;
|
||||
}
|
||||
|
||||
.entry-active {
|
||||
|
@ -128,18 +167,7 @@ Header.-tall {
|
|||
height: 1; /* Fix tall header also to height 1 */
|
||||
}
|
||||
"""
|
||||
|
||||
# Common CSS classes shared across components
|
||||
COMMON_CSS = """
|
||||
.button-row {
|
||||
margin-top: 1;
|
||||
align: center middle;
|
||||
}
|
||||
|
||||
.hidden {
|
||||
display: none;
|
||||
}
|
||||
"""
|
||||
)
|
||||
|
||||
# Help Modal CSS
|
||||
HELP_MODAL_CSS = (
|
||||
|
@ -187,10 +215,6 @@ HelpModal {
|
|||
text-style: bold;
|
||||
color: $accent;
|
||||
}
|
||||
|
||||
.help-button {
|
||||
min-width: 10;
|
||||
}
|
||||
"""
|
||||
)
|
||||
|
||||
|
@ -204,7 +228,7 @@ AddEntryModal {
|
|||
|
||||
.add-entry-container {
|
||||
width: 80;
|
||||
height: 25;
|
||||
height: 26;
|
||||
background: $surface;
|
||||
border: thick $primary;
|
||||
padding: 1;
|
||||
|
@ -217,25 +241,6 @@ AddEntryModal {
|
|||
margin-bottom: 1;
|
||||
}
|
||||
|
||||
.add-entry-section {
|
||||
margin: 1 0;
|
||||
}
|
||||
|
||||
.add-entry-input {
|
||||
margin: 0 2;
|
||||
width: 1fr;
|
||||
}
|
||||
|
||||
.button-row {
|
||||
margin-top: 2;
|
||||
align: center middle;
|
||||
}
|
||||
|
||||
.add-entry-button {
|
||||
margin: 0 1;
|
||||
min-width: 10;
|
||||
}
|
||||
|
||||
.validation-error {
|
||||
color: $error;
|
||||
margin: 0 2;
|
||||
|
@ -254,7 +259,7 @@ DeleteConfirmationModal {
|
|||
|
||||
.delete-container {
|
||||
width: 60;
|
||||
height: 15;
|
||||
height: 16;
|
||||
background: $surface;
|
||||
border: thick $error;
|
||||
padding: 1;
|
||||
|
@ -278,16 +283,6 @@ DeleteConfirmationModal {
|
|||
color: $primary;
|
||||
margin: 1 0;
|
||||
}
|
||||
|
||||
.button-row {
|
||||
margin-top: 2;
|
||||
align: center middle;
|
||||
}
|
||||
|
||||
.delete-button {
|
||||
margin: 0 1;
|
||||
min-width: 10;
|
||||
}
|
||||
"""
|
||||
)
|
||||
|
||||
|
@ -301,7 +296,7 @@ PasswordModal {
|
|||
|
||||
.password-container {
|
||||
width: 60;
|
||||
height: 12;
|
||||
height: 11;
|
||||
background: $surface;
|
||||
border: thick $primary;
|
||||
padding: 1;
|
||||
|
@ -320,15 +315,6 @@ PasswordModal {
|
|||
margin-bottom: 1;
|
||||
}
|
||||
|
||||
.password-input {
|
||||
margin: 1 0;
|
||||
}
|
||||
|
||||
.password-button {
|
||||
margin: 0 1;
|
||||
min-width: 10;
|
||||
}
|
||||
|
||||
.error-message {
|
||||
color: $error;
|
||||
text-align: center;
|
||||
|
@ -367,16 +353,6 @@ ConfigModal {
|
|||
.config-option {
|
||||
margin: 0 2;
|
||||
}
|
||||
|
||||
.button-row {
|
||||
margin-top: 2;
|
||||
align: center middle;
|
||||
}
|
||||
|
||||
.config-button {
|
||||
margin: 0 1;
|
||||
min-width: 10;
|
||||
}
|
||||
"""
|
||||
)
|
||||
|
||||
|
@ -413,9 +389,5 @@ SaveConfirmationModal {
|
|||
margin: 0 1;
|
||||
min-width: 12;
|
||||
}
|
||||
|
||||
.save-confirmation-button:focus {
|
||||
border: thick $accent;
|
||||
}
|
||||
"""
|
||||
)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue