fix(hosts): use LocalResource for network/app dropdowns to fix hydration blank
Resource::new() with SSR returns None during hydration outside <Suspense>, causing dropdowns to stay empty on direct page load. LocalResource fetches client-side only, bypassing the hydration mismatch entirely. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -32,7 +32,7 @@ const PER_PAGE_OPTIONS: &[(i64, &str)] = &[
|
||||
#[component]
|
||||
fn AddHostModal(
|
||||
create_action: ServerAction<CreateHost>,
|
||||
networks_res: Resource<Result<Vec<crate::models::Network>, ServerFnError>>,
|
||||
networks_res: LocalResource<Result<Vec<crate::models::Network>, ServerFnError>>,
|
||||
show_modal: RwSignal<bool>,
|
||||
) -> impl IntoView {
|
||||
// Close the modal automatically after a successful creation.
|
||||
@@ -70,7 +70,7 @@ fn AddHostModal(
|
||||
<select name="network_id" required>
|
||||
<option value="">"— choose —"</option>
|
||||
{move || networks_res.get()
|
||||
.and_then(|r| r.ok())
|
||||
.and_then(|r| (*r).clone().ok())
|
||||
.map(|nets| nets.into_iter().map(|n| {
|
||||
let label = format!("{} - {}", n.name, n.cidr);
|
||||
view! { <option value=n.id.to_string()>{label}</option> }
|
||||
@@ -112,8 +112,8 @@ fn AddHostModal(
|
||||
|
||||
#[component]
|
||||
fn FilterBar(
|
||||
networks_res: Resource<Result<Vec<crate::models::Network>, ServerFnError>>,
|
||||
applications_res: Resource<Result<Vec<crate::models::Application>, ServerFnError>>,
|
||||
networks_res: LocalResource<Result<Vec<crate::models::Network>, ServerFnError>>,
|
||||
applications_res: LocalResource<Result<Vec<crate::models::Application>, ServerFnError>>,
|
||||
name_filter: RwSignal<String>,
|
||||
network_id_filter: RwSignal<i64>,
|
||||
port_filter: RwSignal<String>,
|
||||
@@ -143,7 +143,7 @@ fn FilterBar(
|
||||
}>
|
||||
<option value="0">"All networks"</option>
|
||||
{move || networks_res.get()
|
||||
.and_then(|r| r.ok())
|
||||
.and_then(|r| (*r).clone().ok())
|
||||
.map(|nets| nets.into_iter().map(|n| {
|
||||
let label = format!("{} - {}", n.name, n.cidr);
|
||||
view! { <option value=n.id.to_string()>{label}</option> }
|
||||
@@ -172,7 +172,7 @@ fn FilterBar(
|
||||
}>
|
||||
<option value="0">"All applications"</option>
|
||||
{move || applications_res.get()
|
||||
.and_then(|r| r.ok())
|
||||
.and_then(|r| (*r).clone().ok())
|
||||
.map(|apps| apps.into_iter().map(|a| {
|
||||
view! { <option value=a.id.to_string()>{a.name}</option> }
|
||||
}).collect_view())
|
||||
@@ -342,8 +342,8 @@ pub fn HostsPage() -> impl IntoView {
|
||||
|(name, net, port, app, p, pp, _, _)| get_hosts_page(name, net, port, app, p, pp),
|
||||
);
|
||||
|
||||
let networks_res = Resource::new(|| (), |_| get_networks());
|
||||
let applications_res = Resource::new(|| (), |_| get_applications());
|
||||
let networks_res = LocalResource::new(|| get_networks());
|
||||
let applications_res = LocalResource::new(|| get_applications());
|
||||
|
||||
let total_pages = Signal::derive(move || {
|
||||
hosts.get().and_then(|r| r.ok()).map(|p| p.total_pages).unwrap_or(1)
|
||||
|
||||
Reference in New Issue
Block a user