fix(hosts,applications): fix modal re-open bug and autofocus first field

Move the add-modal auto-close Effect from each modal component to its
parent page component. This prevents the stale-value re-trigger bug
where the Effect would immediately close the modal on second open
because action.value() still held the previous Ok result.

Also add autofocus on the first input field of each add modal using
NodeRef<Input> so the user can start typing immediately on open.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-05-16 21:33:33 +02:00
parent 60e02ca453
commit 5228a76468
2 changed files with 38 additions and 6 deletions

View File

@@ -8,6 +8,7 @@
use leptos::prelude::*;
use leptos::form::ActionForm;
use leptos::html::Input;
use crate::api::applications::{
ApplicationWithCounts, CreateApplication, DeleteApplication,
@@ -21,9 +22,12 @@ fn AddApplicationModal(
create_action: ServerAction<CreateApplication>,
show_modal: RwSignal<bool>,
) -> impl IntoView {
let name_ref = NodeRef::<Input>::new();
// Focus the name field as soon as the modal is mounted.
Effect::new(move |_| {
if let Some(Ok(_)) = create_action.value().get() {
show_modal.set(false);
if let Some(el) = name_ref.get() {
let _ = el.focus();
}
});
@@ -43,6 +47,7 @@ fn AddApplicationModal(
<label>
"Name"
<input
node_ref=name_ref
type="text"
name="name"
placeholder="e.g. Nginx, PostgreSQL, Prometheus"
@@ -132,6 +137,19 @@ pub fn ApplicationsPage() -> impl IntoView {
// Name filter (client-side — list is typically small)
let name_filter = RwSignal::new(String::new());
// Close the add modal when the action transitions pending→done with Ok.
// Lives in the parent so it is never recreated across modal open/close cycles,
// which avoids the stale-value re-trigger bug.
Effect::new(move |was_pending: Option<bool>| {
let is_pending = create_action.pending().get();
if was_pending == Some(true) && !is_pending {
if let Some(Ok(_)) = create_action.value().get() {
show_modal.set(false);
}
}
is_pending
});
// Close the delete modal automatically after a successful deletion.
Effect::new(move |_| {
if let Some(Ok(_)) = delete_action.value().get() {