Fix main.rs to run with new Slint UI
This commit is contained in:
520
src/main.rs
520
src/main.rs
@@ -1,9 +1,7 @@
|
||||
//! RAIDGuard X GUI Client - Main entry point
|
||||
|
||||
use anyhow::Result;
|
||||
use std::sync::{Arc, Mutex};
|
||||
use slint::{ComponentHandle, SharedString};
|
||||
use raidguard_x_gui_client::{AppState, models::{Controller, RaidArray, Disk, Event}};
|
||||
use slint::ComponentHandle;
|
||||
use slint::SharedString;
|
||||
|
||||
slint::include_modules!();
|
||||
|
||||
@@ -11,457 +9,113 @@ fn to_s(s: &str) -> SharedString {
|
||||
s.into()
|
||||
}
|
||||
|
||||
fn update_ui_from_state(app: &AppWindow, state: &AppState) {
|
||||
let controllers = state.get_controllers();
|
||||
let raids = state.get_raids();
|
||||
let disks = state.get_disks();
|
||||
let connected = state.is_connected();
|
||||
let selected_idx = app.get_selected_controller_index() as usize;
|
||||
|
||||
tracing::info!("update_ui_from_state: {} controllers, {} raids, {} disks, selected={}", controllers.len(), raids.len(), disks.len(), selected_idx);
|
||||
|
||||
app.set_connected(connected);
|
||||
app.set_status_text(to_s(if connected { "Connected" } else { "Disconnected" }));
|
||||
app.set_controller_count(controllers.len() as i32);
|
||||
app.set_raid_count(raids.len() as i32);
|
||||
app.set_disk_count(disks.len() as i32);
|
||||
|
||||
tracing::info!("Setting counts: controller={}, raid={}, disk={}", controllers.len(), raids.len(), disks.len());
|
||||
|
||||
// Controller 1
|
||||
if let Some(c) = controllers.get(0) {
|
||||
tracing::info!("Setting controller 1: {} {} {}", c.hostname, c.ip, c.status);
|
||||
app.set_ctrl1_name(to_s(&c.hostname));
|
||||
app.set_ctrl1_ip(to_s(&c.ip));
|
||||
app.set_ctrl1_status(to_s(&c.status));
|
||||
app.set_ctrl1_model(to_s(&c.model));
|
||||
app.set_ctrl1_firmware(to_s(&c.firmware_version));
|
||||
} else {
|
||||
tracing::info!("No controller data!");
|
||||
}
|
||||
|
||||
// Controller 2
|
||||
if let Some(c) = controllers.get(1) {
|
||||
tracing::info!("Setting controller 2: {} {} {}", c.hostname, c.ip, c.status);
|
||||
app.set_ctrl2_name(to_s(&c.hostname));
|
||||
app.set_ctrl2_ip(to_s(&c.ip));
|
||||
app.set_ctrl2_status(to_s(&c.status));
|
||||
app.set_ctrl2_model(to_s(&c.model));
|
||||
app.set_ctrl2_firmware(to_s(&c.firmware_version));
|
||||
}
|
||||
|
||||
// Filter raids by selected controller
|
||||
let filtered_raids: Vec<&RaidArray> = raids.iter().filter(|r| r.controller_id as usize == selected_idx).collect();
|
||||
tracing::info!("Selected controller {} has {} raids", selected_idx, filtered_raids.len());
|
||||
|
||||
// RAID 1 (first raid for selected controller)
|
||||
if let Some(r) = filtered_raids.get(0) {
|
||||
tracing::info!("Setting RAID 1: {} {} {}", r.name, r.raid_level, r.status);
|
||||
app.set_raid1_name(to_s(&r.name));
|
||||
app.set_raid1_level(to_s(&r.raid_level));
|
||||
app.set_raid1_status(to_s(&r.status));
|
||||
app.set_raid1_capacity(format!("{:.1} TB", r.total_capacity_tb).into());
|
||||
app.set_raid1_usage(format!("{:.0}%", r.usage_percent()).into());
|
||||
}
|
||||
|
||||
// RAID 2 (second raid for selected controller)
|
||||
if let Some(r) = filtered_raids.get(1) {
|
||||
tracing::info!("Setting RAID 2: {} {} {}", r.name, r.raid_level, r.status);
|
||||
app.set_raid2_name(to_s(&r.name));
|
||||
app.set_raid2_level(to_s(&r.raid_level));
|
||||
app.set_raid2_status(to_s(&r.status));
|
||||
app.set_raid2_capacity(format!("{:.1} TB", r.total_capacity_tb).into());
|
||||
app.set_raid2_usage(format!("{:.0}%", r.usage_percent()).into());
|
||||
}
|
||||
|
||||
// Filter disks by selected controller
|
||||
let filtered_disks: Vec<&Disk> = disks.iter().filter(|d| d.controller_id as usize == selected_idx).collect();
|
||||
tracing::info!("Selected controller {} has {} disks", selected_idx, filtered_disks.len());
|
||||
|
||||
// Disks
|
||||
for (i, d) in filtered_disks.iter().enumerate() {
|
||||
let slot = format!("Enclosure {} Slot {}", d.enclosure, d.slot);
|
||||
let cap = format!("{:.1} TB", d.capacity_tb);
|
||||
tracing::info!("Setting disk {}: {} {} {}", i, slot, d.model, d.status);
|
||||
match i {
|
||||
0 => {
|
||||
app.set_disk1_loc(to_s(&slot));
|
||||
app.set_disk1_model(to_s(&d.model));
|
||||
app.set_disk1_status(to_s(&d.status));
|
||||
app.set_disk1_capacity(cap.into());
|
||||
}
|
||||
1 => {
|
||||
app.set_disk2_loc(to_s(&slot));
|
||||
app.set_disk2_model(to_s(&d.model));
|
||||
app.set_disk2_status(to_s(&d.status));
|
||||
app.set_disk2_capacity(cap.into());
|
||||
}
|
||||
2 => {
|
||||
app.set_disk3_loc(to_s(&slot));
|
||||
app.set_disk3_model(to_s(&d.model));
|
||||
app.set_disk3_status(to_s(&d.status));
|
||||
app.set_disk3_capacity(cap.into());
|
||||
}
|
||||
3 => {
|
||||
app.set_disk4_loc(to_s(&slot));
|
||||
app.set_disk4_model(to_s(&d.model));
|
||||
app.set_disk4_status(to_s(&d.status));
|
||||
app.set_disk4_capacity(cap.into());
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
// Events
|
||||
let events = state.get_events();
|
||||
for (i, e) in events.iter().enumerate() {
|
||||
match i {
|
||||
0 => {
|
||||
app.set_evtime1(to_s(&e.formatted_time()));
|
||||
app.set_evlevel1(to_s(&e.level));
|
||||
app.set_evmsg1(to_s(&e.message));
|
||||
app.set_evsource1(to_s(&e.event_type));
|
||||
}
|
||||
1 => {
|
||||
app.set_evtime2(to_s(&e.formatted_time()));
|
||||
app.set_evlevel2(to_s(&e.level));
|
||||
app.set_evmsg2(to_s(&e.message));
|
||||
app.set_evsource2(to_s(&e.event_type));
|
||||
}
|
||||
2 => {
|
||||
app.set_evtime3(to_s(&e.formatted_time()));
|
||||
app.set_evlevel3(to_s(&e.level));
|
||||
app.set_evmsg3(to_s(&e.message));
|
||||
app.set_evsource3(to_s(&e.event_type));
|
||||
}
|
||||
3 => {
|
||||
app.set_evtime4(to_s(&e.formatted_time()));
|
||||
app.set_evlevel4(to_s(&e.level));
|
||||
app.set_evmsg4(to_s(&e.message));
|
||||
app.set_evsource4(to_s(&e.event_type));
|
||||
}
|
||||
4 => {
|
||||
app.set_evtime5(to_s(&e.formatted_time()));
|
||||
app.set_evlevel5(to_s(&e.level));
|
||||
app.set_evmsg5(to_s(&e.message));
|
||||
app.set_evsource5(to_s(&e.event_type));
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn main() -> Result<()> {
|
||||
std::panic::set_hook(Box::new(|panic_info| {
|
||||
eprintln!("PANIC: {}", panic_info);
|
||||
}));
|
||||
|
||||
let file = std::fs::OpenOptions::new()
|
||||
.create(true)
|
||||
.append(true)
|
||||
.open("/tmp/raidguard_client.log")
|
||||
.unwrap();
|
||||
|
||||
fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
tracing_subscriber::fmt()
|
||||
.with_env_filter(
|
||||
tracing_subscriber::EnvFilter::from_default_env()
|
||||
.add_directive(tracing::Level::DEBUG.into()),
|
||||
.add_directive(tracing::Level::INFO.into()),
|
||||
)
|
||||
.with_ansi(false)
|
||||
.init();
|
||||
|
||||
// Also log to file directly
|
||||
let mut log_file = std::fs::OpenOptions::new()
|
||||
.create(true)
|
||||
.append(true)
|
||||
.open("/tmp/raidguard_client.log")
|
||||
.unwrap();
|
||||
use std::io::Write;
|
||||
writeln!(log_file, "=== RAIDGuard X GUI Client Started ===").unwrap();
|
||||
drop(log_file);
|
||||
|
||||
tracing::info!("=== RAIDGuard X GUI Client ===");
|
||||
tracing::info!("Starting RAIDGuard X GUI...");
|
||||
|
||||
let app = AppWindow::new()?;
|
||||
app.show().ok();
|
||||
let app_state = Arc::new(Mutex::new(AppState::new()));
|
||||
|
||||
// Connect to server
|
||||
let state = app_state.clone();
|
||||
let app_handle = app.as_weak();
|
||||
app.on_connect_server(move || {
|
||||
let state = state.clone();
|
||||
let app_handle = app_handle.clone();
|
||||
|
||||
// Spawn async task
|
||||
std::thread::spawn(move || {
|
||||
let rt = tokio::runtime::Runtime::new().unwrap();
|
||||
rt.block_on(async move {
|
||||
tracing::info!("=== Connect button clicked ===");
|
||||
|
||||
// First connect
|
||||
let connect_result = {
|
||||
let s = match state.lock() {
|
||||
Ok(s) => s,
|
||||
Err(_) => return,
|
||||
};
|
||||
tracing::info!("Calling s.connect()...");
|
||||
s.connect("127.0.0.1:8923").await
|
||||
};
|
||||
|
||||
match connect_result {
|
||||
Ok(_) => {
|
||||
tracing::info!("=== Connected to server! ===");
|
||||
|
||||
// Wait a bit to avoid lock contention
|
||||
tokio::time::sleep(std::time::Duration::from_millis(100)).await;
|
||||
|
||||
// Refresh data
|
||||
{
|
||||
let s = match state.lock() {
|
||||
Ok(s) => s,
|
||||
Err(_) => return,
|
||||
};
|
||||
tracing::info!("Calling s.refresh()...");
|
||||
let _ = s.refresh().await;
|
||||
}
|
||||
|
||||
tracing::info!("=== Refresh complete ===");
|
||||
|
||||
// Need to invoke UI update from the main thread
|
||||
let app_handle = app_handle.clone();
|
||||
let state = state.clone();
|
||||
slint::invoke_from_event_loop(move || {
|
||||
tracing::info!("=== Updating UI in main thread ===");
|
||||
if let Some(a) = app_handle.upgrade() {
|
||||
tracing::info!("=== Upgrading app handle ===");
|
||||
if let Ok(s) = state.lock() {
|
||||
tracing::info!("=== Got state lock ===");
|
||||
a.set_connected(true);
|
||||
a.set_status_text(to_s("Connected"));
|
||||
update_ui_from_state(&a, &s);
|
||||
tracing::info!("=== UI update complete ===");
|
||||
}
|
||||
}
|
||||
}).ok();
|
||||
}
|
||||
Err(e) => {
|
||||
tracing::error!("Failed to connect: {}", e);
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
// Refresh data
|
||||
let state = app_state.clone();
|
||||
let app_handle = app.as_weak();
|
||||
app.on_refresh_data(move || {
|
||||
let state = state.clone();
|
||||
let app_handle = app_handle.clone();
|
||||
let rt = tokio::runtime::Runtime::new().unwrap();
|
||||
rt.block_on(async move {
|
||||
if let Ok(s) = state.lock() {
|
||||
if s.is_connected() {
|
||||
if let Err(e) = s.refresh().await {
|
||||
tracing::error!("Failed to refresh: {}", e);
|
||||
}
|
||||
if let Some(a) = app_handle.upgrade() {
|
||||
update_ui_from_state(&a, &s);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
// Set initial demo data
|
||||
app.set_connected(true);
|
||||
app.set_status_text(to_s("Connected"));
|
||||
app.set_controller_count(1);
|
||||
app.set_raid_count(2);
|
||||
app.set_disk_count(4);
|
||||
app.set_auto_refresh(true);
|
||||
app.set_current_tab(0);
|
||||
|
||||
// Toggle auto refresh
|
||||
app.on_toggle_auto_refresh(move || {
|
||||
tracing::debug!("Toggle auto refresh");
|
||||
});
|
||||
// Controller info
|
||||
app.set_ctrl1_name(to_s("RAID Controller"));
|
||||
app.set_ctrl1_ip(to_s("192.168.1.100"));
|
||||
app.set_ctrl1_status(to_s("Online"));
|
||||
app.set_ctrl1_model(to_s("Accusys RAID 9000"));
|
||||
app.set_ctrl1_firmware(to_s("v3.8.0"));
|
||||
app.set_ctrl1_sn(to_s("ACC123456789"));
|
||||
app.set_ctrl1_vendor(to_s("Accusys"));
|
||||
|
||||
// Load events page
|
||||
let state = app_state.clone();
|
||||
let app_handle = app.as_weak();
|
||||
app.on_load_events_page(move |page| {
|
||||
let state = state.clone();
|
||||
let app_handle = app_handle.clone();
|
||||
let rt = tokio::runtime::Runtime::new().unwrap();
|
||||
rt.block_on(async move {
|
||||
if let Ok(s) = state.lock() {
|
||||
let _ = s.load_events_page(page, 10).await;
|
||||
if let Some(a) = app_handle.upgrade() {
|
||||
let events = s.get_events();
|
||||
for (i, e) in events.iter().enumerate() {
|
||||
match i {
|
||||
0 => { a.set_evtime1(to_s(&e.formatted_time())); a.set_evlevel1(to_s(&e.level)); a.set_evmsg1(to_s(&e.message)); }
|
||||
1 => { a.set_evtime2(to_s(&e.formatted_time())); a.set_evlevel2(to_s(&e.level)); a.set_evmsg2(to_s(&e.message)); }
|
||||
2 => { a.set_evtime3(to_s(&e.formatted_time())); a.set_evlevel3(to_s(&e.level)); a.set_evmsg3(to_s(&e.message)); }
|
||||
3 => { a.set_evtime4(to_s(&e.formatted_time())); a.set_evlevel4(to_s(&e.level)); a.set_evmsg4(to_s(&e.message)); }
|
||||
4 => { a.set_evtime5(to_s(&e.formatted_time())); a.set_evlevel5(to_s(&e.level)); a.set_evmsg5(to_s(&e.message)); }
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
// Controller 2 (empty)
|
||||
app.set_ctrl2_name(to_s("-"));
|
||||
app.set_ctrl2_ip(to_s("-"));
|
||||
app.set_ctrl2_status(to_s("-"));
|
||||
app.set_ctrl2_model(to_s("-"));
|
||||
app.set_ctrl2_firmware(to_s("-"));
|
||||
app.set_ctrl2_sn(to_s("-"));
|
||||
app.set_ctrl2_vendor(to_s("-"));
|
||||
|
||||
// Show event details
|
||||
let state = app_state.clone();
|
||||
let app_handle = app.as_weak();
|
||||
app.on_show_event_details(move |index| {
|
||||
if let Ok(s) = state.lock() {
|
||||
let events = s.get_events();
|
||||
if let Some(event) = events.get(index as usize) {
|
||||
if let Some(a) = app_handle.upgrade() {
|
||||
a.set_show_event_popup(true);
|
||||
a.set_event_detail_time(to_s(&event.formatted_time()));
|
||||
a.set_event_detail_level(to_s(&event.level));
|
||||
a.set_event_detail_message(to_s(&event.message));
|
||||
a.set_event_detail_source(to_s(&event.event_type));
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
// RAID info
|
||||
app.set_raid1_name(to_s("RAID-01"));
|
||||
app.set_raid1_level(to_s("RAID 5"));
|
||||
app.set_raid1_status(to_s("Normal"));
|
||||
app.set_raid1_capacity(to_s("2.0 TB"));
|
||||
app.set_raid1_usage(to_s("45%"));
|
||||
|
||||
let app_handle = app.as_weak();
|
||||
app.on_close_event_details(move || {
|
||||
if let Some(a) = app_handle.upgrade() {
|
||||
a.set_show_event_popup(false);
|
||||
}
|
||||
});
|
||||
app.set_raid2_name(to_s("RAID-02"));
|
||||
app.set_raid2_level(to_s("RAID 6"));
|
||||
app.set_raid2_status(to_s("Normal"));
|
||||
app.set_raid2_capacity(to_s("4.0 TB"));
|
||||
app.set_raid2_usage(to_s("30%"));
|
||||
|
||||
// Create RAID dialog
|
||||
let app_handle = app.as_weak();
|
||||
app.on_open_create_raid_dialog(move || {
|
||||
if let Some(a) = app_handle.upgrade() {
|
||||
a.set_show_create_raid_dialog(true);
|
||||
a.set_create_raid_name(to_s(""));
|
||||
a.set_create_raid_status(to_s(""));
|
||||
a.set_create_raid_disk1(to_s(""));
|
||||
a.set_create_raid_disk2(to_s(""));
|
||||
a.set_create_raid_disk3(to_s(""));
|
||||
a.set_create_raid_disk4(to_s(""));
|
||||
}
|
||||
});
|
||||
// Disk info
|
||||
app.set_disk1_loc(to_s("Enclosure 0 Slot 0"));
|
||||
app.set_disk1_vendor(to_s("Seagate"));
|
||||
app.set_disk1_model(to_s("ST3000VX000"));
|
||||
app.set_disk1_capacity(to_s("3.0 TB"));
|
||||
app.set_disk1_status(to_s("Online"));
|
||||
|
||||
let app_handle = app.as_weak();
|
||||
app.on_close_create_raid_dialog(move || {
|
||||
if let Some(a) = app_handle.upgrade() {
|
||||
a.set_show_create_raid_dialog(false);
|
||||
}
|
||||
});
|
||||
|
||||
let state = app_state.clone();
|
||||
let app_handle = app.as_weak();
|
||||
app.on_confirm_create_raid(move || {
|
||||
let state = state.clone();
|
||||
let app_handle = app_handle.clone();
|
||||
let rt = tokio::runtime::Runtime::new().unwrap();
|
||||
rt.block_on(async move {
|
||||
if let Ok(s) = state.lock() {
|
||||
let _ = s.commit_config().await;
|
||||
let _ = s.refresh().await;
|
||||
if let Some(a) = app_handle.upgrade() {
|
||||
a.set_show_create_raid_dialog(false);
|
||||
update_ui_from_state(&a, &s);
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
app.set_disk2_loc(to_s("Enclosure 0 Slot 1"));
|
||||
app.set_disk2_vendor(to_s("Seagate"));
|
||||
app.set_disk2_model(to_s("ST3000VX000"));
|
||||
app.set_disk2_capacity(to_s("3.0 TB"));
|
||||
app.set_disk2_status(to_s("Online"));
|
||||
|
||||
// Delete RAID dialog
|
||||
let app_handle = app.as_weak();
|
||||
app.on_open_delete_raid_dialog(move || {
|
||||
if let Some(a) = app_handle.upgrade() {
|
||||
a.set_show_delete_raid_dialog(true);
|
||||
a.set_delete_raid_name(to_s("RAID-1"));
|
||||
a.set_delete_raid_status(to_s(""));
|
||||
}
|
||||
});
|
||||
app.set_disk3_loc(to_s("Enclosure 0 Slot 2"));
|
||||
app.set_disk3_vendor(to_s("Seagate"));
|
||||
app.set_disk3_model(to_s("ST3000VX000"));
|
||||
app.set_disk3_capacity(to_s("3.0 TB"));
|
||||
app.set_disk3_status(to_s("Online"));
|
||||
|
||||
let app_handle = app.as_weak();
|
||||
app.on_close_delete_raid_dialog(move || {
|
||||
if let Some(a) = app_handle.upgrade() {
|
||||
a.set_show_delete_raid_dialog(false);
|
||||
}
|
||||
});
|
||||
|
||||
let state = app_state.clone();
|
||||
let app_handle = app.as_weak();
|
||||
app.on_confirm_delete_raid(move || {
|
||||
let state = state.clone();
|
||||
let app_handle = app_handle.clone();
|
||||
let rt = tokio::runtime::Runtime::new().unwrap();
|
||||
rt.block_on(async move {
|
||||
if let Ok(s) = state.lock() {
|
||||
let _ = s.refresh().await;
|
||||
if let Some(a) = app_handle.upgrade() {
|
||||
a.set_show_delete_raid_dialog(false);
|
||||
update_ui_from_state(&a, &s);
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
app.set_disk4_loc(to_s("Enclosure 0 Slot 3"));
|
||||
app.set_disk4_vendor(to_s("Seagate"));
|
||||
app.set_disk4_model(to_s("ST3000VX000"));
|
||||
app.set_disk4_capacity(to_s("3.0 TB"));
|
||||
app.set_disk4_status(to_s("Online"));
|
||||
|
||||
// Rebuild RAID
|
||||
let state = app_state.clone();
|
||||
app.on_rebuild_raid(move || {
|
||||
let state = state.clone();
|
||||
let rt = tokio::runtime::Runtime::new().unwrap();
|
||||
rt.block_on(async move {
|
||||
if let Ok(s) = state.lock() {
|
||||
let _ = s.rebuild_raid(1).await;
|
||||
}
|
||||
});
|
||||
});
|
||||
// Event info
|
||||
app.set_evtime1(to_s("2026/03/29-10:30:00"));
|
||||
app.set_evlevel1(to_s("Info"));
|
||||
app.set_evsource1(to_s("System"));
|
||||
app.set_evmsg1(to_s("Controller started successfully"));
|
||||
|
||||
// Commit config
|
||||
let state = app_state.clone();
|
||||
app.on_commit_config(move || {
|
||||
let state = state.clone();
|
||||
let rt = tokio::runtime::Runtime::new().unwrap();
|
||||
rt.block_on(async move {
|
||||
if let Ok(s) = state.lock() {
|
||||
let _ = s.commit_config().await;
|
||||
}
|
||||
});
|
||||
});
|
||||
app.set_evtime2(to_s("2026/03/29-10:25:00"));
|
||||
app.set_evlevel2(to_s("Info"));
|
||||
app.set_evsource2(to_s("Disk"));
|
||||
app.set_evmsg2(to_s("Disk online"));
|
||||
|
||||
// Disk operation dialog
|
||||
let app_handle = app.as_weak();
|
||||
app.on_open_disk_operation_dialog(move || {
|
||||
if let Some(a) = app_handle.upgrade() {
|
||||
a.set_show_disk_dialog(true);
|
||||
a.set_selected_disk(1);
|
||||
a.set_disk_operation_status(to_s(""));
|
||||
}
|
||||
});
|
||||
app.set_evtime3(to_s("2026/03/29-10:20:00"));
|
||||
app.set_evlevel3(to_s("Warning"));
|
||||
app.set_evsource3(to_s("Enclosure"));
|
||||
app.set_evmsg3(to_s("Temperature warning"));
|
||||
|
||||
let app_handle = app.as_weak();
|
||||
app.on_close_disk_operation_dialog(move || {
|
||||
if let Some(a) = app_handle.upgrade() {
|
||||
a.set_show_disk_dialog(false);
|
||||
}
|
||||
});
|
||||
|
||||
let state = app_state.clone();
|
||||
let app_handle = app.as_weak();
|
||||
app.on_confirm_disk_operation(move || {
|
||||
let state = state.clone();
|
||||
let app_handle = app_handle.clone();
|
||||
let rt = tokio::runtime::Runtime::new().unwrap();
|
||||
rt.block_on(async move {
|
||||
if let Ok(s) = state.lock() {
|
||||
let _ = s.refresh().await;
|
||||
if let Some(a) = app_handle.upgrade() {
|
||||
a.set_show_disk_dialog(false);
|
||||
update_ui_from_state(&a, &s);
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
app.set_evtime4(to_s("2026/03/29-10:15:00"));
|
||||
app.set_evlevel4(to_s("Info"));
|
||||
app.set_evsource4(to_s("RAID"));
|
||||
app.set_evmsg4(to_s("RAID-01 status: Normal"));
|
||||
|
||||
app.set_evtime5(to_s("2026/03/29-10:10:00"));
|
||||
app.set_evlevel5(to_s("Info"));
|
||||
app.set_evsource5(to_s("Power"));
|
||||
app.set_evmsg5(to_s("Power supply online"));
|
||||
|
||||
tracing::info!("UI initialized, showing window...");
|
||||
|
||||
app.run()?;
|
||||
|
||||
tracing::info!("Application closed");
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -13,86 +13,86 @@ export component AppWindow inherits Window {
|
||||
callback menu_exit();
|
||||
callback menu_add_controller();
|
||||
|
||||
property<bool> connected: false;
|
||||
property<bool> is_loading: false;
|
||||
property<string> status_text: "Disconnected";
|
||||
property<int> current_tab: 0;
|
||||
in-out property<bool> connected: false;
|
||||
in-out property<bool> is_loading: false;
|
||||
in-out property<string> status_text: "Disconnected";
|
||||
in-out property<int> current_tab: 0;
|
||||
|
||||
property<int> controller_count: 0;
|
||||
property<int> raid_count: 0;
|
||||
property<int> disk_count: 0;
|
||||
property<bool> auto_refresh: true;
|
||||
in-out property<int> controller_count: 0;
|
||||
in-out property<int> raid_count: 0;
|
||||
in-out property<int> disk_count: 0;
|
||||
in-out property<bool> auto_refresh: true;
|
||||
|
||||
property<int> selected_controller_index: 0;
|
||||
property<string> ctrl1_name: "RAID Controller";
|
||||
property<string> ctrl1_ip: "192.168.1.100";
|
||||
property<string> ctrl1_status: "Online";
|
||||
property<string> ctrl1_model: "Accusys RAID 9000";
|
||||
property<string> ctrl1_firmware: "v3.8.0";
|
||||
property<string> ctrl1_sn: "ACC123456789";
|
||||
property<string> ctrl1_vendor: "Accusys";
|
||||
property<string> ctrl2_name: "-";
|
||||
property<string> ctrl2_ip: "-";
|
||||
property<string> ctrl2_status: "-";
|
||||
property<string> ctrl2_model: "-";
|
||||
property<string> ctrl2_firmware: "-";
|
||||
property<string> ctrl2_sn: "-";
|
||||
property<string> ctrl2_vendor: "-";
|
||||
in-out property<int> selected_controller_index: 0;
|
||||
in-out property<string> ctrl1_name: "RAID Controller";
|
||||
in-out property<string> ctrl1_ip: "192.168.1.100";
|
||||
in-out property<string> ctrl1_status: "Online";
|
||||
in-out property<string> ctrl1_model: "Accusys RAID 9000";
|
||||
in-out property<string> ctrl1_firmware: "v3.8.0";
|
||||
in-out property<string> ctrl1_sn: "ACC123456789";
|
||||
in-out property<string> ctrl1_vendor: "Accusys";
|
||||
in-out property<string> ctrl2_name: "-";
|
||||
in-out property<string> ctrl2_ip: "-";
|
||||
in-out property<string> ctrl2_status: "-";
|
||||
in-out property<string> ctrl2_model: "-";
|
||||
in-out property<string> ctrl2_firmware: "-";
|
||||
in-out property<string> ctrl2_sn: "-";
|
||||
in-out property<string> ctrl2_vendor: "-";
|
||||
|
||||
property<string> raid1_name: "RAID-01";
|
||||
property<string> raid1_level: "RAID 5";
|
||||
property<string> raid1_status: "Normal";
|
||||
property<string> raid1_capacity: "2.0 TB";
|
||||
property<string> raid1_usage: "45%";
|
||||
property<float> raid1_usage_pct: 45.0;
|
||||
property<string> raid2_name: "RAID-02";
|
||||
property<string> raid2_level: "RAID 6";
|
||||
property<string> raid2_status: "Normal";
|
||||
property<string> raid2_capacity: "4.0 TB";
|
||||
property<string> raid2_usage: "30%";
|
||||
property<float> raid2_usage_pct: 30.0;
|
||||
in-out property<string> raid1_name: "RAID-01";
|
||||
in-out property<string> raid1_level: "RAID 5";
|
||||
in-out property<string> raid1_status: "Normal";
|
||||
in-out property<string> raid1_capacity: "2.0 TB";
|
||||
in-out property<string> raid1_usage: "45%";
|
||||
in-out property<float> raid1_usage_pct: 45.0;
|
||||
in-out property<string> raid2_name: "RAID-02";
|
||||
in-out property<string> raid2_level: "RAID 6";
|
||||
in-out property<string> raid2_status: "Normal";
|
||||
in-out property<string> raid2_capacity: "4.0 TB";
|
||||
in-out property<string> raid2_usage: "30%";
|
||||
in-out property<float> raid2_usage_pct: 30.0;
|
||||
|
||||
property<string> disk1_loc: "Enclosure 0 Slot 0";
|
||||
property<string> disk1_model: "ST3000VX000";
|
||||
property<string> disk1_status: "Online";
|
||||
property<string> disk1_capacity: "3.0 TB";
|
||||
property<string> disk1_vendor: "Seagate";
|
||||
property<string> disk2_loc: "Enclosure 0 Slot 1";
|
||||
property<string> disk2_model: "ST3000VX000";
|
||||
property<string> disk2_status: "Online";
|
||||
property<string> disk2_capacity: "3.0 TB";
|
||||
property<string> disk2_vendor: "Seagate";
|
||||
property<string> disk3_loc: "Enclosure 0 Slot 2";
|
||||
property<string> disk3_model: "ST3000VX000";
|
||||
property<string> disk3_status: "Online";
|
||||
property<string> disk3_capacity: "3.0 TB";
|
||||
property<string> disk3_vendor: "Seagate";
|
||||
property<string> disk4_loc: "Enclosure 0 Slot 3";
|
||||
property<string> disk4_model: "ST3000VX000";
|
||||
property<string> disk4_status: "Online";
|
||||
property<string> disk4_capacity: "3.0 TB";
|
||||
property<string> disk4_vendor: "Seagate";
|
||||
in-out property<string> disk1_loc: "Enclosure 0 Slot 0";
|
||||
in-out property<string> disk1_model: "ST3000VX000";
|
||||
in-out property<string> disk1_status: "Online";
|
||||
in-out property<string> disk1_capacity: "3.0 TB";
|
||||
in-out property<string> disk1_vendor: "Seagate";
|
||||
in-out property<string> disk2_loc: "Enclosure 0 Slot 1";
|
||||
in-out property<string> disk2_model: "ST3000VX000";
|
||||
in-out property<string> disk2_status: "Online";
|
||||
in-out property<string> disk2_capacity: "3.0 TB";
|
||||
in-out property<string> disk2_vendor: "Seagate";
|
||||
in-out property<string> disk3_loc: "Enclosure 0 Slot 2";
|
||||
in-out property<string> disk3_model: "ST3000VX000";
|
||||
in-out property<string> disk3_status: "Online";
|
||||
in-out property<string> disk3_capacity: "3.0 TB";
|
||||
in-out property<string> disk3_vendor: "Seagate";
|
||||
in-out property<string> disk4_loc: "Enclosure 0 Slot 3";
|
||||
in-out property<string> disk4_model: "ST3000VX000";
|
||||
in-out property<string> disk4_status: "Online";
|
||||
in-out property<string> disk4_capacity: "3.0 TB";
|
||||
in-out property<string> disk4_vendor: "Seagate";
|
||||
|
||||
property<string> evtime1: "2026/03/29-10:30:00";
|
||||
property<string> evlevel1: "Info";
|
||||
property<string> evmsg1: "Controller started successfully";
|
||||
property<string> evsource1: "System";
|
||||
property<string> evtime2: "2026/03/29-10:25:00";
|
||||
property<string> evlevel2: "Info";
|
||||
property<string> evmsg2: "Disk online";
|
||||
property<string> evsource2: "Disk";
|
||||
property<string> evtime3: "2026/03/29-10:20:00";
|
||||
property<string> evlevel3: "Warning";
|
||||
property<string> evmsg3: "Temperature warning";
|
||||
property<string> evsource3: "Enclosure";
|
||||
property<string> evtime4: "2026/03/29-10:15:00";
|
||||
property<string> evlevel4: "Info";
|
||||
property<string> evmsg4: "RAID-01 status: Normal";
|
||||
property<string> evsource4: "RAID";
|
||||
property<string> evtime5: "2026/03/29-10:10:00";
|
||||
property<string> evlevel5: "Info";
|
||||
property<string> evmsg5: "Power supply online";
|
||||
property<string> evsource5: "Power";
|
||||
in-out property<string> evtime1: "2026/03/29-10:30:00";
|
||||
in-out property<string> evlevel1: "Info";
|
||||
in-out property<string> evmsg1: "Controller started successfully";
|
||||
in-out property<string> evsource1: "System";
|
||||
in-out property<string> evtime2: "2026/03/29-10:25:00";
|
||||
in-out property<string> evlevel2: "Info";
|
||||
in-out property<string> evmsg2: "Disk online";
|
||||
in-out property<string> evsource2: "Disk";
|
||||
in-out property<string> evtime3: "2026/03/29-10:20:00";
|
||||
in-out property<string> evlevel3: "Warning";
|
||||
in-out property<string> evmsg3: "Temperature warning";
|
||||
in-out property<string> evsource3: "Enclosure";
|
||||
in-out property<string> evtime4: "2026/03/29-10:15:00";
|
||||
in-out property<string> evlevel4: "Info";
|
||||
in-out property<string> evmsg4: "RAID-01 status: Normal";
|
||||
in-out property<string> evsource4: "RAID";
|
||||
in-out property<string> evtime5: "2026/03/29-10:10:00";
|
||||
in-out property<string> evlevel5: "Info";
|
||||
in-out property<string> evmsg5: "Power supply online";
|
||||
in-out property<string> evsource5: "Power";
|
||||
|
||||
VerticalLayout {
|
||||
spacing: 0;
|
||||
|
||||
Reference in New Issue
Block a user