diff --git a/opendut-lea/src/about/overview.rs b/opendut-lea/src/about/overview.rs index c7e13126..4d1babf5 100644 --- a/opendut-lea/src/about/overview.rs +++ b/opendut-lea/src/about/overview.rs @@ -1,6 +1,6 @@ use leptos::prelude::*; use crate::app::use_app_globals; -use crate::components::BasePageContainer; +use crate::components::{BasePageContainer, LoadingSpinner}; use shadow_rs::shadow; use opendut_types::proto::util::VersionInfo; @@ -28,7 +28,7 @@ pub fn AboutOverview() -> impl IntoView { controls=view! { <> } >
- "Loading..."

}> + { move || Suspend::new(async move { let metadata = metadata.await; view! { diff --git a/opendut-lea/src/clusters/configurator/components/device_selector.rs b/opendut-lea/src/clusters/configurator/components/device_selector.rs index 5b072ac3..c58cba6d 100644 --- a/opendut-lea/src/clusters/configurator/components/device_selector.rs +++ b/opendut-lea/src/clusters/configurator/components/device_selector.rs @@ -9,7 +9,7 @@ use opendut_types::topology::{DeviceDescriptor, DeviceId}; use opendut_types::util::net::NetworkInterfaceDescriptor; use crate::clusters::configurator::components::{get_all_peers, get_all_selected_devices}; use crate::clusters::configurator::types::UserClusterConfiguration; -use crate::components::{ButtonColor, ButtonSize, ButtonState, FontAwesomeIcon, IconButton}; +use crate::components::{ButtonColor, ButtonSize, ButtonState, FontAwesomeIcon, IconButton, LoadingSpinner}; use crate::util::{Ior, NON_BREAKING_SPACE}; use crate::util::net::UserNetworkInterfaceConfiguration; @@ -119,8 +119,8 @@ pub fn DeviceSelector(cluster_configuration: RwSignal) - "Loading..."

} + {move || Suspend::new(async move { let peer_descriptors = peer_descriptors.await; @@ -129,7 +129,7 @@ pub fn DeviceSelector(cluster_configuration: RwSignal) { render_peer_descriptors(peer_descriptors, selected_devices, getter, setter) } } })} -
+
diff --git a/opendut-lea/src/clusters/configurator/components/leader_selector.rs b/opendut-lea/src/clusters/configurator/components/leader_selector.rs index 257c6608..d61c0eb2 100644 --- a/opendut-lea/src/clusters/configurator/components/leader_selector.rs +++ b/opendut-lea/src/clusters/configurator/components/leader_selector.rs @@ -7,6 +7,7 @@ use opendut_types::topology::DeviceId; use crate::clusters::configurator::components::{get_all_peers, get_all_selected_devices}; use crate::clusters::configurator::types::UserClusterConfiguration; +use crate::components::LoadingSpinner; use crate::util::{Ior, NON_BREAKING_SPACE}; pub type LeaderSelectionError = String; @@ -14,6 +15,7 @@ pub type LeaderSelection = Ior; #[component] pub fn LeaderSelector(cluster_configuration: RwSignal) -> impl IntoView { + let peer_descriptors = get_all_peers(); let getter_selected_devices = create_read_slice(cluster_configuration, |config| { @@ -38,7 +40,7 @@ pub fn LeaderSelector(cluster_configuration: RwSignal) }) }; - let rows = LocalResource::new(move || async move { + let peers = LocalResource::new(move || async move { let selected_devices = selected_devices(); let mut peers = peer_descriptors.await; @@ -53,9 +55,11 @@ pub fn LeaderSelector(cluster_configuration: RwSignal) peers.clone().into_iter() .filter(|peer_descriptor| { let mut peer_devices: HashSet = HashSet::new(); + for device in &peer_descriptor.topology.devices { peer_devices.insert(device.id); } + if selected_devices.len() < 2 { setter_leader.set(LeaderSelection::Left(String::from("Please select at least two devices first."))); } @@ -72,42 +76,9 @@ pub fn LeaderSelector(cluster_configuration: RwSignal) setter_leader.set(LeaderSelection::Left(String::from("Select a leader."))); } } + !peer_devices.is_disjoint(&selected_devices) }) - .map(|peer| { - view! { - - - { peer.name.to_string().into_view() } - - - { peer.id.to_string().into_view() } - - - { peer.location.unwrap_or_default().to_string().into_view() } - - -
- -
- - - } - }) .collect::>() }); @@ -124,13 +95,56 @@ pub fn LeaderSelector(cluster_configuration: RwSignal) - "Loading..."

} + {move || Suspend::new(async move { - rows.await + let peers = peers.await; + + let is_leader = move |peer: PeerId| { + match getter_leader.get() { + LeaderSelection::Right(leader) => peer == leader, + LeaderSelection::Left(_) | LeaderSelection::Both(_, _) => false, + } + }; + + view! { + + + { peer.name.to_string() } + + + { peer.id.to_string() } + + + { peer.location.clone().unwrap_or_default().to_string() } + + +
+ +
+ + + } + } + /> + } })} -
+ diff --git a/opendut-lea/src/clusters/configurator/mod.rs b/opendut-lea/src/clusters/configurator/mod.rs index 25fbe24d..1cacdc37 100644 --- a/opendut-lea/src/clusters/configurator/mod.rs +++ b/opendut-lea/src/clusters/configurator/mod.rs @@ -1,3 +1,4 @@ +use leptos::either::Either; use leptos::prelude::*; use leptos_router::hooks::{use_navigate, use_params_map}; use opendut_types::cluster::ClusterId; @@ -8,8 +9,8 @@ use crate::clusters::configurator::components::Controls; use crate::clusters::configurator::tabs::{DevicesTab, GeneralTab, LeaderTab, TabIdentifier}; use crate::clusters::configurator::types::UserClusterConfiguration; use crate::clusters::overview::IsDeployed; -use crate::components::{BasePageContainer, Breadcrumb, use_active_tab}; -use crate::components::{UserInputError, UserInputValue}; +use crate::components::{use_active_tab, BasePageContainer, Breadcrumb, LoadingSpinner}; +use crate::components::UserInputValue; use crate::routing::{navigate_to, WellKnownRoutes}; mod types; @@ -22,55 +23,72 @@ pub fn ClusterConfigurator() -> impl IntoView { let globals = use_app_globals(); let params = use_params_map(); - let active_tab = use_active_tab::(); + let load_cluster_configuration = { + let carl = globals.client.clone(); + + LocalResource::new(move || { + let mut carl = carl.clone(); - let cluster_configuration = { - let cluster_id = { - let cluster_id = params.with_untracked(|params| { + let maybe_cluster_id = params.with(|params| { params.get("id").and_then(|id| ClusterId::try_from(id.as_str()).ok()) }); - match cluster_id { - None => { - let use_navigate = use_navigate(); - navigate_to(WellKnownRoutes::ErrorPage { - title: String::from("Invalid ClusterId"), - text: String::from("Could not parse the provided value as ClusterId!"), - details: None, - }, use_navigate); - - ClusterId::default() - } - Some(cluster_id) => { - cluster_id + async move { + match maybe_cluster_id { + Some(cluster_id) => { + carl.cluster.get_cluster_configuration(cluster_id).await + .map(|configuration| { + UserClusterConfiguration { + id: cluster_id, + name: UserInputValue::Right(configuration.name.value()), + devices: DeviceSelection::Right(configuration.devices), + leader: LeaderSelection::Right(configuration.leader), + } + }) + .map_err(|error| format!("Error while loading cluster configuration: {error}")) + } + None => { + Err(String::from("Could not parse the provided value as ClusterId!")) + } } } - }; + }) + }; - let user_configuration = RwSignal::new(UserClusterConfiguration { - id: cluster_id, - name: UserInputValue::Left(UserInputError::from("Enter a valid cluster name.")), - devices: DeviceSelection::Left(String::from("Select at least two devices.")), - leader: LeaderSelection::Left(String::from("Select a leader.")), - }); + view! { + + {move || Suspend::new(async move { + let cluster_configuration = load_cluster_configuration.await; - let carl = globals.client.clone(); + match cluster_configuration { + Ok(cluster_configuration) => Either::Right(view! { + + }), - LocalResource::new(move || { - let mut carl = carl.clone(); - async move { - if let Ok(configuration) = carl.cluster.get_cluster_configuration(cluster_id).await { - user_configuration.update(|user_configuration| { - user_configuration.name = UserInputValue::Right(configuration.name.value()); - user_configuration.devices = DeviceSelection::Right(configuration.devices); - user_configuration.leader = LeaderSelection::Right(configuration.leader); - }); - } + Err(error) => Either::Left({ + let use_navigate = use_navigate(); + + navigate_to(WellKnownRoutes::ErrorPage { + title: String::from("Error while loading Cluster overview"), + text: String::from(error), + details: None, + }, use_navigate); + }) } - }); + })} + + } +} - user_configuration - }; +#[component] +fn LoadedClusterConfigurator( + loaded: UserClusterConfiguration, +) -> impl IntoView { + let globals = use_app_globals(); + + let cluster_configuration = RwSignal::new(loaded); let cluster_id = create_read_slice(cluster_configuration, |config| config.id); @@ -83,6 +101,8 @@ pub fn ClusterConfigurator() -> impl IntoView { ] }); + let active_tab = use_active_tab::(); + let cluster_deployments = { let carl = globals.client.clone(); LocalResource::new(move || { @@ -144,13 +164,13 @@ pub fn ClusterConfigurator() -> impl IntoView {
- +
- +
- +
diff --git a/opendut-lea/src/clusters/configurator/tabs/leader.rs b/opendut-lea/src/clusters/configurator/tabs/leader.rs index 9d49b1be..4041c0e8 100644 --- a/opendut-lea/src/clusters/configurator/tabs/leader.rs +++ b/opendut-lea/src/clusters/configurator/tabs/leader.rs @@ -8,7 +8,7 @@ pub fn LeaderTab(cluster_configuration: RwSignal) -> i view! {
- +
} -} \ No newline at end of file +} diff --git a/opendut-lea/src/clusters/overview.rs b/opendut-lea/src/clusters/overview.rs index f6f63160..e46c1243 100644 --- a/opendut-lea/src/clusters/overview.rs +++ b/opendut-lea/src/clusters/overview.rs @@ -9,7 +9,7 @@ use opendut_types::cluster::{ClusterConfiguration, ClusterDeployment, ClusterId} use crate::app::use_app_globals; use crate::clusters::components::CreateClusterButton; -use crate::components::{BasePageContainer, Breadcrumb, ButtonColor, ButtonSize, ButtonState, FontAwesomeIcon, health, IconButton, Toast, use_toaster}; +use crate::components::{health, use_toaster, BasePageContainer, Breadcrumb, ButtonColor, ButtonSize, ButtonState, FontAwesomeIcon, IconButton, LoadingSpinner, Toast}; use crate::components::health::Health; #[component] @@ -165,7 +165,7 @@ pub fn ClustersOverview() -> impl IntoView { } > "Loading..."

} + fallback=LoadingSpinner > {move || { let rows = rows.clone(); diff --git a/opendut-lea/src/components/authenticated.rs b/opendut-lea/src/components/authenticated.rs index bb299910..5d708e0c 100644 --- a/opendut-lea/src/components/authenticated.rs +++ b/opendut-lea/src/components/authenticated.rs @@ -6,7 +6,7 @@ use leptos_oidc::Auth; use opendut_auth::public::OptionalAuthData; use tracing::info; use opendut_carl_api::carl::wasm::CarlClient; -use crate::app::{use_app_globals, AppConfig, AppGlobals, AppGlobalsError}; +use crate::{app::{use_app_globals, AppConfig, AppGlobals, AppGlobalsError}, components::LoadingSpinner}; #[must_use] #[component(transparent)] @@ -29,6 +29,7 @@ pub fn Initialized( let maybe_auth = match config.auth_parameters { Some(ref auth_parameters) => { info!("Auth parameters: {auth_parameters:?}"); + let auth = Auth::init(auth_parameters.clone()).await; Some(auth) }, @@ -49,7 +50,7 @@ pub fn Initialized( view! { } + fallback=LoadingSpinner > {move || Suspend::new(async move { let app_globals_result = globals.await; @@ -83,7 +84,7 @@ pub fn Initialized( } #[component] -pub fn InitializedAndAuthenticated( +fn InitializedAndAuthenticated( children: ChildrenFn, #[prop(optional)] _groups: Vec, #[prop(optional)] _roles: Vec, @@ -113,7 +114,6 @@ pub fn InitializedAndAuthenticated( {children.read_value()()} }.into_any() - } } } diff --git a/opendut-lea/src/components/loading_spinner.rs b/opendut-lea/src/components/loading_spinner.rs new file mode 100644 index 00000000..ef13ab56 --- /dev/null +++ b/opendut-lea/src/components/loading_spinner.rs @@ -0,0 +1,12 @@ +use leptos::prelude::*; + +#[component] +pub fn LoadingSpinner() -> impl IntoView { + view! { +
+ + + +
+ } +} diff --git a/opendut-lea/src/components/mod.rs b/opendut-lea/src/components/mod.rs index 5996e978..9e6285bc 100644 --- a/opendut-lea/src/components/mod.rs +++ b/opendut-lea/src/components/mod.rs @@ -11,6 +11,7 @@ pub use inputs::readonly_input::ReadOnlyInput; pub use inputs::user_input::UserInput; pub use inputs::user_textarea::UserTextarea; pub use inputs::vector_user_input::VectorUserInput; +pub use loading_spinner::LoadingSpinner; pub use page::BasePageContainer; pub use toast::{Toast, ToastContent, Toaster, ToastKind, use_toaster}; pub use util::ButtonStateSignalProvider; @@ -27,6 +28,7 @@ mod breadcrumbs; mod doorhanger; mod generate_setup_string; mod inputs; +mod loading_spinner; mod page; mod toast; mod util; diff --git a/opendut-lea/src/licenses/overview.rs b/opendut-lea/src/licenses/overview.rs index b81aa476..5cbf7dee 100644 --- a/opendut-lea/src/licenses/overview.rs +++ b/opendut-lea/src/licenses/overview.rs @@ -4,6 +4,7 @@ use leptos::prelude::*; use crate::api::ApiError; use crate::api::ComponentLicenses; use crate::components::BasePageContainer; +use crate::components::LoadingSpinner; #[component] pub fn LicensesOverview() -> impl IntoView { @@ -87,14 +88,3 @@ pub fn LicensesOverview() -> impl IntoView { } } - -#[component] -fn LoadingSpinner() -> impl IntoView { - view! { -
- - - -
- } -} diff --git a/opendut-lea/src/nav.rs b/opendut-lea/src/nav.rs index 2cace81b..6e84506f 100644 --- a/opendut-lea/src/nav.rs +++ b/opendut-lea/src/nav.rs @@ -122,7 +122,7 @@ pub fn Navbar() -> impl IntoView { } }> - + "Sign out" diff --git a/opendut-lea/src/peers/overview.rs b/opendut-lea/src/peers/overview.rs index b3de1b0f..1c4f32b0 100644 --- a/opendut-lea/src/peers/overview.rs +++ b/opendut-lea/src/peers/overview.rs @@ -1,5 +1,5 @@ use crate::app::use_app_globals; -use crate::components::health; +use crate::components::{health, LoadingSpinner}; use crate::components::health::Health; use crate::components::{BasePageContainer, Breadcrumb, ButtonColor, ButtonSize, ButtonState, FontAwesomeIcon, IconButton}; use crate::peers::components::CreatePeerButton; @@ -96,7 +96,7 @@ pub fn PeersOverview() -> impl IntoView { >
"Loading..."

} + fallback=LoadingSpinner > {move || { Suspend::new(async move { diff --git a/opendut-lea/src/routing.rs b/opendut-lea/src/routing.rs index b6207f17..63cf8127 100644 --- a/opendut-lea/src/routing.rs +++ b/opendut-lea/src/routing.rs @@ -90,35 +90,35 @@ mod routes { } + view=|| view! { } /> } + view=|| view! { } /> } + view=|| view! { } /> } + view=|| view! { } /> } + view=|| view! { } /> } + view=|| view! { } /> } + view=|| view! { } /> } + view=|| view! { } />