diff --git a/src-tauri/src/cmd/mod.rs b/src-tauri/src/cmd/mod.rs index e0c2b91d..8a15dd68 100644 --- a/src-tauri/src/cmd/mod.rs +++ b/src-tauri/src/cmd/mod.rs @@ -14,6 +14,7 @@ pub mod clash; pub mod verge; pub mod runtime; pub mod save_profile; +pub mod system; // Re-export all command functions for backwards compatibility pub use profile::*; @@ -25,4 +26,5 @@ pub use network::*; pub use clash::*; pub use verge::*; pub use runtime::*; -pub use save_profile::*; \ No newline at end of file +pub use save_profile::*; +pub use system::*; \ No newline at end of file diff --git a/src-tauri/src/cmd/system.rs b/src-tauri/src/cmd/system.rs new file mode 100644 index 00000000..a0651a6e --- /dev/null +++ b/src-tauri/src/cmd/system.rs @@ -0,0 +1,17 @@ +use super::CmdResult; +use crate::{core::handle, model::sysinfo::PlatformSpecification}; +use tauri_plugin_clipboard_manager::ClipboardExt; + +#[tauri::command] +pub async fn export_diagnostic_info() -> CmdResult<()> { + let sysinfo = PlatformSpecification::new(); + let info = format!("{:?}", sysinfo); + + let app_handle = handle::Handle::global().app_handle().unwrap(); + let cliboard = app_handle.clipboard(); + + if let Err(_) = cliboard.write_text(info) { + log::error!(target: "app", "Failed to write to clipboard"); + } + Ok(()) +} diff --git a/src-tauri/src/lib.rs b/src-tauri/src/lib.rs index a199cf1e..903c10b3 100644 --- a/src-tauri/src/lib.rs +++ b/src-tauri/src/lib.rs @@ -4,6 +4,8 @@ mod core; mod enhance; mod feat; mod utils; +mod model; +mod module; use crate::core::hotkey; use crate::utils::{resolve, resolve::resolve_scheme, server}; use config::Config; @@ -191,6 +193,8 @@ pub fn run() { cmd::list_webdav_backup, cmd::delete_webdav_backup, cmd::restore_webdav_backup, + // export diagnostic info for issue reporting + cmd::export_diagnostic_info, ]); #[cfg(debug_assertions)] diff --git a/src-tauri/src/model/mod.rs b/src-tauri/src/model/mod.rs new file mode 100644 index 00000000..f146b310 --- /dev/null +++ b/src-tauri/src/model/mod.rs @@ -0,0 +1 @@ +pub mod sysinfo; \ No newline at end of file diff --git a/src-tauri/src/model/sysinfo.rs b/src-tauri/src/model/sysinfo.rs new file mode 100644 index 00000000..b626181d --- /dev/null +++ b/src-tauri/src/model/sysinfo.rs @@ -0,0 +1,18 @@ +use std::fmt::{self, Debug, Formatter}; + +pub struct PlatformSpecification { + pub system_name: String, + pub system_version: String, + pub system_kernel_version: String, + pub system_arch: String, +} + +impl Debug for PlatformSpecification { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + write!( + f, + "System Name: {}\nSystem Version: {}\nSystem kernel Version: {}\nSystem Arch: {}", + self.system_name, self.system_version, self.system_kernel_version, self.system_arch + ) + } +} \ No newline at end of file diff --git a/src-tauri/src/module/mod.rs b/src-tauri/src/module/mod.rs new file mode 100644 index 00000000..f146b310 --- /dev/null +++ b/src-tauri/src/module/mod.rs @@ -0,0 +1 @@ +pub mod sysinfo; \ No newline at end of file diff --git a/src-tauri/src/module/sysinfo.rs b/src-tauri/src/module/sysinfo.rs new file mode 100644 index 00000000..9908f6cc --- /dev/null +++ b/src-tauri/src/module/sysinfo.rs @@ -0,0 +1,19 @@ +use crate::model::sysinfo::PlatformSpecification; + +use sysinfo::System; + +impl PlatformSpecification { + pub fn new() -> Self { + let system_name = System::name().unwrap_or("Null".into()); + let system_version = System::long_os_version().unwrap_or("Null".into()); + let system_kernel_version = System::kernel_version().unwrap_or("Null".into()); + let system_arch = std::env::consts::ARCH.to_string(); + + Self { + system_name, + system_version, + system_kernel_version, + system_arch + } + } +} diff --git a/src/components/setting/setting-verge-advanced.tsx b/src/components/setting/setting-verge-advanced.tsx index e5d91ba5..4473b8dd 100644 --- a/src/components/setting/setting-verge-advanced.tsx +++ b/src/components/setting/setting-verge-advanced.tsx @@ -1,4 +1,4 @@ -import { useRef } from "react"; +import { useCallback, useRef } from "react"; import { useTranslation } from "react-i18next"; import { Typography } from "@mui/material"; import { @@ -7,6 +7,7 @@ import { openCoreDir, openLogsDir, openDevTools, + exportDiagnosticInfo, } from "@/services/cmds"; import { check as checkUpdate } from "@tauri-apps/plugin-updater"; import { useVerge } from "@/hooks/use-verge"; @@ -21,6 +22,7 @@ import { LayoutViewer } from "./mods/layout-viewer"; import { UpdateViewer } from "./mods/update-viewer"; import { BackupViewer } from "./mods/backup-viewer"; import { TooltipIcon } from "@/components/base/base-tooltip-icon"; +import { ContentCopyRounded } from "@mui/icons-material"; interface Props { onError?: (err: Error) => void; @@ -51,6 +53,11 @@ const SettingVergeAdvanced = ({ onError }: Props) => { } }; + const onExportDiagnosticInfo = useCallback(async () => { + await exportDiagnosticInfo(); + Notice.success(t("Copy Success"), 1000); + }, []); + return ( @@ -111,6 +118,16 @@ const SettingVergeAdvanced = ({ onError }: Props) => { label={t("Exit")} /> + + } + > + v{version} diff --git a/src/locales/en.json b/src/locales/en.json index e5e1ff6b..e9aef5d3 100644 --- a/src/locales/en.json +++ b/src/locales/en.json @@ -349,6 +349,8 @@ "Portable Updater Error": "The portable version does not support in-app updates. Please manually download and replace it", "Break Change Update Error": "This version is a major update and does not support in-app updates. Please uninstall it and manually download and install the new version", "Open Dev Tools": "Dev Tools", + "Export Diagnostic Info": "Export Diagnostic Info", + "Export Diagnostic Info For Issue Reporting": "Export Diagnostic Info For Issue Reporting", "Exit": "Exit", "Verge Version": "Verge Version", "ReadOnly": "ReadOnly", diff --git a/src/services/cmds.ts b/src/services/cmds.ts index f0ce4c14..5a468e8f 100644 --- a/src/services/cmds.ts +++ b/src/services/cmds.ts @@ -191,6 +191,10 @@ export async function exitApp() { return invoke("exit_app"); } +export async function exportDiagnosticInfo() { + return invoke("export_diagnostic_info"); +} + export async function copyIconFile( path: string, name: "common" | "sysproxy" | "tun",