Order hostnames first in new entry form

This commit is contained in:
Philip Henning 2026-09-04 18:43:39 +02:00
parent f9d09e7fad
commit 703e85fb1b
2 changed files with 23 additions and 29 deletions

View file

@ -45,7 +45,17 @@ class AddEntryModal(ModalScreen[HostEntry | None]):
) )
yield RadioButton("DNS Name Entry", id="dns-entry-radio") yield RadioButton("DNS Name Entry", id="dns-entry-radio")
# IP Address Section # Hostnames Section
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="default-input",
)
yield Static("", id="hostnames-error", classes="validation-error")
# Address sections follow Hostnames in both visual and Tab order.
with Vertical(classes="default-section", id="ip-section") as ip_address: with Vertical(classes="default-section", id="ip-section") as ip_address:
ip_address.border_title = "IP Address" ip_address.border_title = "IP Address"
yield Input( yield Input(
@ -55,7 +65,6 @@ class AddEntryModal(ModalScreen[HostEntry | None]):
) )
yield Static("", id="ip-error", classes="validation-error") yield Static("", id="ip-error", classes="validation-error")
# DNS Name Section (initially hidden)
with Vertical( with Vertical(
classes="default-section hidden", id="dns-section" classes="default-section hidden", id="dns-section"
) as dns_name: ) as dns_name:
@ -67,16 +76,6 @@ class AddEntryModal(ModalScreen[HostEntry | None]):
) )
yield Static("", id="dns-error", classes="validation-error") yield Static("", id="dns-error", classes="validation-error")
# Hostnames Section
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="default-input",
)
yield Static("", id="hostnames-error", classes="validation-error")
# Comment Section # Comment Section
with Vertical(classes="default-section") as comment: with Vertical(classes="default-section") as comment:
comment.border_title = "Comment (optional)" comment.border_title = "Comment (optional)"
@ -112,9 +111,8 @@ class AddEntryModal(ModalScreen[HostEntry | None]):
) )
def on_mount(self) -> None: def on_mount(self) -> None:
"""Focus IP address input when modal opens.""" """Focus the entry type choice when the modal opens."""
ip_input = self.query_one("#entry-type-radio", RadioSet) self.query_one("#entry-type-radio", RadioSet).focus()
ip_input.focus()
def on_radio_set_changed(self, event: RadioSet.Changed) -> None: def on_radio_set_changed(self, event: RadioSet.Changed) -> None:
"""Handle entry type radio button changes.""" """Handle entry type radio button changes."""
@ -135,9 +133,7 @@ class AddEntryModal(ModalScreen[HostEntry | None]):
if isinstance(active_section, Vertical): if isinstance(active_section, Vertical):
active_section.border_title = "Activate Entry" active_section.border_title = "Activate Entry"
# Focus IP input self.query_one("#hostnames-input", Input).focus()
ip_input = self.query_one("#ip-address-input", Input)
ip_input.focus()
elif pressed_radio and pressed_radio.id == "dns-entry-radio": elif pressed_radio and pressed_radio.id == "dns-entry-radio":
# Show DNS section, hide IP section # Show DNS section, hide IP section
ip_section = self.query_one("#ip-section") ip_section = self.query_one("#ip-section")
@ -155,9 +151,7 @@ class AddEntryModal(ModalScreen[HostEntry | None]):
"Activate Entry (DNS entries activate after resolution)" "Activate Entry (DNS entries activate after resolution)"
) )
# Focus DNS input self.query_one("#hostnames-input", Input).focus()
dns_input = self.query_one("#dns-name-input", Input)
dns_input.focus()
def on_button_pressed(self, event: Button.Pressed) -> None: def on_button_pressed(self, event: Button.Pressed) -> None:
"""Handle button presses.""" """Handle button presses."""

View file

@ -193,15 +193,15 @@ class TestAddEntryModalRadioButtonLogic:
# Mock the query_one method for sections and inputs # Mock the query_one method for sections and inputs
mock_ip_section = Mock() mock_ip_section = Mock()
mock_dns_section = Mock() mock_dns_section = Mock()
mock_ip_input = Mock(spec=Input) mock_hostname_input = Mock(spec=Input)
def mock_query_one(selector, widget_type=None): def mock_query_one(selector, widget_type=None):
if selector == "#ip-section": if selector == "#ip-section":
return mock_ip_section return mock_ip_section
elif selector == "#dns-section": elif selector == "#dns-section":
return mock_dns_section return mock_dns_section
elif selector == "#ip-address-input": elif selector == "#hostnames-input":
return mock_ip_input return mock_hostname_input
return Mock() return Mock()
self.modal.query_one = Mock(side_effect=mock_query_one) self.modal.query_one = Mock(side_effect=mock_query_one)
@ -225,22 +225,22 @@ class TestAddEntryModalRadioButtonLogic:
# Verify IP section is shown and DNS section is hidden # Verify IP section is shown and DNS section is hidden
mock_ip_section.remove_class.assert_called_with("hidden") mock_ip_section.remove_class.assert_called_with("hidden")
mock_dns_section.add_class.assert_called_with("hidden") mock_dns_section.add_class.assert_called_with("hidden")
mock_ip_input.focus.assert_called_once() mock_hostname_input.focus.assert_called_once()
def test_radio_button_change_to_dns_entry(self): def test_radio_button_change_to_dns_entry(self):
"""Test radio button change to DNS entry mode.""" """Test radio button change to DNS entry mode."""
# Mock the query_one method for sections and inputs # Mock the query_one method for sections and inputs
mock_ip_section = Mock() mock_ip_section = Mock()
mock_dns_section = Mock() mock_dns_section = Mock()
mock_dns_input = Mock(spec=Input) mock_hostname_input = Mock(spec=Input)
def mock_query_one(selector, widget_type=None): def mock_query_one(selector, widget_type=None):
if selector == "#ip-section": if selector == "#ip-section":
return mock_ip_section return mock_ip_section
elif selector == "#dns-section": elif selector == "#dns-section":
return mock_dns_section return mock_dns_section
elif selector == "#dns-name-input": elif selector == "#hostnames-input":
return mock_dns_input return mock_hostname_input
return Mock() return Mock()
self.modal.query_one = Mock(side_effect=mock_query_one) self.modal.query_one = Mock(side_effect=mock_query_one)
@ -264,7 +264,7 @@ class TestAddEntryModalRadioButtonLogic:
# Verify DNS section is shown and IP section is hidden # Verify DNS section is shown and IP section is hidden
mock_ip_section.add_class.assert_called_with("hidden") mock_ip_section.add_class.assert_called_with("hidden")
mock_dns_section.remove_class.assert_called_with("hidden") mock_dns_section.remove_class.assert_called_with("hidden")
mock_dns_input.focus.assert_called_once() mock_hostname_input.focus.assert_called_once()
class TestAddEntryModalSaveLogic: class TestAddEntryModalSaveLogic: