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

View File

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

View File

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

View File

@ -22,13 +22,10 @@
const statusOptions = [
{ value: "all", label: "All Statuses" },
{ value: "R", label: "🏃 Running" },
{ value: "S", label: "😴 Sleeping" },
{ value: "I", label: "⌛ Idle" },
{ value: "Z", label: "🧟 Zombie" },
{ value: "T", label: "⛔ Stopped" },
{ value: "X", label: "💀 Dead" },
{ value: "Unknown", label: "🤔 Unknown" },
{ value: "Running", label: "🏃 Running" },
{ value: "Sleeping", label: "😴 Sleeping" },
{ value: "Idle", label: "⌛ Idle" },
{ value: "Unknown", label: "🫥 Unknown" },
];
function changePage(page: number) {
@ -60,7 +57,6 @@
</div>
</div>
<div class="toolbar-group">
<span class="toolbar-label">Status:</span>
<select bind:value={statusFilter} class="select-input">
{#each statusOptions as option}
<option value={option.value}>{option.label}</option>
@ -364,52 +360,4 @@
opacity: 0.5;
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>

View File

@ -5,39 +5,24 @@ export interface ProcessStatus {
}
export const statusMap: Record<string, ProcessStatus> = {
"R": { // Running
"Running": {
label: "Running",
emoji: "🏃",
color: "var(--green)",
},
"S": { // Sleeping
"Sleeping": {
label: "Sleeping",
emoji: "😴",
color: "var(--blue)",
},
"I": { // Idle
"Idle": {
label: "Idle",
emoji: "⌛",
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": {
label: "Unknown",
emoji: "🤔",
emoji: "🫥",
color: "var(--overlay0)",
},
};