show username and id

This commit is contained in:
Abdenasser 2024-10-30 18:30:32 +01:00
parent 519021e67e
commit 3e6f153bbe
5 changed files with 42 additions and 101 deletions

11
src-tauri/Cargo.lock generated
View File

@ -1712,6 +1712,7 @@ dependencies = [
"tauri", "tauri",
"tauri-build", "tauri-build",
"tauri-plugin-shell", "tauri-plugin-shell",
"users",
"windows 0.48.0", "windows 0.48.0",
] ]
@ -3796,6 +3797,16 @@ dependencies = [
"url", "url",
] ]
[[package]]
name = "users"
version = "0.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "24cc0f6d6f267b73e5a2cadf007ba8f9bc39c6a6f9666f8cf25ea809a153b032"
dependencies = [
"libc",
"log",
]
[[package]] [[package]]
name = "utf-8" name = "utf-8"
version = "0.7.6" version = "0.7.6"

View File

@ -24,6 +24,7 @@ serde = { version = "1", features = ["derive"] }
serde_json = "1" serde_json = "1"
sysinfo = "0.29.0" sysinfo = "0.29.0"
base64 = "0.21" base64 = "0.21"
users = "0.11"
[target.'cfg(target_os = "macos")'.dependencies] [target.'cfg(target_os = "macos")'.dependencies]
cocoa = "0.25" cocoa = "0.25"

View File

