perspective_viewer/components/
status_indicator.rs1use perspective_client::config::ViewConfigUpdate;
14use perspective_js::utils::ApiError;
15use web_sys::*;
16use yew::prelude::*;
17
18use crate::renderer::Renderer;
19use crate::session::{Session, SessionProps, TableLoadState};
20use crate::tasks::apply_and_render;
21use crate::utils::*;
22
23#[derive(PartialEq, Properties)]
28pub struct StatusIndicatorProps {
29 pub renderer: Renderer,
30 pub session: Session,
31
32 pub update_count: u32,
34 pub session_props: SessionProps,
35}
36
37#[function_component]
41pub fn StatusIndicator(props: &StatusIndicatorProps) -> Html {
42 let has_table_cells = props.session_props.has_table_cells;
43 let state = if let Some(err) = &props.session_props.error {
44 StatusIconState::Errored(
45 err.message(),
46 err.stacktrace(),
47 err.kind(),
48 err.is_reconnect(),
49 )
50 } else if !has_table_cells
51 && matches!(props.session_props.has_table, Some(TableLoadState::Loading))
52 {
53 StatusIconState::Loading
54 } else if props.update_count > 0 {
55 StatusIconState::Updating
56 } else if has_table_cells {
57 StatusIconState::Normal
58 } else {
59 StatusIconState::Uninitialized
60 };
61
62 let class_name = match &state {
63 StatusIconState::Errored(_, _, _, true) => "errored",
64 StatusIconState::Errored(_, _, _, false) => "errored disabled",
65 StatusIconState::Normal => "connected",
66 StatusIconState::Updating => "updating",
67 StatusIconState::Loading => "loading",
68 StatusIconState::Uninitialized => "uninitialized",
69 };
70
71 let onclick = use_async_callback(
72 (props.session.clone(), props.renderer.clone(), state.clone()),
73 async move |_: MouseEvent, (session, renderer, state)| {
74 match &state {
75 StatusIconState::Errored(..) => {
76 session.reconnect().await?;
77 apply_and_render(session, renderer, ViewConfigUpdate::default())?.await?;
78 },
79 StatusIconState::Normal => {
80 session.status_indicator_clicked.emit(());
81 },
82 _ => {},
83 };
84
85 Ok::<_, ApiError>(())
86 },
87 );
88
89 html! {
90 <>
91 <div class="section">
92 <div id="status_reconnect" class={class_name} {onclick}>
93 <span id="status" class={class_name} />
94 <span id="status_updating" class={class_name} />
95 </div>
96 if let StatusIconState::Errored(err, stack, kind, _) = &state {
97 <div class="error-dialog">
98 <div class="error-dialog-message">{ format!("{} {}", kind, err) }</div>
99 <div class="error-dialog-stack">{ stack }</div>
100 </div>
101 }
102 </div>
103 </>
104 }
105}
106
107#[derive(Clone, Debug, PartialEq)]
108enum StatusIconState {
109 Loading,
110 Updating,
111 Errored(String, String, &'static str, bool),
112 Normal,
113 Uninitialized,
114}