From 8e692b013bb739afb045009d3beaf9f250647cb6 Mon Sep 17 00:00:00 2001 From: Abdenasser Date: Fri, 8 Nov 2024 20:39:01 +0100 Subject: [PATCH 1/2] minor fixes --- docs/styles.css | 1 + src/lib/components/AppInfo.svelte | 1 + src/lib/components/ToolBar.svelte | 17 ----------------- 3 files changed, 2 insertions(+), 17 deletions(-) diff --git a/docs/styles.css b/docs/styles.css index 1349533..d4375ef 100644 --- a/docs/styles.css +++ b/docs/styles.css @@ -1229,6 +1229,7 @@ footer { font-size: 2.5rem; margin-bottom: 1rem; background: linear-gradient(135deg, var(--primary-color), var(--secondary-color)); + background-clip: text; -webkit-background-clip: text; -webkit-text-fill-color: transparent; } diff --git a/src/lib/components/AppInfo.svelte b/src/lib/components/AppInfo.svelte index 020ea52..9a4f77d 100644 --- a/src/lib/components/AppInfo.svelte +++ b/src/lib/components/AppInfo.svelte @@ -86,6 +86,7 @@ {#if showInfo} +
(showInfo = false)}>
{ASCII_ART}
diff --git a/src/lib/components/ToolBar.svelte b/src/lib/components/ToolBar.svelte index 70c5f7c..de98b7c 100644 --- a/src/lib/components/ToolBar.svelte +++ b/src/lib/components/ToolBar.svelte @@ -221,23 +221,6 @@ box-shadow: 0 0 0 2px color-mix(in srgb, var(--blue) 25%, transparent); } - .btn-clear { - padding: 6px 12px; - background: var(--surface0); - border: 1px solid var(--surface1); - border-radius: 6px; - color: var(--text); - font-size: 12px; - cursor: pointer; - transition: all 0.2s ease; - white-space: nowrap; - } - - .btn-clear:hover { - background: var(--surface1); - border-color: var(--surface2); - } - .pagination-controls { display: flex; align-items: center; From 7f44f8de098327a92c43084857e67ec67d707db3 Mon Sep 17 00:00:00 2001 From: Abdenasser Date: Sat, 9 Nov 2024 14:13:42 +0100 Subject: [PATCH 2/2] adds environ, root, vram, run_time, start_time, disk_usage, session_id columns --- src-tauri/src/main.rs | 41 ++- src/lib/components/ProcessDetailsModal.svelte | 298 +++++++++++++++--- src/lib/components/StatsBar.svelte | 6 + src/lib/types/index.ts | 7 + src/routes/+page.svelte | 54 +++- 5 files changed, 357 insertions(+), 49 deletions(-) diff --git a/src-tauri/src/main.rs b/src-tauri/src/main.rs index 0486dfa..64eaab0 100644 --- a/src-tauri/src/main.rs +++ b/src-tauri/src/main.rs @@ -15,7 +15,7 @@ use sysinfo::{ use tauri::State; use std::sync::Mutex; use std::collections::HashMap; -use std::time::Instant; +use std::time::{Instant, SystemTime, UNIX_EPOCH}; struct AppState { sys: Mutex, @@ -58,6 +58,13 @@ struct ProcessInfo { user: String, command: String, threads: Option, + environ: Vec, + root: String, + virtual_memory: u64, + start_time: u64, + run_time: u64, + disk_usage: (u64, u64), // (read_bytes, written_bytes) + session_id: Option, } #[derive(serde::Serialize)] @@ -96,6 +103,12 @@ async fn get_processes(state: State<'_, AppState>) -> Result<(Vec, let processes_data; let system_stats; + // Get current time once for all calculations + let current_time = SystemTime::now() + .duration_since(UNIX_EPOCH) + .map_err(|e| e.to_string())? + .as_secs(); + // Scope for system lock { let mut sys = state.sys.lock().map_err(|_| "Failed to lock system state")?; @@ -109,6 +122,13 @@ async fn get_processes(state: State<'_, AppState>) -> Result<(Vec, .processes() .iter() .map(|(pid, process)| { + let start_time = process.start_time(); + let run_time = if start_time > 0 { + current_time.saturating_sub(start_time) + } else { + 0 + }; + ( pid.as_u32(), process.name().to_string(), @@ -118,6 +138,14 @@ async fn get_processes(state: State<'_, AppState>) -> Result<(Vec, process.memory(), process.status(), process.parent().map(|p| p.as_u32()), + process.environ().to_vec(), + process.root().to_string_lossy().into_owned(), + process.virtual_memory(), + start_time, + run_time, // Use calculated run_time + process.disk_usage().read_bytes, + process.disk_usage().written_bytes, + process.session_id().map(|id| id.as_u32()), ) }) .collect::>(); @@ -170,7 +198,9 @@ async fn get_processes(state: State<'_, AppState>) -> Result<(Vec, // Build the process info list let processes = processes_data .into_iter() - .map(|(pid, name, cmd, user_id, cpu_usage, memory, status, ppid)| { + .map(|(pid, name, cmd, user_id, cpu_usage, memory, status, ppid, + environ, root, virtual_memory, start_time, run_time, + disk_read, disk_written, session_id)| { let static_info = process_cache.entry(pid).or_insert_with(|| { ProcessStaticInfo { name: name.clone(), @@ -196,6 +226,13 @@ async fn get_processes(state: State<'_, AppState>) -> Result<(Vec, user: static_info.user.clone(), command: static_info.command.clone(), threads: None, + environ, + root, + virtual_memory, + start_time, + run_time, + disk_usage: (disk_read, disk_written), + session_id, } }) .collect(); diff --git a/src/lib/components/ProcessDetailsModal.svelte b/src/lib/components/ProcessDetailsModal.svelte index d9e7dc2..c1635cf 100644 --- a/src/lib/components/ProcessDetailsModal.svelte +++ b/src/lib/components/ProcessDetailsModal.svelte @@ -1,60 +1,183 @@ - - {#if process} + + {#if currentProcess}
-
- Name: - {process.name} -
-
- PID: - {process.pid} -
-
- Parent PID: - {process.ppid} -
-
- User: - {process.user} -
-
- Status: - - {@html formatStatus(process.status)} - -
-
- CPU Usage: - {process.cpu_usage.toFixed(1)}% -
-
- Memory Usage: - {formatMemory(process.memory_usage)} -
-
- Command: - {process.command} -
+ +
+

Basic Information

+
+
+ Name: + {currentProcess.name} +
+
+ PID: + {currentProcess.pid} +
+
+ Parent PID: + {currentProcess.ppid} +
+
+ User: + {currentProcess.user} +
+
+ Status: + + {@html formatStatus(currentProcess.status)} + +
+
+
+ + +
+

Resource Usage

+
+ +
+
+ + CPU Usage +
+
+
+
50} + class:critical={currentProcess.cpu_usage > 80} + >
+
+ {currentProcess.cpu_usage.toFixed(1)}% +
+
+ + +
+
+ + Memory Usage +
+
+
Physical: {formatBytes(currentProcess.memory_usage)}
+
Virtual: {formatBytes(currentProcess.virtual_memory)}
+
+
+ + +
+
+ + Disk I/O +
+
+
Read: {formatBytes(currentProcess.disk_usage[0])}
+
Written: {formatBytes(currentProcess.disk_usage[1])}
+
+
+ + +
+
+ + Time Information +
+
+
Started: {formatDate(currentProcess.start_time)}
+
Running: {formatUptime(currentProcess.run_time)}
+
+
+
+
+ + +
+

Process Details

+
+
+ Command: + {currentProcess.command} +
+
+ Root: + {currentProcess.root} +
+ {#if currentProcess.environ.length > 0} +
+ Environment: +
+ {#each currentProcess.environ as env} +
{env}
+ {/each} +
+
+ {/if} +
+
{/if}
diff --git a/src/lib/components/StatsBar.svelte b/src/lib/components/StatsBar.svelte index 326a5f8..33b5762 100644 --- a/src/lib/components/StatsBar.svelte +++ b/src/lib/components/StatsBar.svelte @@ -46,6 +46,12 @@

CPU Usage

+
+ {formatPercentage( + systemStats.cpu_usage.reduce((a, b) => a + b, 0) / + systemStats.cpu_usage.length, + )} +
{#each systemStats.cpu_usage as usage, i} diff --git a/src/lib/types/index.ts b/src/lib/types/index.ts index 6704350..e415c6f 100644 --- a/src/lib/types/index.ts +++ b/src/lib/types/index.ts @@ -9,6 +9,13 @@ export interface Process { user: string; command: string; threads?: number; + environ: string[]; + root: string; + virtual_memory: number; + start_time: number; + run_time: number; + disk_usage: [number, number]; // [read_bytes, written_bytes] + session_id?: number; } export interface SystemStats { diff --git a/src/routes/+page.svelte b/src/routes/+page.svelte index accfa57..422c4e5 100644 --- a/src/routes/+page.svelte +++ b/src/routes/+page.svelte @@ -6,7 +6,7 @@ import ProcessTable from "$lib/components/ProcessTable.svelte"; import ProcessDetailsModal from "$lib/components/ProcessDetailsModal.svelte"; import KillProcessModal from "$lib/components/KillProcessModal.svelte"; - import { formatStatus } from "$lib/utils"; + import { formatMemorySize, formatStatus } from "$lib/utils"; import { themeStore } from "$lib/stores"; import type { Process, SystemStats, Column } from "$lib/types"; @@ -27,6 +27,7 @@ let statusFilter = "all"; let refreshRate = 1000; let isFrozen = false; + let selectedProcessPid: number | null = null; let columns: Column[] = [ { id: "name", label: "Process Name", visible: true, required: true }, @@ -52,6 +53,40 @@ }, { id: "command", label: "Command", visible: false }, { id: "ppid", label: "Parent PID", visible: false }, + { id: "environ", label: "Environment", visible: false }, + { id: "root", label: "Root", visible: false }, + { + id: "virtual_memory", + label: "Virtual Memory", + visible: false, + format: (v) => formatMemorySize(v), + }, + { + id: "start_time", + label: "Start Time", + visible: false, + format: (v) => new Date(v * 1000).toLocaleString(), // v is the time where the process was started (in seconds) from epoch + }, + { + id: "run_time", + label: "Run Time", + visible: false, + format: (v) => { + const seconds = v; // v is the time the process has been running in seconds + const hours = Math.floor(seconds / 3600); + const minutes = Math.floor((seconds % 3600) / 60); + const remainingSeconds = seconds % 60; + return `${hours}h ${minutes}m ${remainingSeconds}s`; // Format as HH:MM:SS + }, + }, + { + id: "disk_usage", + label: "Disk Usage", + visible: false, + format: (v) => + `${(v[0] / (1024 * 1024)).toFixed(1)} / ${(v[1] / (1024 * 1024)).toFixed(1)} MB`, + }, + { id: "session_id", label: "Session ID", visible: false }, ]; let sortConfig = { @@ -127,6 +162,11 @@ } } + $: if (selectedProcessPid && processes.length > 0) { + selectedProcess = + processes.find((p) => p.pid === selectedProcessPid) || null; + } + async function getProcesses() { try { const result = await invoke<[Process[], SystemStats]>("get_processes"); @@ -176,6 +216,7 @@ } function showProcessDetails(process: Process) { + selectedProcessPid = process.pid; selectedProcess = process; showInfoModal = true; } @@ -198,6 +239,12 @@ } } + function handleModalClose() { + showInfoModal = false; + selectedProcess = null; + selectedProcessPid = null; + } + onMount(async () => { try { await Promise.all([getProcesses()]); @@ -259,10 +306,7 @@ { - showInfoModal = false; - selectedProcess = null; - }} + onClose={handleModalClose} />