212 lines
9.3 KiB
Rust
212 lines
9.3 KiB
Rust
|
|
use gloo_storage::{LocalStorage, Storage};
|
||
|
|
use leptos::prelude::*;
|
||
|
|
use leptos::task::spawn_local;
|
||
|
|
|
||
|
|
use crate::api::client;
|
||
|
|
use crate::components::onboarding::{NextSteps, SystemStatus, WelcomeWizard};
|
||
|
|
use crate::config::use_config;
|
||
|
|
|
||
|
|
#[component]
|
||
|
|
pub fn DashboardPage() -> impl IntoView {
|
||
|
|
// Check if onboarding is complete
|
||
|
|
let (show_wizard, set_show_wizard) = signal(false);
|
||
|
|
let (show_onboarding_section, set_show_onboarding_section) = signal(true);
|
||
|
|
|
||
|
|
// Check onboarding status on mount
|
||
|
|
Effect::new(move |_| {
|
||
|
|
let onboarding_complete = LocalStorage::get::<bool>("onboarding_complete").unwrap_or(false);
|
||
|
|
|
||
|
|
if !onboarding_complete {
|
||
|
|
set_show_wizard.set(true);
|
||
|
|
}
|
||
|
|
set_show_onboarding_section.set(!onboarding_complete);
|
||
|
|
});
|
||
|
|
|
||
|
|
// Reactive signals for service status
|
||
|
|
let (orchestrator_status, set_orchestrator_status) = signal(String::from("Loading..."));
|
||
|
|
let (orchestrator_color, set_orchestrator_color) = signal(String::from("#999"));
|
||
|
|
let (control_center_status, set_control_center_status) = signal(String::from("Loading..."));
|
||
|
|
let (control_center_color, set_control_center_color) = signal(String::from("#999"));
|
||
|
|
let (active_tasks, set_active_tasks) = signal(0usize);
|
||
|
|
|
||
|
|
// Signals for onboarding status checks
|
||
|
|
let (workspace_exists, set_workspace_exists) = signal(false);
|
||
|
|
let (servers_exist, set_servers_exist) = signal(false);
|
||
|
|
let (taskservs_exist, set_taskservs_exist) = signal(false);
|
||
|
|
|
||
|
|
// Fetch orchestrator health
|
||
|
|
Effect::new(move |_| {
|
||
|
|
spawn_local(async move {
|
||
|
|
match client::fetch_orchestrator_health().await {
|
||
|
|
Ok(health) => {
|
||
|
|
set_orchestrator_status.set(format!("✅ {}", health.status));
|
||
|
|
set_orchestrator_color.set(String::from("#10b981"));
|
||
|
|
}
|
||
|
|
Err(e) => {
|
||
|
|
set_orchestrator_status.set(format!("❌ Error: {}", e));
|
||
|
|
set_orchestrator_color.set(String::from("#ef4444"));
|
||
|
|
}
|
||
|
|
}
|
||
|
|
});
|
||
|
|
});
|
||
|
|
|
||
|
|
// Fetch control-center health
|
||
|
|
Effect::new(move |_| {
|
||
|
|
spawn_local(async move {
|
||
|
|
match client::fetch_control_center_health().await {
|
||
|
|
Ok(health) => {
|
||
|
|
set_control_center_status.set(format!("✅ {}", health.status));
|
||
|
|
set_control_center_color.set(String::from("#10b981"));
|
||
|
|
}
|
||
|
|
Err(e) => {
|
||
|
|
set_control_center_status.set(format!("❌ Error: {}", e));
|
||
|
|
set_control_center_color.set(String::from("#ef4444"));
|
||
|
|
}
|
||
|
|
}
|
||
|
|
});
|
||
|
|
});
|
||
|
|
|
||
|
|
// Fetch active tasks
|
||
|
|
Effect::new(move |_| {
|
||
|
|
spawn_local(async move {
|
||
|
|
match client::fetch_tasks().await {
|
||
|
|
Ok(tasks_response) => {
|
||
|
|
set_active_tasks.set(tasks_response.tasks.len());
|
||
|
|
}
|
||
|
|
Err(e) => {
|
||
|
|
web_sys::console::warn_1(&format!("Failed to fetch tasks: {}", e).into());
|
||
|
|
set_active_tasks.set(0);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
});
|
||
|
|
});
|
||
|
|
|
||
|
|
// Get config for URLs
|
||
|
|
let config = use_config();
|
||
|
|
|
||
|
|
view! {
|
||
|
|
// Welcome Wizard (shows on first visit)
|
||
|
|
<Show when=move || show_wizard.get()>
|
||
|
|
<WelcomeWizard
|
||
|
|
on_complete=Callback::new(move |_| {
|
||
|
|
set_show_wizard.set(false);
|
||
|
|
set_show_onboarding_section.set(false);
|
||
|
|
})
|
||
|
|
on_skip=Callback::new(move |_| {
|
||
|
|
set_show_wizard.set(false);
|
||
|
|
})
|
||
|
|
/>
|
||
|
|
</Show>
|
||
|
|
|
||
|
|
<div class="dashboard-page" style="padding: 20px;">
|
||
|
|
<h1 style="font-size: 2rem; margin-bottom: 20px; color: #333;">
|
||
|
|
"📊 Dashboard"
|
||
|
|
</h1>
|
||
|
|
|
||
|
|
<div style="display: grid; grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); gap: 20px; margin-bottom: 20px;">
|
||
|
|
// Orchestrator Status Card
|
||
|
|
<div style="background: white; padding: 20px; border-radius: 8px; box-shadow: 0 2px 4px rgba(0,0,0,0.1);">
|
||
|
|
<h3 style="margin: 0 0 10px 0; color: #666; font-size: 0.9rem;">
|
||
|
|
"Orchestrator Status"
|
||
|
|
</h3>
|
||
|
|
<p style=move || format!("font-size: 1.5rem; margin: 0; color: {};", orchestrator_color.get())>
|
||
|
|
{move || orchestrator_status.get()}
|
||
|
|
</p>
|
||
|
|
<p style="margin: 10px 0 0 0; color: #999; font-size: 0.85rem;">
|
||
|
|
{config.api.orchestrator_url.clone()}
|
||
|
|
</p>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
// Control Center Status Card
|
||
|
|
<div style="background: white; padding: 20px; border-radius: 8px; box-shadow: 0 2px 4px rgba(0,0,0,0.1);">
|
||
|
|
<h3 style="margin: 0 0 10px 0; color: #666; font-size: 0.9rem;">
|
||
|
|
"Control Center Status"
|
||
|
|
</h3>
|
||
|
|
<p style=move || format!("font-size: 1.5rem; margin: 0; color: {};", control_center_color.get())>
|
||
|
|
{move || control_center_status.get()}
|
||
|
|
</p>
|
||
|
|
<p style="margin: 10px 0 0 0; color: #999; font-size: 0.85rem;">
|
||
|
|
{config.api.control_center_url.clone()}
|
||
|
|
</p>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
// Workflows Card
|
||
|
|
<div style="background: white; padding: 20px; border-radius: 8px; box-shadow: 0 2px 4px rgba(0,0,0,0.1);">
|
||
|
|
<h3 style="margin: 0 0 10px 0; color: #666; font-size: 0.9rem;">
|
||
|
|
"Active Tasks"
|
||
|
|
</h3>
|
||
|
|
<p style="font-size: 1.5rem; margin: 0; color: #3b82f6;">
|
||
|
|
{move || active_tasks.get().to_string()}
|
||
|
|
</p>
|
||
|
|
<p style="margin: 10px 0 0 0; color: #999; font-size: 0.85rem;">
|
||
|
|
{move || if active_tasks.get() == 0 {
|
||
|
|
"No tasks running"
|
||
|
|
} else if active_tasks.get() == 1 {
|
||
|
|
"1 task running"
|
||
|
|
} else {
|
||
|
|
"tasks running"
|
||
|
|
}}
|
||
|
|
</p>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
<div style="background: white; padding: 20px; border-radius: 8px; box-shadow: 0 2px 4px rgba(0,0,0,0.1);">
|
||
|
|
<h2 style="margin: 0 0 15px 0; font-size: 1.3rem; color: #333;">
|
||
|
|
"🚀 Quick Actions"
|
||
|
|
</h2>
|
||
|
|
<div style="display: flex; gap: 10px; flex-wrap: wrap;">
|
||
|
|
<a href="/servers" style="padding: 10px 20px; background: #3b82f6; color: white; text-decoration: none; border-radius: 6px; font-weight: 500;">
|
||
|
|
"Manage Servers"
|
||
|
|
</a>
|
||
|
|
<a href="/workflows" style="padding: 10px 20px; background: #10b981; color: white; text-decoration: none; border-radius: 6px; font-weight: 500;">
|
||
|
|
"View Workflows"
|
||
|
|
</a>
|
||
|
|
<a href="/taskservs" style="padding: 10px 20px; background: #8b5cf6; color: white; text-decoration: none; border-radius: 6px; font-weight: 500;">
|
||
|
|
"Task Services"
|
||
|
|
</a>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
// Onboarding sections (show if not completed)
|
||
|
|
<Show when=move || show_onboarding_section.get()>
|
||
|
|
<div style="margin-top: 30px;">
|
||
|
|
<SystemStatus auto_refresh=true />
|
||
|
|
</div>
|
||
|
|
|
||
|
|
<div style="margin-top: 30px;">
|
||
|
|
<NextSteps
|
||
|
|
workspace_exists=workspace_exists
|
||
|
|
servers_exist=servers_exist
|
||
|
|
taskservs_exist=taskservs_exist
|
||
|
|
/>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
<div style="margin-top: 20px; padding: 15px; background: #fef3c7; border-radius: 8px; border-left: 4px solid #f59e0b;">
|
||
|
|
<div style="display: flex; align-items: start; gap: 15px;">
|
||
|
|
<div style="font-size: 1.5rem;">
|
||
|
|
"💡"
|
||
|
|
</div>
|
||
|
|
<div style="flex: 1;">
|
||
|
|
<p style="margin: 0 0 10px 0; color: #92400e; font-weight: 600;">
|
||
|
|
"New to the platform?"
|
||
|
|
</p>
|
||
|
|
<p style="margin: 0 0 12px 0; color: #78350f; line-height: 1.6;">
|
||
|
|
"Complete the welcome wizard to set up your first infrastructure. You can restart it anytime from Settings."
|
||
|
|
</p>
|
||
|
|
<button
|
||
|
|
on:click=move |_| {
|
||
|
|
LocalStorage::delete("onboarding_complete");
|
||
|
|
set_show_wizard.set(true);
|
||
|
|
}
|
||
|
|
style="padding: 8px 16px; background: #f59e0b; color: white; border: none; border-radius: 6px; cursor: pointer; font-weight: 500;"
|
||
|
|
>
|
||
|
|
"Restart Welcome Wizard"
|
||
|
|
</button>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
</Show>
|
||
|
|
</div>
|
||
|
|
}
|
||
|
|
}
|