From c8e8db34128ce94769a7ff94a6a9fa34b950315f Mon Sep 17 00:00:00 2001 From: xiaji Date: Fri, 17 Apr 2026 07:38:34 +0800 Subject: [PATCH] Add per-VM action buttons in VM list --- src/gui.rs | 174 +++++++++++++++++++++++++---------------------------- 1 file changed, 82 insertions(+), 92 deletions(-) diff --git a/src/gui.rs b/src/gui.rs index 733d055..4f2545f 100644 --- a/src/gui.rs +++ b/src/gui.rs @@ -316,103 +316,93 @@ impl eframe::App for App { } }); - // 虚拟机列表(只读) + // 虚拟机列表(每行带操作按钮) ui.label("虚拟机列表:"); - egui::ScrollArea::vertical().max_height(120.0).stick_to_bottom(true).show(ui, |ui| { - let vm_count = st.vms.len(); - ui.label(format!("共 {} 台虚拟机 (点击选择)", vm_count)); + let vms_list = st.vms.clone(); + let client_ref = st.client.clone(); + let node_ref = st.node.clone(); + egui::ScrollArea::vertical().max_height(180.0).stick_to_bottom(true).show(ui, |ui| { + let vm_count = vms_list.len(); + ui.label(format!("共 {} 台虚拟机", vm_count)); ui.separator(); - for (idx, (id, name)) in st.vms.iter().enumerate() { - let is_selected = st.vm_id == *id; - let label = if is_selected { - format!("● {} ({}) - 已选择", name, id) - } else { - format!("○ {} ({})", name, id) - }; - if is_selected { - ui.colored_label(egui::Color32::LIGHT_BLUE, label); - } else { - ui.label(label); - } + for (_, (id, name)) in vms_list.iter().enumerate() { + ui.horizontal(|ui| { + ui.label(format!("{} ({})", name, id)); + ui.add_space(10.0); + + let client = client_ref.clone(); + let node = node_ref.clone(); + let vm_id = *id; + let state_clone = state.clone(); + + if ui.button("▶").clicked() { + state_clone.write().unwrap().add_log(&format!("启动 VM {}...", vm_id)); + ctx.request_repaint(); + thread::spawn(move || { + let rt = tokio::runtime::Runtime::new().unwrap(); + rt.block_on(async { + let client = client.lock().unwrap(); + if let Some(c) = client.as_ref() { + match c.start_vm(&node, vm_id).await { + Ok(_) => state_clone.write().unwrap().add_log("✓ 启动成功"), + Err(e) => state_clone.write().unwrap().add_log(&format!("✗ {}", e)), + } + } + }); + }); + } + + let client2 = client_ref.clone(); + let node2 = node_ref.clone(); + let vm_id2 = *id; + let state2 = state.clone(); + if ui.button("■").clicked() { + state2.write().unwrap().add_log(&format!("停止 VM {}...", vm_id2)); + ctx.request_repaint(); + thread::spawn(move || { + let rt = tokio::runtime::Runtime::new().unwrap(); + rt.block_on(async { + let client = client2.lock().unwrap(); + if let Some(c) = client.as_ref() { + match c.stop_vm(&node2, vm_id2).await { + Ok(_) => state2.write().unwrap().add_log("✓ 停止成功"), + Err(e) => state2.write().unwrap().add_log(&format!("✗ {}", e)), + } + } + }); + }); + } + + let client3 = client_ref.clone(); + let node3 = node_ref.clone(); + let vm_id3 = *id; + let state3 = state.clone(); + if ui.button("↻").clicked() { + state3.write().unwrap().add_log(&format!("重启 VM {}...", vm_id3)); + ctx.request_repaint(); + thread::spawn(move || { + let rt = tokio::runtime::Runtime::new().unwrap(); + rt.block_on(async { + let client = client3.lock().unwrap(); + if let Some(c) = client.as_ref() { + match c.stop_vm(&node3, vm_id3).await { + Ok(_) => { + tokio::time::sleep(tokio::time::Duration::from_secs(3)).await; + match c.start_vm(&node3, vm_id3).await { + Ok(_) => state3.write().unwrap().add_log("✓ 重启成功"), + Err(e) => state3.write().unwrap().add_log(&format!("✗ {}", e)), + } + } + Err(e) => state3.write().unwrap().add_log(&format!("✗ {}", e)), + } + } + }); + }); + } + }); } }); - - // 选择VM后显示操作按钮 - if !st.vms.is_empty() { - ui.horizontal(|ui| { - ui.label("选中 VM 操作:"); - let client = st.client.clone(); - let node = st.node.clone(); - let vm_id = st.vm_id; - let state_clone = state.clone(); - - if ui.button("▶ 启动").clicked() { - st.add_log(&format!("启动 VM {}...", vm_id)); - ctx.request_repaint(); - thread::spawn(move || { - let rt = tokio::runtime::Runtime::new().unwrap(); - rt.block_on(async { - let client = client.lock().unwrap(); - if let Some(c) = client.as_ref() { - match c.start_vm(&node, vm_id).await { - Ok(_) => state_clone.write().unwrap().add_log("✓ 启动成功"), - Err(e) => state_clone.write().unwrap().add_log(&format!("✗ {}", e)), - } - } - }); - }); - } - - let client2 = st.client.clone(); - let node2 = st.node.clone(); - let vm_id2 = st.vm_id; - let state2 = state.clone(); - if ui.button("■ 停止").clicked() { - st.add_log(&format!("停止 VM {}...", vm_id2)); - ctx.request_repaint(); - thread::spawn(move || { - let rt = tokio::runtime::Runtime::new().unwrap(); - rt.block_on(async { - let client = client2.lock().unwrap(); - if let Some(c) = client.as_ref() { - match c.stop_vm(&node2, vm_id2).await { - Ok(_) => state2.write().unwrap().add_log("✓ 停止成功"), - Err(e) => state2.write().unwrap().add_log(&format!("✗ {}", e)), - } - } - }); - }); - } - - let client3 = st.client.clone(); - let node3 = st.node.clone(); - let vm_id3 = st.vm_id; - let state3 = state.clone(); - if ui.button("↻ 重启").clicked() { - st.add_log(&format!("重启 VM {}...", vm_id3)); - ctx.request_repaint(); - thread::spawn(move || { - let rt = tokio::runtime::Runtime::new().unwrap(); - rt.block_on(async { - let client = client3.lock().unwrap(); - if let Some(c) = client.as_ref() { - match c.stop_vm(&node3, vm_id3).await { - Ok(_) => { - tokio::time::sleep(tokio::time::Duration::from_secs(3)).await; - match c.start_vm(&node3, vm_id3).await { - Ok(_) => state3.write().unwrap().add_log("✓ 重启成功"), - Err(e) => state3.write().unwrap().add_log(&format!("✗ {}", e)), - } - } - Err(e) => state3.write().unwrap().add_log(&format!("✗ {}", e)), - } - } - }); - }); - } - }); - } }); });