use yew::prelude::*; use wasm_bindgen::JsCast; use wasm_bindgen_futures::spawn_local; use gloo::console; use hero_supervisor_openrpc_client::wasm::{WasmSupervisorClient, WasmJob}; #[derive(Clone, PartialEq)] pub struct SupervisorInfo { pub server_url: String, pub admin_secrets_count: usize, pub user_secrets_count: usize, pub register_secrets_count: usize, pub runners_count: usize, } #[derive(Clone, PartialEq, Debug)] pub enum SessionSecretType { None, User, Admin, } #[derive(Properties, PartialEq)] pub struct SidebarProps { pub server_url: String, pub supervisor_info: Option, pub session_secret: String, pub session_secret_type: SessionSecretType, pub on_session_secret_change: Callback<(String, SessionSecretType)>, pub on_supervisor_info_loaded: Callback, } #[function_component(Sidebar)] pub fn sidebar(props: &SidebarProps) -> Html { let session_secret_input = use_state(|| String::new()); let payload_input = use_state(|| String::new()); let admin_secrets = use_state(|| Vec::::new()); let user_secrets = use_state(|| Vec::::new()); let register_secrets = use_state(|| Vec::::new()); let is_loading = use_state(|| false); let on_session_secret_change = { let session_secret_input = session_secret_input.clone(); Callback::from(move |e: web_sys::Event| { let input: web_sys::HtmlInputElement = e.target().unwrap().dyn_into().unwrap(); session_secret_input.set(input.value()); }) }; let on_session_secret_submit = { let session_secret_input = session_secret_input.clone(); let is_loading = is_loading.clone(); let admin_secrets = admin_secrets.clone(); let user_secrets = user_secrets.clone(); let register_secrets = register_secrets.clone(); let server_url = props.server_url.clone(); let on_session_secret_change = props.on_session_secret_change.clone(); Callback::from(move |_: web_sys::MouseEvent| { let secret = (*session_secret_input).clone(); if secret.is_empty() { return; } is_loading.set(true); let client = WasmSupervisorClient::new(server_url.clone()); let session_secret_input = session_secret_input.clone(); let is_loading = is_loading.clone(); let admin_secrets = admin_secrets.clone(); let user_secrets = user_secrets.clone(); let register_secrets = register_secrets.clone(); let on_session_secret_change = on_session_secret_change.clone(); spawn_local(async move { // Try to get admin secrets first to determine if this is an admin secret match client.list_admin_secrets(&secret).await { Ok(admin_secret_list) => { // This is an admin secret admin_secrets.set(admin_secret_list); // Also load user and register secrets if let Ok(user_secret_list) = client.list_user_secrets(&secret).await { user_secrets.set(user_secret_list); } if let Ok(register_secret_list) = client.list_register_secrets(&secret).await { register_secrets.set(register_secret_list); } on_session_secret_change.emit((secret, SessionSecretType::Admin)); console::log!("Admin session established"); } Err(_) => { // Try as user secret - just test if we can make any call with it match client.list_runners().await { Ok(_) => { // This appears to be a valid user secret on_session_secret_change.emit((secret, SessionSecretType::User)); console::log!("User session established"); } Err(e) => { console::log!("Invalid secret:", format!("{:?}", e)); on_session_secret_change.emit((String::new(), SessionSecretType::None)); } } } } is_loading.set(false); session_secret_input.set(String::new()); }); }) }; let on_session_clear = { let on_session_secret_change = props.on_session_secret_change.clone(); let admin_secrets = admin_secrets.clone(); let user_secrets = user_secrets.clone(); let register_secrets = register_secrets.clone(); Callback::from(move |_: web_sys::MouseEvent| { on_session_secret_change.emit((String::new(), SessionSecretType::None)); admin_secrets.set(Vec::new()); user_secrets.set(Vec::new()); register_secrets.set(Vec::new()); console::log!("Session cleared"); }) }; let on_payload_change = { let payload_input = payload_input.clone(); Callback::from(move |e: web_sys::Event| { let input: web_sys::HtmlInputElement = e.target().unwrap().dyn_into().unwrap(); payload_input.set(input.value()); }) }; let on_run_click = { let payload_input = payload_input.clone(); let server_url = props.server_url.clone(); let session_secret = props.session_secret.clone(); let is_loading = is_loading.clone(); Callback::from(move |_: web_sys::MouseEvent| { let payload = (*payload_input).clone(); if payload.is_empty() || session_secret.is_empty() { return; } is_loading.set(true); let client = WasmSupervisorClient::new(server_url.clone()); let payload_input = payload_input.clone(); let is_loading = is_loading.clone(); let session_secret = session_secret.clone(); spawn_local(async move { // Create WasmJob object using constructor let job = WasmJob::new( uuid::Uuid::new_v4().to_string(), payload.clone(), "osis".to_string(), "default".to_string(), ); match client.create_job(session_secret.clone(), job).await { Ok(job_id) => { console::log!("Job created successfully:", job_id); payload_input.set(String::new()); } Err(e) => { console::log!("Failed to create job:", format!("{:?}", e)); } } is_loading.set(false); }); }) }; html! { } }