use perspective_client::config::ViewConfigUpdate;
use perspective_js::utils::ApiError;
use wasm_bindgen::JsValue;
use web_sys::*;
use yew::prelude::*;
use crate::custom_events::CustomEvents;
use crate::renderer::Renderer;
use crate::session::{Session, TableErrorState, TableLoadState, ViewStats};
use crate::utils::*;
#[derive(PartialEq, Properties)]
pub struct StatusIndicatorProps {
pub custom_events: CustomEvents,
pub renderer: Renderer,
pub session: Session,
pub update_count: u32,
pub error: Option<TableErrorState>,
pub has_table: Option<TableLoadState>,
pub stats: Option<ViewStats>,
}
#[function_component]
pub fn StatusIndicator(props: &StatusIndicatorProps) -> Html {
let has_table_cells = props
.stats
.as_ref()
.and_then(|s| s.num_table_cells)
.is_some();
let state = if let Some(err) = &props.error {
StatusIconState::Errored(
err.message(),
err.stacktrace(),
err.kind(),
err.is_reconnect(),
)
} else if !has_table_cells && matches!(props.has_table, Some(TableLoadState::Loading)) {
StatusIconState::Loading
} else if props.update_count > 0 {
StatusIconState::Updating
} else if has_table_cells {
StatusIconState::Normal
} else {
StatusIconState::Uninitialized
};
let class_name = match &state {
StatusIconState::Errored(_, _, _, true) => "errored",
StatusIconState::Errored(_, _, _, false) => "errored disabled",
StatusIconState::Normal => "connected",
StatusIconState::Updating => "updating",
StatusIconState::Loading => "loading",
StatusIconState::Uninitialized => "uninitialized",
};
let onclick = use_async_callback(
(
props.session.clone(),
props.renderer.clone(),
props.custom_events.clone(),
state.clone(),
),
async move |_: MouseEvent, (session, renderer, custom_events, state)| {
match &state {
StatusIconState::Errored(..) => {
session.reconnect().await?;
let cfg = ViewConfigUpdate::default();
session.update_view_config(cfg)?;
renderer.apply_pending_plugin()?;
renderer
.draw(session.validate().await?.create_view())
.await?;
},
StatusIconState::Normal => {
custom_events.dispatch_event("status-indicator-click", JsValue::UNDEFINED)?;
},
_ => {},
};
Ok::<_, ApiError>(())
},
);
html! {
<>
<div class="section">
<div id="status_reconnect" class={class_name} {onclick}>
<span id="status" class={class_name} />
<span id="status_updating" class={class_name} />
</div>
if let StatusIconState::Errored(err, stack, kind, _) = &state {
<div class="error-dialog">
<div class="error-dialog-message">{ format!("{} {}", kind, err) }</div>
<div class="error-dialog-stack">{ stack }</div>
</div>
}
</div>
</>
}
}
#[derive(Clone, Debug, PartialEq)]
enum StatusIconState {
Loading,
Updating,
Errored(String, String, &'static str, bool),
Normal,
Uninitialized,
}