@ -3,6 +3,7 @@
use sysinfo::{CpuExt, SystemExt, ProcessExt, System, PidExt, ProcessStatus}; use sysinfo::{CpuExt, SystemExt, ProcessExt, System, PidExt, ProcessStatus};
use tauri::State; use tauri::State;
use std::sync::Mutex; use std::sync::Mutex;
use users::{Users, UsersCache};
struct AppState { struct AppState {
sys: Mutex<System>, sys: Mutex<System>,
@ -35,33 +36,30 @@ async fn get_processes(state: State<'_, AppState>) -> Result<Vec<ProcessInfo>, S
let mut sys = state.sys.lock().map_err(|_| "Failed to lock system state")?; let mut sys = state.sys.lock().map_err(|_| "Failed to lock system state")?;
sys.refresh_all(); sys.refresh_all();
let users_cache = UsersCache::new();
Ok(sys.processes() Ok(sys.processes()
.iter() .iter()
.map(|(pid, process)| { .map(|(pid, process)| {
let threads = if cfg!(target_os = "macos") { let status = match process.status() {
use std::process::Command; ProcessStatus::Run => "Running",
Command::new("ps") ProcessStatus::Sleep => {
.args(["-o", "thcount=", "-p", &pid.as_u32().to_string()]) if process.cpu_usage() < 0.1 {
.output() "Idle"
.ok() } else {
.and_then(|output| { "Sleeping"
String::from_utf8(output.stdout) }
.ok() },
.and_then(|s| s.trim().parse().ok()) _ => "Unknown"
})
} else {
None
}; };
let status = match process.status() { let user = process.user_id()
ProcessStatus::Run => "R", // Running .and_then(|uid| {
ProcessStatus::Sleep => "S", // Sleeping let uid_num = uid.to_string().parse::<u32>().unwrap_or(0);
ProcessStatus::Idle => "I", // Idle users_cache.get_user_by_uid(uid_num)
ProcessStatus::Zombie => "Z", // Zombie .map(|user| format!("{} ({})", user.name().to_string_lossy(), uid_num))
ProcessStatus::Stop => "T", // Stopped })
ProcessStatus::Dead => "X", // Dead .unwrap_or_else(|| "-".to_string());
_ => "Unknown",
};
ProcessInfo { ProcessInfo {
pid: pid.as_u32(), pid: pid.as_u32(),
@ -70,11 +68,9 @@ async fn get_processes(state: State<'_, AppState>) -> Result<Vec<ProcessInfo>, S
cpu_usage: process.cpu_usage(), cpu_usage: process.cpu_usage(),
memory_usage: process.memory(), memory_usage: process.memory(),
status: status.to_string(), status: status.to_string(),
user: process.user_id() user,
.map(|uid| uid.to_string())
.unwrap_or_else(|| "-".to_string()),
command: process.cmd().join(" "), command: process.cmd().join(" "),
threads, threads: None,
} }
}) })
.collect()) .collect())

View File

@ -22,13 +22,10 @@
const statusOptions = [ const statusOptions = [
{ value: "all", label: "All Statuses" }, { value: "all", label: "All Statuses" },
{ value: "R", label: "🏃 Running" }, { value: "Running", label: "🏃 Running" },
{ value: "S", label: "😴 Sleeping" }, { value: "Sleeping", label: "😴 Sleeping" },
{ value: "I", label: "⌛ Idle" }, { value: "Idle", label: "⌛ Idle" },
{ value: "Z", label: "🧟 Zombie" }, { value: "Unknown", label: "🫥 Unknown" },
{ value: "T", label: "⛔ Stopped" },
{ value: "X", label: "💀 Dead" },
{ value: "Unknown", label: "🤔 Unknown" },
]; ];
function changePage(page: number) { function changePage(page: number) {
@ -60,7 +57,6 @@
</div> </div>
</div> </div>
<div class="toolbar-group"> <div class="toolbar-group">
<span class="toolbar-label">Status:</span>
<select bind:value={statusFilter} class="select-input"> <select bind:value={statusFilter} class="select-input">
{#each statusOptions as option} {#each statusOptions as option}
<option value={option.value}>{option.label}</option> <option value={option.value}>{option.label}</option>
@ -364,52 +360,4 @@
opacity: 0.5; opacity: 0.5;
cursor: not-allowed; cursor: not-allowed;
} }
.filter-box {
display: flex;
align-items: center;
gap: 8px;
}
.status-select {
padding: 6px 12px;
font-size: 13px;
color: var(--text);
background: var(--surface0);
border: 1px solid var(--surface1);
border-radius: 6px;
cursor: pointer;
}
.status-select:hover {
background: var(--surface1);
}
select.btn-base {
appearance: none;
padding: 6px 28px 6px 12px;
font-size: 12px;
color: var(--text);
background: var(--surface0)
url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E")
no-repeat right 8px center;
border: 1px solid var(--surface1);
border-radius: 6px;
cursor: pointer;
transition: all 0.2s ease;
}
select.btn-base:hover {
background-color: var(--surface1);
}
select.btn-base:focus {
outline: none;
border-color: var(--blue);
}
/* Ensure proper spacing between toolbar items */
.filter-box {
margin-left: 8px;
}
</style> </style>

View File

@ -5,39 +5,24 @@ export interface ProcessStatus {
} }
export const statusMap: Record<string, ProcessStatus> = { export const statusMap: Record<string, ProcessStatus> = {
"R": { // Running "Running": {
label: "Running", label: "Running",
emoji: "🏃", emoji: "🏃",
color: "var(--green)", color: "var(--green)",
}, },
"S": { // Sleeping "Sleeping": {
label: "Sleeping", label: "Sleeping",
emoji: "😴", emoji: "😴",
color: "var(--blue)", color: "var(--blue)",
}, },
"I": { // Idle "Idle": {
label: "Idle", label: "Idle",
emoji: "⌛", emoji: "⌛",
color: "var(--overlay0)", color: "var(--overlay0)",
}, },
"Z": { // Zombie
label: "Zombie",
emoji: "🧟",
color: "var(--red)",
},
"T": { // Stopped
label: "Stopped",
emoji: "⛔",
color: "var(--yellow)",
},
"X": { // Dead
label: "Dead",
emoji: "💀",
color: "var(--red)",
},
"Unknown": { "Unknown": {
label: "Unknown", label: "Unknown",
emoji: "🤔", emoji: "🫥",
color: "var(--overlay0)", color: "var(--overlay0)",
}, },
}; };