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! { }
/>