Elysia Tools

Browse tools, examples, visual explainers, and topic guides from one clear workspace.

Top Categories

Hubs

Language
ZHESPTRUFRDEEN

Elysia Tools

Navigation

Desktop Development

Tauri Samples

Lightweight desktop application development examples using Tauri framework with Rust backend and web frontend

Samples

Entries inside this sample collection

CoderustSimple

Tauri Hello World Application

Basic Tauri application setup with minimal configuration and simple Rust-JavaScript communication

Difficulty

3/10

Estimated time

15 min

Tags

tauri, desktop, rust, web

Prerequisites

Rust basics, HTML/CSS/JavaScript, Node.js

rust
// Tauri Hello World Application Examples

// 1. Cargo.toml Dependencies
[package]
name = "tauri-app"
version = "0.1.0"
edition = "2021"

[build-dependencies]
tauri-build = { version = "1.0", features = [] }

[dependencies]
tauri = { version = "1.0", features = ["api-all"] }
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
tokio = { version = "1", features = ["time"] }

[features]
default = ["custom-protocol"]
custom-protocol = ["tauri/custom-protocol"]

// 2. tauri.conf.json - Application Configuration
{
  "build": {
    "beforeBuildCommand": "npm run build",
    "beforeDevCommand": "npm run dev",
    "devPath": "http://localhost:3000",
    "distDir": "../dist"
  },
  "package": {
    "productName": "Tauri App",
    "version": "0.1.0"
  },
  "tauri": {
    "allowlist": {
      "all": false,
      "shell": {
        "all": false,
        "open": true
      },
      "dialog": {
        "all": false,
        "open": true,
        "save": true
      }
    },
    "bundle": {
      "active": true,
      "category": "DeveloperTool",
      "copyright": "",
      "deb": {
        "depends": []
      },
      "externalBin": [],
      "icon": [
        "icons/32x32.png",
        "icons/128x128.png",
        "icons/[email protected]",
        "icons/icon.icns",
        "icons/icon.ico"
      ],
      "identifier": "com.tauri.app",
      "longDescription": "",
      "macOS": {
        "entitlements": null,
        "exceptionDomain": "",
        "frameworks": [],
        "providerShortName": null,
        "signingIdentity": null
      },
      "resources": [],
      "shortDescription": "",
      "targets": "all",
      "windows": {
        "certificateThumbprint": null,
        "digestAlgorithm": "sha256",
        "timestampUrl": ""
      }
    },
    "security": {
      "csp": null
    },
    "updater": {
      "active": false
    },
    "windows": [
      {
        "fullscreen": false,
        "height": 600,
        "resizable": true,
        "title": "Tauri App",
        "width": 800
      }
    ]
  }
}

// 3. main.rs - Rust Backend
#![cfg_attr(
    all(not(debug_assertions), target_os = "windows"),
    windows_subsystem = "windows"
)]

use tauri::Manager;

// Simple greeting command
#[tauri::command]
fn greet(name: &str) -> String {
    format!("Hello, {}! You've been greeted from Rust!", name)
}

// Command to get system info
#[tauri::command]
fn get_system_info() -> serde_json::Value {
    serde_json::json!({
        "platform": std::env::consts::OS,
        "arch": std::env::consts::ARCH,
        "version": env!("CARGO_PKG_VERSION"),
        "name": env!("CARGO_PKG_NAME")
    })
}

// Command with async operation
#[tauri::command]
async fn delayed_message(delay_ms: u64, message: String) -> String {
    tokio::time::sleep(tokio::time::Duration::from_millis(delay_ms)).await;
    format!("Delayed message: {}", message)
}

// Command that returns Result
#[tauri::command]
fn validate_input(input: String) -> Result<String, String> {
    if input.trim().is_empty() {
        Err("Input cannot be empty".to_string())
    } else if input.len() > 100 {
        Err("Input too long (max 100 characters)".to_string())
    } else {
        Ok(format!("Valid input: {}", input))
    }
}

// File operations
#[tauri::command]
async fn read_file_content(path: String) -> Result<String, String> {
    use std::fs;

    match fs::read_to_string(&path) {
        Ok(content) => Ok(content),
        Err(e) => Err(format!("Failed to read file: {}", e))
    }
}

#[tauri::command]
async fn write_file_content(path: String, content: String) -> Result<(), String> {
    use std::fs;

    match fs::write(&path, content) {
        Ok(_) => Ok(()),
        Err(e) => Err(format!("Failed to write file: {}", e))
    }
}

fn main() {
    tauri::Builder::default()
        .setup(|app| {
            // Get the main window
            let window = app.get_window("main").unwrap();

            // Set window title
            window.set_title("Tauri Hello World").unwrap();

            Ok(())
        })
        .invoke_handler(tauri::generate_handler![
            greet,
            get_system_info,
            delayed_message,
            validate_input,
            read_file_content,
            write_file_content
        ])
        .run(tauri::generate_context!())
        .expect("error while running tauri application");
}

// 4. build.rs - Build Script
fn main() {
    tauri_build::build()
}

// 5. HTML Frontend (index.html)
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Tauri App</title>
    <style>
        body {
            font-family: Arial, sans-serif;
            max-width: 800px;
            margin: 0 auto;
            padding: 20px;
            background-color: #f5f5f5;
        }
        .container {
            background: white;
            padding: 30px;
            border-radius: 10px;
            box-shadow: 0 2px 10px rgba(0,0,0,0.1);
        }
        .input-group {
            margin: 20px 0;
        }
        input, button {
            padding: 10px;
            margin: 5px;
            border: 1px solid #ddd;
            border-radius: 5px;
        }
        button {
            background-color: #007bff;
            color: white;
            cursor: pointer;
        }
        button:hover {
            background-color: #0056b3;
        }
        .result {
            margin-top: 10px;
            padding: 10px;
            background-color: #f8f9fa;
            border-radius: 5px;
            border-left: 4px solid #007bff;
        }
        .error {
            border-left-color: #dc3545;
            background-color: #f8d7da;
            color: #721c24;
        }
    </style>
</head>
<body>
    <div class="container">
        <h1>Tauri Hello World Application</h1>

        <div class="input-group">
            <input type="text" id="nameInput" placeholder="Enter your name" value="Tauri">
            <button onclick="greetUser()">Greet</button>
        </div>
        <div id="greetResult" class="result" style="display: none;"></div>

        <div class="input-group">
            <button onclick="getSystemInfo()">Get System Info</button>
        </div>
        <div id="systemInfoResult" class="result" style="display: none;"></div>

        <div class="input-group">
            <input type="text" id="delayMessage" placeholder="Message for delay" value="Hello from the future!">
            <input type="number" id="delayMs" placeholder="Delay (ms)" value="2000">
            <button onclick="sendDelayedMessage()">Send Delayed Message</button>
        </div>
        <div id="delayResult" class="result" style="display: none;"></div>

        <div class="input-group">
            <input type="text" id="validationInput" placeholder="Text to validate (max 100 chars)">
            <button onclick="validateInput()">Validate</button>
        </div>
        <div id="validationResult" class="result" style="display: none;"></div>

        <div class="input-group">
            <input type="text" id="filePath" placeholder="File path">
            <button onclick="readFile()">Read File</button>
            <button onclick="writeFile()">Write File</button>
        </div>
        <div id="fileResult" class="result" style="display: none;"></div>
    </div>

    <script>
        const { invoke } = window.__TAURI__.core;

        async function greetUser() {
            const name = document.getElementById('nameInput').value;
            const resultDiv = document.getElementById('greetResult');

            try {
                const response = await invoke('greet', { name });
                resultDiv.textContent = response;
                resultDiv.className = 'result';
                resultDiv.style.display = 'block';
            } catch (error) {
                resultDiv.textContent = 'Error: ' + error;
                resultDiv.className = 'result error';
                resultDiv.style.display = 'block';
            }
        }

        async function getSystemInfo() {
            const resultDiv = document.getElementById('systemInfoResult');

            try {
                const info = await invoke('get_system_info');
                const formatted = 'Platform: ' + info.platform +
                               ', Arch: ' + info.arch +
                               ', Version: ' + info.version;
                resultDiv.textContent = formatted;
                resultDiv.className = 'result';
                resultDiv.style.display = 'block';
            } catch (error) {
                resultDiv.textContent = 'Error: ' + error;
                resultDiv.className = 'result error';
                resultDiv.style.display = 'block';
            }
        }

        async function sendDelayedMessage() {
            const message = document.getElementById('delayMessage').value;
            const delayMs = parseInt(document.getElementById('delayMs').value);
            const resultDiv = document.getElementById('delayResult');

            resultDiv.textContent = 'Sending delayed message...';
            resultDiv.className = 'result';
            resultDiv.style.display = 'block';

            try {
                const response = await invoke('delayed_message', { delayMs, message });
                resultDiv.textContent = response;
            } catch (error) {
                resultDiv.textContent = 'Error: ' + error;
                resultDiv.className = 'result error';
            }
        }

        async function validateInput() {
            const input = document.getElementById('validationInput').value;
            const resultDiv = document.getElementById('validationResult');

            try {
                const response = await invoke('validate_input', { input });
                resultDiv.textContent = response;
                resultDiv.className = 'result';
                resultDiv.style.display = 'block';
            } catch (error) {
                resultDiv.textContent = 'Validation Error: ' + error;
                resultDiv.className = 'result error';
                resultDiv.style.display = 'block';
            }
        }

        async function readFile() {
            const path = document.getElementById('filePath').value;
            const resultDiv = document.getElementById('fileResult');

            if (!path) {
                resultDiv.textContent = 'Please enter a file path';
                resultDiv.className = 'result error';
                resultDiv.style.display = 'block';
                return;
            }

            try {
                const content = await invoke('read_file_content', { path });
                resultDiv.textContent = 'File content:\n' + content;
                resultDiv.className = 'result';
                resultDiv.style.display = 'block';
            } catch (error) {
                resultDiv.textContent = 'Error reading file: ' + error;
                resultDiv.className = 'result error';
                resultDiv.style.display = 'block';
            }
        }

        async function writeFile() {
            const path = document.getElementById('filePath').value;
            const resultDiv = document.getElementById('fileResult');

            if (!path) {
                resultDiv.textContent = 'Please enter a file path';
                resultDiv.className = 'result error';
                resultDiv.style.display = 'block';
                return;
            }

            const content = 'Hello from Tauri! Written at ' + new Date().toISOString();

            try {
                await invoke('write_file_content', { path, content });
                resultDiv.textContent = 'File written successfully!';
                resultDiv.className = 'result';
                resultDiv.style.display = 'block';
            } catch (error) {
                resultDiv.textContent = 'Error writing file: ' + error;
                resultDiv.className = 'result error';
                resultDiv.style.display = 'block';
            }
        }
    </script>
</body>
</html>

// 6. package.json for Frontend Dependencies
{
  "name": "tauri-app",
  "private": true,
  "version": "0.1.0",
  "type": "module",
  "scripts": {
    "dev": "vite",
    "build": "vite build",
    "preview": "vite preview",
    "tauri": "tauri"
  },
  "dependencies": {
    "@tauri-apps/api": "^1.0.0"
  },
  "devDependencies": {
    "@tauri-apps/cli": "^1.0.0",
    "vite": "^4.0.0"
  }
}

// 7. Development Commands
/*
# Install dependencies
npm install

# Start development server
npm run tauri dev

# Build application
npm run tauri build

# Development only (frontend)
npm run dev
*/
CoderustIntermediate

Tauri File Manager Application

Complete file manager application with drag-and-drop, file operations, and system integration

Difficulty

8/10

Estimated time

45 min

Tags

tauri, file manager, desktop, rust

Prerequisites

Tauri basics, Rust async programming, Advanced HTML/CSS/JavaScript

rust
// Tauri File Manager Application

// 1. main.rs - Enhanced Rust Backend
#![cfg_attr(
    all(not(debug_assertions), target_os = "windows"),
    windows_subsystem = "windows"
)]

use tauri::{Manager, Menu, MenuItem, Submenu};
use std::path::PathBuf;
use std::fs;
use serde::{Deserialize, Serialize};

#[derive(Debug, Serialize, Deserialize)]
struct FileInfo {
    name: String,
    path: String,
    is_dir: bool,
    size: u64,
    modified: String,
    extension: Option<String>,
}

#[derive(Debug, Serialize, Deserialize)]
struct DirectoryContents {
    path: String,
    files: Vec<FileInfo>,
    parent: Option<String>,
}

// List directory contents
#[tauri::command]
async fn list_directory(path: String) -> Result<DirectoryContents, String> {
    let dir_path = PathBuf::from(&path);

    if !dir_path.exists() || !dir_path.is_dir() {
        return Err("Invalid directory path".to_string());
    }

    let mut files = Vec::new();

    match fs::read_dir(&dir_path) {
        Ok(entries) => {
            for entry in entries {
                if let Ok(entry) = entry {
                    let metadata = match entry.metadata() {
                        Ok(meta) => meta,
                        Err(_) => continue,
                    };

                    let file_name = entry.file_name().to_string_lossy().to_string();
                    let file_path = entry.path().to_string_lossy().to_string();
                    let is_dir = metadata.is_dir();
                    let size = metadata.len() as u64;

                    let modified = metadata.modified()
                        .ok()
                        .and_then(|time| {
                            time.duration_since(std::time::SystemTime::UNIX_EPOCH)
                                .ok()
                                .map(|d| d.as_secs())
                        })
                        .map(|timestamp| {
                            chrono::DateTime::from_timestamp(timestamp as i64, 0)
                                .unwrap_or_default()
                                .format("%Y-%m-%d %H:%M:%S")
                                .to_string()
                        })
                        .unwrap_or_else(|| "Unknown".to_string());

                    let extension = if !is_dir {
                        PathBuf::from(&file_name)
                            .extension()
                            .and_then(|ext| ext.to_str())
                            .map(|s| s.to_lowercase())
                    } else {
                        None
                    };

                    files.push(FileInfo {
                        name: file_name,
                        path: file_path,
                        is_dir,
                        size,
                        modified,
                        extension,
                    });
                }
            }
        }
        Err(e) => return Err(format!("Failed to read directory: {}", e)),
    }

    // Sort files: directories first, then files, both alphabetically
    files.sort_by(|a, b| {
        match (a.is_dir, b.is_dir) {
            (true, false) => std::cmp::Ordering::Less,
            (false, true) => std::cmp::Ordering::Greater,
            _ => a.name.cmp(&b.name),
        }
    });

    let parent = dir_path.parent()
        .map(|p| p.to_string_lossy().to_string());

    Ok(DirectoryContents {
        path,
        files,
        parent,
    })
}

// Create directory
#[tauri::command]
async fn create_directory(path: String) -> Result<(), String> {
    match fs::create_dir(&path) {
        Ok(_) => Ok(()),
        Err(e) => Err(format!("Failed to create directory: {}", e))
    }
}

// Delete file or directory
#[tauri::command]
async fn delete_item(path: String, is_dir: bool) -> Result<(), String> {
    let path_buf = PathBuf::from(&path);

    let result = if is_dir {
        fs::remove_dir_all(&path_buf)
    } else {
        fs::remove_file(&path_buf)
    };

    match result {
        Ok(_) => Ok(()),
        Err(e) => Err(format!("Failed to delete item: {}", e))
    }
}

// Copy file
#[tauri::command]
async fn copy_file(source: String, destination: String) -> Result<(), String> {
    match fs::copy(&source, &destination) {
        Ok(_) => Ok(()),
        Err(e) => Err(format!("Failed to copy file: {}", e))
    }
}

// Move/rename file
#[tauri::command]
async fn move_file(source: String, destination: String) -> Result<(), String> {
    match fs::rename(&source, &destination) {
        Ok(_) => Ok(()),
        Err(e) => Err(format!("Failed to move file: {}", e))
    }
}

// Get file content (for text files)
#[tauri::command]
async fn get_file_content(path: String) -> Result<String, String> {
    match fs::read_to_string(&path) {
        Ok(content) => Ok(content),
        Err(e) => Err(format!("Failed to read file: {}", e))
    }
}

// Save file content
#[tauri::command]
async fn save_file_content(path: String, content: String) -> Result<(), String> {
    match fs::write(&path, content) {
        Ok(_) => Ok(()),
        Err(e) => Err(format!("Failed to write file: {}", e))
    }
}

// Get system drives/volumes
#[tauri::command]
async fn get_system_drives() -> Result<Vec<String>, String> {
    #[cfg(windows)]
    {
        use std::ffi::OsStr;
        use std::os::windows::ffi::OsStrExt;

        let mut drives = Vec::new();
        let mut buffer = [0u16; 256];

        unsafe {
            let result = windows_sys::Win32::Storage::FileSystem::GetLogicalDriveStringsW(
                buffer.len() as u32,
                buffer.as_mut_ptr()
            );

            if result > 0 {
                let mut pos = 0;
                while pos < result as usize {
                    let mut end = pos;
                    while buffer[end] != 0 && end < buffer.len() {
                        end += 1;
                    }

                    if end > pos {
                        let drive_str = OsStr::new_wide(&buffer[pos..end])
                            .to_string_lossy()
                            .to_string();
                        drives.push(drive_str);
                    }

                    pos = end + 1;
                }
            }
        }

        Ok(drives)
    }

    #[cfg(unix)]
    {
        Ok(vec!["/".to_string()])
    }

    #[cfg(not(any(windows, unix)))]
    {
        Ok(vec![])
    }
}

// Open file with default application
#[tauri::command]
async fn open_file_with_default(path: String) -> Result<(), String> {
    #[cfg(windows)]
    {
        use std::process::Command;

        match Command::new("cmd")
            .args(["/C", "start", "", &path])
            .spawn()
        {
            Ok(_) => Ok(()),
            Err(e) => Err(format!("Failed to open file: {}", e))
        }
    }

    #[cfg(unix)]
    {
        use std::process::Command;

        match Command::new("open")
            .arg(&path)
            .spawn()
        {
            Ok(_) => Ok(()),
            Err(e) => Err(format!("Failed to open file: {}", e))
        }
    }

    #[cfg(not(any(windows, unix)))]
    {
        Err("Platform not supported".to_string())
    }
}

fn main() {
    // Create application menu
    let menu = Menu::new()
        .add_submenu(Submenu::new(
            "File",
            Menu::new()
                .add_native_item(MenuItem::Separator)
                .add_item(MenuItem::new("Exit", true, None, None, None, None, None, None))
        ))
        .add_submenu(Submenu::new(
            "Help",
            Menu::new()
                .add_item(MenuItem::new("About", true, None, None, None, None, None, None))
        ));

    tauri::Builder::default()
        .menu(menu)
        .setup(|app| {
            let window = app.get_window("main").unwrap();

            // Set window properties
            window.set_title("Tauri File Manager").unwrap();
            window.set_min_size(Some((800.0, 600.0)).into()).unwrap();

            Ok(())
        })
        .invoke_handler(tauri::generate_handler![
            list_directory,
            create_directory,
            delete_item,
            copy_file,
            move_file,
            get_file_content,
            save_file_content,
            get_system_drives,
            open_file_with_default
        ])
        .run(tauri::generate_context!())
        .expect("error while running tauri application");
}

// 2. HTML Frontend with Enhanced UI
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Tauri File Manager</title>
    <style>
        * {
            margin: 0;
            padding: 0;
            box-sizing: border-box;
        }

        body {
            font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
            height: 100vh;
            display: flex;
            flex-direction: column;
            background-color: #f5f5f5;
        }

        .header {
            background: #2c3e50;
            color: white;
            padding: 10px 20px;
            display: flex;
            align-items: center;
            gap: 10px;
        }

        .path-bar {
            flex: 1;
            background: #34495e;
            border: none;
            color: white;
            padding: 8px 12px;
            border-radius: 4px;
            font-family: inherit;
        }

        .main-container {
            flex: 1;
            display: flex;
            overflow: hidden;
        }

        .sidebar {
            width: 200px;
            background: white;
            border-right: 1px solid #ddd;
            overflow-y: auto;
        }

        .drive-item {
            padding: 10px 20px;
            cursor: pointer;
            border-bottom: 1px solid #f0f0f0;
        }

        .drive-item:hover {
            background: #e3f2fd;
        }

        .drive-item.active {
            background: #2196f3;
            color: white;
        }

        .file-list {
            flex: 1;
            background: white;
            overflow: auto;
        }

        .file-item {
            display: flex;
            align-items: center;
            padding: 12px 20px;
            border-bottom: 1px solid #f0f0f0;
            cursor: pointer;
            user-select: none;
        }

        .file-item:hover {
            background: #f5f5f5;
        }

        .file-item.selected {
            background: #e3f2fd;
        }

        .file-item.dragging {
            opacity: 0.5;
        }

        .file-icon {
            width: 20px;
            height: 20px;
            margin-right: 12px;
            font-size: 16px;
        }

        .file-info {
            flex: 1;
            display: flex;
            justify-content: space-between;
            align-items: center;
        }

        .file-name {
            font-weight: 500;
        }

        .file-meta {
            font-size: 12px;
            color: #666;
            display: flex;
            gap: 15px;
        }

        .context-menu {
            position: fixed;
            background: white;
            border: 1px solid #ddd;
            border-radius: 4px;
            box-shadow: 0 2px 10px rgba(0,0,0,0.1);
            z-index: 1000;
            display: none;
        }

        .context-menu-item {
            padding: 10px 20px;
            cursor: pointer;
            border-bottom: 1px solid #f0f0f0;
        }

        .context-menu-item:hover {
            background: #f0f0f0;
        }

        .context-menu-item:last-child {
            border-bottom: none;
        }

        .modal {
            display: none;
            position: fixed;
            top: 0;
            left: 0;
            width: 100%;
            height: 100%;
            background: rgba(0,0,0,0.5);
            z-index: 2000;
            align-items: center;
            justify-content: center;
        }

        .modal-content {
            background: white;
            padding: 30px;
            border-radius: 8px;
            min-width: 400px;
            box-shadow: 0 4px 20px rgba(0,0,0,0.2);
        }

        .modal-header {
            margin-bottom: 20px;
        }

        .modal-body {
            margin-bottom: 20px;
        }

        .modal-footer {
            display: flex;
            justify-content: flex-end;
            gap: 10px;
        }

        input, textarea {
            width: 100%;
            padding: 10px;
            border: 1px solid #ddd;
            border-radius: 4px;
            font-family: inherit;
        }

        button {
            padding: 10px 20px;
            border: none;
            border-radius: 4px;
            cursor: pointer;
            font-family: inherit;
        }

        .btn-primary {
            background: #2196f3;
            color: white;
        }

        .btn-primary:hover {
            background: #1976d2;
        }

        .btn-secondary {
            background: #6c757d;
            color: white;
        }

        .btn-secondary:hover {
            background: #5a6268;
        }

        .btn-danger {
            background: #dc3545;
            color: white;
        }

        .btn-danger:hover {
            background: #c82333;
        }

        .toolbar {
            background: white;
            padding: 10px 20px;
            border-bottom: 1px solid #ddd;
            display: flex;
            gap: 10px;
        }

        .toolbar button {
            padding: 8px 16px;
        }

        .loading {
            display: flex;
            align-items: center;
            justify-content: center;
            height: 100%;
            font-size: 18px;
            color: #666;
        }
    </style>
</head>
<body>
    <div class="header">
        <input type="text" class="path-bar" id="pathBar" readonly>
        <button onclick="navigateUp()">↑</button>
        <button onclick="refreshDirectory()">↻</button>
    </div>

    <div class="toolbar">
        <button onclick="createFolder()">📁 New Folder</button>
        <button onclick="createFile()">📄 New File</button>
        <button onclick="deleteSelected()">🗑️ Delete</button>
        <button onclick="copySelected()">📋 Copy</button>
        <button onclick="pasteItems()">📄 Paste</button>
    </div>

    <div class="main-container">
        <div class="sidebar" id="sidebar">
            <!-- Drives will be populated here -->
        </div>

        <div class="file-list" id="fileList">
            <div class="loading">Loading...</div>
        </div>
    </div>

    <div class="context-menu" id="contextMenu">
        <div class="context-menu-item" onclick="openItem()">Open</div>
        <div class="context-menu-item" onclick="renameItem()">Rename</div>
        <div class="context-menu-item" onclick="deleteItem()">Delete</div>
        <div class="context-menu-item" onclick="copyItem()">Copy</div>
    </div>

    <!-- Create/Name Modal -->
    <div class="modal" id="nameModal">
        <div class="modal-content">
            <div class="modal-header">
                <h2 id="modalTitle">Create New</h2>
            </div>
            <div class="modal-body">
                <input type="text" id="nameInput" placeholder="Enter name">
            </div>
            <div class="modal-footer">
                <button class="btn-secondary" onclick="closeModal()">Cancel</button>
                <button class="btn-primary" onclick="confirmNameAction()">Create</button>
            </div>
        </div>
    </div>

    <!-- File Editor Modal -->
    <div class="modal" id="editorModal">
        <div class="modal-content" style="width: 80%; height: 80%;">
            <div class="modal-header">
                <h2 id="editorTitle">Edit File</h2>
            </div>
            <div class="modal-body" style="height: calc(100% - 120px);">
                <textarea id="editorContent" style="height: 100%; resize: none;"></textarea>
            </div>
            <div class="modal-footer">
                <button class="btn-secondary" onclick="closeEditor()">Cancel</button>
                <button class="btn-primary" onclick="saveFile()">Save</button>
            </div>
        </div>
    </div>

    <script>
        const { invoke } = window.__TAURI__.core;

        let currentPath = '';
        let selectedFile = null;
        let clipboard = null;

        // Initialize application
        async function init() {
            await loadSystemDrives();
            setupEventListeners();
        }

        // Load system drives
        async function loadSystemDrives() {
            try {
                const drives = await invoke('get_system_drives');
                const sidebar = document.getElementById('sidebar');
                sidebar.innerHTML = '';

                drives.forEach(drive => {
                    const item = document.createElement('div');
                    item.className = 'drive-item';
                    item.textContent = drive;
                    item.onclick = () => navigateToPath(drive);
                    sidebar.appendChild(item);
                });

                // Navigate to first drive
                if (drives.length > 0) {
                    navigateToPath(drives[0]);
                }
            } catch (error) {
                console.error('Failed to load drives:', error);
            }
        }

        // Navigate to specific path
        async function navigateToPath(path) {
            currentPath = path;
            document.getElementById('pathBar').value = path;

            // Update sidebar active state
            document.querySelectorAll('.drive-item').forEach(item => {
                item.classList.toggle('active', item.textContent.trim() === path.trim());
            });

            await loadDirectory(path);
        }

        // Load directory contents
        async function loadDirectory(path) {
            const fileList = document.getElementById('fileList');
            fileList.innerHTML = '<div class="loading">Loading...</div>';

            try {
                const contents = await invoke('list_directory', { path });
                renderFileList(contents);
            } catch (error) {
                fileList.innerHTML = '<div class="loading">Error: ' + error + '</div>';
            }
        }

        // Render file list
        function renderFileList(contents) {
            const fileList = document.getElementById('fileList');
            fileList.innerHTML = '';

            if (contents.parent) {
                const parentItem = createFileItem({
                    name: '..',
                    path: contents.parent,
                    is_dir: true,
                    size: 0,
                    modified: '',
                    extension: null
                });
                fileList.appendChild(parentItem);
            }

            contents.files.forEach(file => {
                const fileItem = createFileItem(file);
                fileList.appendChild(fileItem);
            });
        }

        // Create file item element
        function createFileItem(file) {
            const item = document.createElement('div');
            item.className = 'file-item';
            item.dataset.path = file.path;
            item.dataset.isDirectory = file.is_dir;

            const icon = file.is_dir ? '📁' : getFileIcon(file.extension);
            const size = file.is_dir ? '—' : formatFileSize(file.size);

            item.innerHTML = `
                <div class="file-icon">${icon}</div>
                <div class="file-info">
                    <span class="file-name">${file.name}</span>
                    <div class="file-meta">
                        <span>${size}</span>
                        <span>${file.modified}</span>
                    </div>
                </div>
            `;

            item.onclick = () => handleFileClick(file);
            item.ondblclick = () => handleFileDoubleClick(file);
            item.oncontextmenu = (e) => showContextMenu(e, file);

            // Drag and drop
            item.draggable = true;
            item.ondragstart = (e) => handleDragStart(e, file);
            item.ondragover = (e) => handleDragOver(e);
            item.ondrop = (e) => handleDrop(e, file);
            item.ondragend = handleDragEnd;

            return item;
        }

        // Get file icon based on extension
        function getFileIcon(extension) {
            const iconMap = {
                'txt': '📄',
                'pdf': '📑',
                'doc': '📝',
                'docx': '📝',
                'xls': '📊',
                'xlsx': '📊',
                'jpg': '🖼️',
                'jpeg': '🖼️',
                'png': '🖼️',
                'gif': '🖼️',
                'mp4': '🎬',
                'mp3': '🎵',
                'zip': '🗜️',
                'exe': '⚙️',
                'js': '📜',
                'html': '🌐',
                'css': '🎨',
                'json': '📋',
                'md': '📖'
            };

            return iconMap[extension] || '📄';
        }

        // Format file size
        function formatFileSize(bytes) {
            if (bytes === 0) return '0 B';

            const k = 1024;
            const sizes = ['B', 'KB', 'MB', 'GB'];
            const i = Math.floor(Math.log(bytes) / Math.log(k));

            return parseFloat((bytes / Math.pow(k, i)).toFixed(1)) + ' ' + sizes[i];
        }

        // Handle file click (selection)
        function handleFileClick(file) {
            document.querySelectorAll('.file-item').forEach(item => {
                item.classList.remove('selected');
            });

            const item = document.querySelector(`[data-path="${file.path}"]`);
            if (item) {
                item.classList.add('selected');
                selectedFile = file;
            }
        }

        // Handle file double click (open)
        async function handleFileDoubleClick(file) {
            if (file.is_dir) {
                await navigateToPath(file.path);
            } else {
                await openFile(file);
            }
        }

        // Open file
        async function openFile(file) {
            const textExtensions = ['txt', 'js', 'html', 'css', 'json', 'md', 'xml', 'csv', 'log'];

            if (textExtensions.includes(file.extension || '')) {
                try {
                    const content = await invoke('get_file_content', { path: file.path });
                    showFileEditor(file, content);
                } catch (error) {
                    console.error('Failed to open file:', error);
                }
            } else {
                try {
                    await invoke('open_file_with_default', { path: file.path });
                } catch (error) {
                    console.error('Failed to open file with default app:', error);
                }
            }
        }

        // Show file editor
        function showFileEditor(file, content) {
            document.getElementById('editorTitle').textContent = `Edit: ${file.name}`;
            document.getElementById('editorContent').value = content;
            document.getElementById('editorModal').style.display = 'flex';

            // Store current file path for saving
            window.currentEditingFile = file.path;
        }

        // Save file
        async function saveFile() {
            if (!window.currentEditingFile) return;

            const content = document.getElementById('editorContent').value;

            try {
                await invoke('save_file_content', {
                    path: window.currentEditingFile,
                    content
                });
                closeEditor();
            } catch (error) {
                alert('Failed to save file: ' + error);
            }
        }

        // Close editor
        function closeEditor() {
            document.getElementById('editorModal').style.display = 'none';
            delete window.currentEditingFile;
        }

        // Navigate up
        function navigateUp() {
            const parts = currentPath.split(/[/\\]/);
            if (parts.length > 1) {
                parts.pop();
                const parentPath = parts.join('/') || (currentPath.startsWith('/') ? '/' : '');
                navigateToPath(parentPath);
            }
        }

        // Refresh directory
        function refreshDirectory() {
            loadDirectory(currentPath);
        }

        // Context menu
        function showContextMenu(event, file) {
            event.preventDefault();
            selectedFile = file;

            const menu = document.getElementById('contextMenu');
            menu.style.display = 'block';
            menu.style.left = event.pageX + 'px';
            menu.style.top = event.pageY + 'px';
        }

        // Close context menu
        function hideContextMenu() {
            document.getElementById('contextMenu').style.display = 'none';
        }

        // Context menu actions
        async function openItem() {
            if (selectedFile) {
                await handleFileDoubleClick(selectedFile);
            }
            hideContextMenu();
        }

        async function deleteItem() {
            if (selectedFile && confirm(`Delete '${selectedFile.name}'?`)) {
                try {
                    await invoke('delete_item', {
                        path: selectedFile.path,
                        is_dir: selectedFile.is_dir
                    });
                    await loadDirectory(currentPath);
                } catch (error) {
                    alert('Failed to delete: ' + error);
                }
            }
            hideContextMenu();
        }

        function renameItem() {
            if (selectedFile) {
                showNameModal(`Rename '${selectedFile.name}'`, selectedFile.name, (newName) => {
                    const newPath = currentPath + '/' + newName;
                    moveSelectedFile(newPath);
                });
            }
            hideContextMenu();
        }

        function copyItem() {
            if (selectedFile) {
                clipboard = { ...selectedFile };
            }
            hideContextMenu();
        }

        // Drag and drop handlers
        function handleDragStart(event, file) {
            event.dataTransfer.effectAllowed = 'move';
            event.dataTransfer.setData('text/plain', file.path);
            event.target.classList.add('dragging');
        }

        function handleDragOver(event) {
            event.preventDefault();
            event.dataTransfer.dropEffect = 'move';
        }

        async function handleDrop(event, targetFile) {
            event.preventDefault();

            if (!targetFile.is_dir) return;

            const sourcePath = event.dataTransfer.getData('text/plain');

            try {
                const fileName = sourcePath.split(/[/\\]/).pop();
                const destinationPath = targetFile.path + '/' + fileName;

                await invoke('move_file', { source: sourcePath, destination: destinationPath });
                await loadDirectory(currentPath);
            } catch (error) {
                alert('Failed to move file: ' + error);
            }
        }

        function handleDragEnd(event) {
            event.target.classList.remove('dragging');
        }

        // Modal functions
        function showNameModal(title, defaultValue, callback) {
            document.getElementById('modalTitle').textContent = title;
            document.getElementById('nameInput').value = defaultValue || '';
            document.getElementById('nameModal').style.display = 'flex';

            window.nameModalCallback = callback;
        }

        function closeModal() {
            document.getElementById('nameModal').style.display = 'none';
            delete window.nameModalCallback;
        }

        function confirmNameAction() {
            const name = document.getElementById('nameInput').value.trim();

            if (name && window.nameModalCallback) {
                window.nameModalCallback(name);
            }

            closeModal();
        }

        // Toolbar actions
        function createFolder() {
            showNameModal('Create New Folder', '', (name) => {
                const path = currentPath + '/' + name;
                invoke('create_directory', { path })
                    .then(() => loadDirectory(currentPath))
                    .catch(error => alert('Failed to create folder: ' + error));
            });
        }

        function createFile() {
            showNameModal('Create New File', 'untitled.txt', (name) => {
                const path = currentPath + '/' + name;
                invoke('save_file_content', { path, content: '' })
                    .then(() => loadDirectory(currentPath))
                    .catch(error => alert('Failed to create file: ' + error));
            });
        }

        function deleteSelected() {
            if (selectedFile) {
                deleteItem();
            }
        }

        function copySelected() {
            if (selectedFile) {
                clipboard = { ...selectedFile };
            }
        }

        async function pasteItems() {
            if (!clipboard) return;

            const destinationPath = currentPath + '/' + clipboard.name;

            try {
                await invoke('copy_file', {
                    source: clipboard.path,
                    destination: destinationPath
                });
                await loadDirectory(currentPath);
            } catch (error) {
                alert('Failed to paste: ' + error);
            }
        }

        // Setup event listeners
        function setupEventListeners() {
            // Hide context menu on click outside
            document.addEventListener('click', hideContextMenu);

            // Keyboard shortcuts
            document.addEventListener('keydown', (event) => {
                if (event.key === 'Delete' && selectedFile) {
                    deleteSelected();
                } else if (event.ctrlKey && event.key === 'c' && selectedFile) {
                    copySelected();
                } else if (event.ctrlKey && event.key === 'v' && clipboard) {
                    pasteItems();
                }
            });

            // Modal close on escape
            document.addEventListener('keydown', (event) => {
                if (event.key === 'Escape') {
                    closeModal();
                    closeEditor();
                }
            });
        }

        // Initialize when DOM is loaded
        document.addEventListener('DOMContentLoaded', init);
    </script>
</body>
</html>
CoderustComplex

Tauri System Monitor Application

Real-time system monitoring dashboard with CPU, memory, disk usage and process management

Difficulty

9/10

Estimated time

60 min

Tags

tauri, system monitor, rust, performance

Prerequisites

Advanced Tauri, Rust async programming, Chart.js, System monitoring concepts

rust
// Tauri System Monitor Application

// 1. Cargo.toml with additional dependencies
[package]
name = "tauri-system-monitor"
version = "0.1.0"
edition = "2021"

[dependencies]
tauri = { version = "1.0", features = ["api-all"] }
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
sysinfo = "0.29"
chrono = { version = "0.4", features = ["serde"] }
tokio = { version = "1", features = ["time"] }

[build-dependencies]
tauri-build = { version = "1.0", features = [] }

[features]
default = ["custom-protocol"]
custom-protocol = ["tauri/custom-protocol"]

// 2. main.rs - System Monitor Backend
#![cfg_attr(
    all(not(debug_assertions), target_os = "windows"),
    windows_subsystem = "windows"
)]

use tauri::{Manager, State, Window};
use sysinfo::{System, SystemExt, ProcessExt, CpuExt, DiskExt, NetworkExt};
use std::sync::{Arc, Mutex};
use std::thread;
use std::time::Duration;
use serde::{Deserialize, Serialize};

// Shared system state
pub struct AppState {
    system: Arc<Mutex<System>>,
}

#[derive(Debug, Serialize, Deserialize)]
struct SystemInfo {
    cpu_usage: f32,
    memory_total: u64,
    memory_used: u64,
    memory_usage: f32,
    disk_total: u64,
    disk_used: u64,
    disk_usage: f32,
    uptime: u64,
    process_count: usize,
    load_average: [f64; 3],
}

#[derive(Debug, Serialize, Deserialize)]
struct ProcessInfo {
    pid: u32,
    name: String,
    cpu_usage: f32,
    memory_usage: u64,
    memory_percent: f32,
    status: String,
    start_time: u64,
}

#[derive(Debug, Serialize, Deserialize)]
struct DiskInfo {
    name: String,
    mount_point: String,
    file_system: String,
    total_space: u64,
    available_space: u64,
    used_space: u64,
    usage_percent: f32,
}

#[derive(Debug, Serialize, Deserialize)]
struct NetworkInfo {
    interface: String,
    data_received: u64,
    data_transmitted: u64,
    packets_received: u64,
    packets_transmitted: u64,
    errors_on_received: u64,
    errors_on_transmitted: u64,
}

// Get overall system information
#[tauri::command]
async fn get_system_info(state: State<'_, AppState>) -> Result<SystemInfo, String> {
    let system = state.system.lock().map_err(|e| e.to_string())?;
    system.refresh_all();

    let cpu_usage = system.global_cpu_info().cpu_usage();
    let memory_total = system.total_memory();
    let memory_used = system.used_memory();
    let memory_usage = (memory_used as f32 / memory_total as f32) * 100.0;

    // Calculate disk usage
    let mut disk_total = 0u64;
    let mut disk_used = 0u64;

    for disk in system.disks() {
        disk_total += disk.total_space();
        disk_used += disk.total_space() - disk.available_space();
    }

    let disk_usage = if disk_total > 0 {
        (disk_used as f32 / disk_total as f32) * 100.0
    } else {
        0.0
    };

    let uptime = system.uptime();
    let process_count = system.processes().len();

    // Get load average (Unix systems only)
    let load_average = sysinfo::get_current_pid()
        .ok()
        .and_then(|pid| system.process(pid))
        .map(|process| {
            // This is a simplified approach - in production you'd use platform-specific APIs
            [0.0, 0.0, 0.0] // Placeholder
        })
        .unwrap_or([0.0, 0.0, 0.0]);

    Ok(SystemInfo {
        cpu_usage,
        memory_total,
        memory_used,
        memory_usage,
        disk_total,
        disk_used,
        disk_usage,
        uptime,
        process_count,
        load_average,
    })
}

// Get process list
#[tauri::command]
async fn get_processes(state: State<'_, AppState>) -> Result<Vec<ProcessInfo>, String> {
    let system = state.system.lock().map_err(|e| e.to_string())?;
    system.refresh_processes();

    let total_memory = system.total_memory();
    let mut processes = Vec::new();

    for (pid, process) in system.processes() {
        let memory_percent = (process.memory() as f32 / total_memory as f32) * 100.0;

        processes.push(ProcessInfo {
            pid: pid.as_u32(),
            name: process.name().to_string(),
            cpu_usage: process.cpu_usage(),
            memory_usage: process.memory(),
            memory_percent,
            status: format!("{:?}", process.status()),
            start_time: process.start_time(),
        });
    }

    // Sort by CPU usage (descending)
    processes.sort_by(|a, b| b.cpu_usage.partial_cmp(&a.cpu_usage).unwrap_or(std::cmp::Ordering::Equal));

    // Limit to top 50 processes
    processes.truncate(50);

    Ok(processes)
}

// Get disk information
#[tauri::command]
async fn get_disks(state: State<'_, AppState>) -> Result<Vec<DiskInfo>, String> {
    let system = state.system.lock().map_err(|e| e.to_string())?;
    system.refresh_disks();

    let mut disks = Vec::new();

    for disk in system.disks() {
        let total_space = disk.total_space();
        let available_space = disk.available_space();
        let used_space = total_space - available_space;
        let usage_percent = if total_space > 0 {
            (used_space as f32 / total_space as f32) * 100.0
        } else {
            0.0
        };

        disks.push(DiskInfo {
            name: disk.name().to_string_lossy().to_string(),
            mount_point: disk.mount_point().to_string_lossy().to_string(),
            file_system: std::str::from_utf8(disk.file_system()).unwrap_or("Unknown").to_string(),
            total_space,
            available_space,
            used_space,
            usage_percent,
        });
    }

    Ok(disks)
}

// Get network information
#[tauri::command]
async fn get_network_info(state: State<'_, AppState>) -> Result<Vec<NetworkInfo>, String> {
    let system = state.system.lock().map_err(|e| e.to_string())?;
    system.refresh_networks();

    let mut networks = Vec::new();

    for (interface_name, data) in system.networks() {
        networks.push(NetworkInfo {
            interface: interface_name.clone(),
            data_received: data.total_received(),
            data_transmitted: data.total_transmitted(),
            packets_received: data.total_packets_received(),
            packets_transmitted: data.total_packets_transmitted(),
            errors_on_received: data.errors_on_received(),
            errors_on_transmitted: data.errors_on_transmitted(),
        });
    }

    Ok(networks)
}

// Kill process
#[tauri::command]
async fn kill_process(pid: u32, state: State<'_, AppState>) -> Result<bool, String> {
    let system = state.system.lock().map_err(|e| e.to_string())?;

    // Convert u32 to sysinfo's Pid type
    if let Some(sys_pid) = sysinfo::Pid::from_u32(pid) {
        if system.process(sys_pid).is_some() {
            // In a real implementation, you would use platform-specific APIs to kill the process
            // For now, we'll just return true
            Ok(true)
        } else {
            Err("Process not found".to_string())
        }
    } else {
        Err("Invalid PID".to_string())
    }
}

// Start background monitoring
#[tauri::command]
async fn start_monitoring(window: Window, state: State<'_, AppState>) -> Result<(), String> {
    let window_clone = window.clone();
    let system_state = state.inner().clone();

    thread::spawn(move || {
        loop {
            // Update system info every 2 seconds
            if let Err(_) = window_clone.emit("system-update", "refresh") {
                // Window closed, exit thread
                break;
            }

            thread::sleep(Duration::from_secs(2));
        }
    });

    Ok(())
}

fn main() {
    let mut system = System::new();
    system.refresh_all();

    let app_state = AppState {
        system: Arc::new(Mutex::new(system)),
    };

    tauri::Builder::default()
        .manage(app_state)
        .setup(|app| {
            let window = app.get_window("main").unwrap();

            // Set window properties
            window.set_title("System Monitor").unwrap();
            window.set_min_size(Some((1000.0, 700.0)).into()).unwrap();

            // Start monitoring
            let state = app.state::<AppState>();
            let window_clone = window.clone();
            tauri::async_runtime::spawn(async move {
                if let Err(e) = start_monitoring(window_clone, state).await {
                    eprintln!("Failed to start monitoring: {}", e);
                }
            });

            Ok(())
        })
        .invoke_handler(tauri::generate_handler![
            get_system_info,
            get_processes,
            get_disks,
            get_network_info,
            kill_process,
            start_monitoring
        ])
        .run(tauri::generate_context!())
        .expect("error while running tauri application");
}

// 3. System Monitor Frontend
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>System Monitor</title>
    <script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
    <style>
        * {
            margin: 0;
            padding: 0;
            box-sizing: border-box;
        }

        body {
            font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
            background: #1e1e1e;
            color: #ffffff;
            overflow: hidden;
        }

        .container {
            height: 100vh;
            display: flex;
            flex-direction: column;
        }

        .header {
            background: #2d2d30;
            padding: 15px 20px;
            border-bottom: 1px solid #3e3e42;
        }

        .header h1 {
            font-size: 18px;
            font-weight: 400;
        }

        .main-content {
            flex: 1;
            display: flex;
            overflow: hidden;
        }

        .sidebar {
            width: 250px;
            background: #252526;
            border-right: 1px solid #3e3e42;
            overflow-y: auto;
        }

        .nav-item {
            padding: 12px 20px;
            cursor: pointer;
            border-left: 3px solid transparent;
            transition: all 0.2s;
        }

        .nav-item:hover {
            background: #2d2d30;
        }

        .nav-item.active {
            background: #2d2d30;
            border-left-color: #007acc;
        }

        .content {
            flex: 1;
            overflow-y: auto;
            padding: 20px;
        }

        .dashboard {
            display: none;
        }

        .dashboard.active {
            display: block;
        }

        .metrics-grid {
            display: grid;
            grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
            gap: 20px;
            margin-bottom: 30px;
        }

        .metric-card {
            background: #2d2d30;
            border: 1px solid #3e3e42;
            border-radius: 8px;
            padding: 20px;
        }

        .metric-header {
            display: flex;
            justify-content: space-between;
            align-items: center;
            margin-bottom: 15px;
        }

        .metric-title {
            font-size: 14px;
            color: #cccccc;
            text-transform: uppercase;
            letter-spacing: 0.5px;
        }

        .metric-value {
            font-size: 24px;
            font-weight: bold;
            color: #ffffff;
        }

        .metric-unit {
            font-size: 14px;
            color: #cccccc;
            margin-left: 5px;
        }

        .chart-container {
            height: 200px;
            margin-top: 15px;
        }

        .process-table {
            width: 100%;
            background: #2d2d30;
            border: 1px solid #3e3e42;
            border-radius: 8px;
            overflow: hidden;
        }

        .process-table table {
            width: 100%;
            border-collapse: collapse;
        }

        .process-table th,
        .process-table td {
            padding: 12px 15px;
            text-align: left;
            border-bottom: 1px solid #3e3e42;
        }

        .process-table th {
            background: #3e3e42;
            font-weight: 600;
            color: #cccccc;
            text-transform: uppercase;
            font-size: 12px;
            letter-spacing: 0.5px;
        }

        .process-table tr:hover {
            background: #1e1e1e;
        }

        .progress-bar {
            width: 100%;
            height: 8px;
            background: #3e3e42;
            border-radius: 4px;
            overflow: hidden;
        }

        .progress-fill {
            height: 100%;
            background: #007acc;
            transition: width 0.3s ease;
        }

        .progress-fill.high {
            background: #d9534f;
        }

        .progress-fill.medium {
            background: #f0ad4e;
        }

        .status-indicator {
            display: inline-block;
            width: 8px;
            height: 8px;
            border-radius: 50%;
            margin-right: 8px;
        }

        .status-running {
            background: #5cb85c;
        }

        .status-sleeping {
            background: #f0ad4e;
        }

        .status-zombie {
            background: #d9534f;
        }

        .refresh-btn {
            background: #007acc;
            color: white;
            border: none;
            padding: 8px 16px;
            border-radius: 4px;
            cursor: pointer;
            font-size: 12px;
            text-transform: uppercase;
            letter-spacing: 0.5px;
        }

        .refresh-btn:hover {
            background: #005a9e;
        }

        .tab-container {
            display: flex;
            gap: 10px;
            margin-bottom: 20px;
        }

        .tab {
            background: #2d2d30;
            border: 1px solid #3e3e42;
            padding: 10px 20px;
            border-radius: 4px;
            cursor: pointer;
            transition: all 0.2s;
        }

        .tab.active {
            background: #007acc;
            border-color: #007acc;
        }

        .tab:hover:not(.active) {
            background: #3e3e42;
        }

        @keyframes pulse {
            0% { opacity: 1; }
            50% { opacity: 0.5; }
            100% { opacity: 1; }
        }

        .updating {
            animation: pulse 1s infinite;
        }
    </style>
</head>
<body>
    <div class="container">
        <div class="header">
            <h1>🖥️ System Monitor</h1>
        </div>

        <div class="main-content">
            <div class="sidebar">
                <div class="nav-item active" data-panel="overview">📊 Overview</div>
                <div class="nav-item" data-panel="processes">⚙️ Processes</div>
                <div class="nav-item" data-panel="disks">💾 Disks</div>
                <div class="nav-item" data-panel="network">🌐 Network</div>
            </div>

            <div class="content">
                <!-- Overview Panel -->
                <div class="dashboard active" id="overview">
                    <div class="metrics-grid">
                        <div class="metric-card">
                            <div class="metric-header">
                                <span class="metric-title">CPU Usage</span>
                                <span class="metric-value" id="cpuUsage">0%</span>
                            </div>
                            <div class="progress-bar">
                                <div class="progress-fill" id="cpuProgress"></div>
                            </div>
                            <div class="chart-container">
                                <canvas id="cpuChart"></canvas>
                            </div>
                        </div>

                        <div class="metric-card">
                            <div class="metric-header">
                                <span class="metric-title">Memory Usage</span>
                                <span class="metric-value">
                                    <span id="memoryUsed">0</span>
                                    <span class="metric-unit">GB</span>
                                </span>
                            </div>
                            <div class="progress-bar">
                                <div class="progress-fill" id="memoryProgress"></div>
                            </div>
                            <div class="chart-container">
                                <canvas id="memoryChart"></canvas>
                            </div>
                        </div>

                        <div class="metric-card">
                            <div class="metric-header">
                                <span class="metric-title">Disk Usage</span>
                                <span class="metric-value" id="diskUsage">0%</span>
                            </div>
                            <div class="progress-bar">
                                <div class="progress-fill" id="diskProgress"></div>
                            </div>
                            <div class="chart-container">
                                <canvas id="diskChart"></canvas>
                            </div>
                        </div>

                        <div class="metric-card">
                            <div class="metric-header">
                                <span class="metric-title">System Info</span>
                                <button class="refresh-btn" onclick="refreshSystemInfo()">Refresh</button>
                            </div>
                            <div style="margin-top: 15px;">
                                <div style="margin-bottom: 10px;">
                                    <strong>Uptime:</strong> <span id="uptime">0h 0m</span>
                                </div>
                                <div style="margin-bottom: 10px;">
                                    <strong>Processes:</strong> <span id="processCount">0</span>
                                </div>
                                <div style="margin-bottom: 10px;">
                                    <strong>Total Memory:</strong> <span id="totalMemory">0 GB</span>
                                </div>
                                <div>
                                    <strong>Total Disk:</strong> <span id="totalDisk">0 GB</span>
                                </div>
                            </div>
                        </div>
                    </div>
                </div>

                <!-- Processes Panel -->
                <div class="dashboard" id="processes">
                    <div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 20px;">
                        <h2>Running Processes</h2>
                        <button class="refresh-btn" onclick="refreshProcesses()">Refresh</button>
                    </div>

                    <div class="tab-container">
                        <div class="tab active" onclick="setProcessSort('cpu')">Sort by CPU</div>
                        <div class="tab" onclick="setProcessSort('memory')">Sort by Memory</div>
                        <div class="tab" onclick="setProcessSort('name')">Sort by Name</div>
                    </div>

                    <div class="process-table">
                        <table>
                            <thead>
                                <tr>
                                    <th>PID</th>
                                    <th>Name</th>
                                    <th>CPU %</th>
                                    <th>Memory</th>
                                    <th>Memory %</th>
                                    <th>Status</th>
                                    <th>Action</th>
                                </tr>
                            </thead>
                            <tbody id="processTableBody">
                                <tr>
                                    <td colspan="7" style="text-align: center;">Loading...</td>
                                </tr>
                            </tbody>
                        </table>
                    </div>
                </div>

                <!-- Disks Panel -->
                <div class="dashboard" id="disks">
                    <div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 20px;">
                        <h2>Disk Usage</h2>
                        <button class="refresh-btn" onclick="refreshDisks()">Refresh</button>
                    </div>

                    <div id="diskInfo">
                        <div class="process-table">
                            <table>
                                <thead>
                                    <tr>
                                        <th>Name</th>
                                        <th>Mount Point</th>
                                        <th>File System</th>
                                        <th>Used</th>
                                        <th>Available</th>
                                        <th>Total</th>
                                        <th>Usage</th>
                                    </tr>
                                </thead>
                                <tbody id="diskTableBody">
                                    <tr>
                                        <td colspan="7" style="text-align: center;">Loading...</td>
                                    </tr>
                                </tbody>
                            </table>
                        </div>
                    </div>
                </div>

                <!-- Network Panel -->
                <div class="dashboard" id="network">
                    <div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 20px;">
                        <h2>Network Activity</h2>
                        <button class="refresh-btn" onclick="refreshNetwork()">Refresh</button>
                    </div>

                    <div id="networkInfo">
                        <div class="process-table">
                            <table>
                                <thead>
                                    <tr>
                                        <th>Interface</th>
                                        <th>Received</th>
                                        <th>Transmitted</th>
                                        <th>Packets Rx</th>
                                        <th>Packets Tx</th>
                                        <th>Errors Rx</th>
                                        <th>Errors Tx</th>
                                    </tr>
                                </thead>
                                <tbody id="networkTableBody">
                                    <tr>
                                        <td colspan="7" style="text-align: center;">Loading...</td>
                                    </tr>
                                </tbody>
                            </table>
                        </div>
                    </div>
                </div>
            </div>
        </div>
    </div>

    <script>
        const { invoke } = window.__TAURI__.core;

        let currentPanel = 'overview';
        let processSortBy = 'cpu';
        let charts = {};
        let updateInterval;

        // Initialize application
        async function init() {
            setupEventListeners();
            await loadInitialData();
            startAutoUpdate();
        }

        // Setup event listeners
        function setupEventListeners() {
            // Navigation
            document.querySelectorAll('.nav-item').forEach(item => {
                item.addEventListener('click', () => {
                    const panel = item.dataset.panel;
                    switchPanel(panel);
                });
            });
        }

        // Switch between panels
        function switchPanel(panel) {
            currentPanel = panel;

            // Update navigation
            document.querySelectorAll('.nav-item').forEach(item => {
                item.classList.toggle('active', item.dataset.panel === panel);
            });

            // Update content
            document.querySelectorAll('.dashboard').forEach(dashboard => {
                dashboard.classList.toggle('active', dashboard.id === panel);
            });

            // Load panel-specific data
            switch (panel) {
                case 'processes':
                    refreshProcesses();
                    break;
                case 'disks':
                    refreshDisks();
                    break;
                case 'network':
                    refreshNetwork();
                    break;
                default:
                    refreshSystemInfo();
            }
        }

        // Load initial data
        async function loadInitialData() {
            await refreshSystemInfo();
            await refreshProcesses();
            await refreshDisks();
            await refreshNetwork();
            initializeCharts();
        }

        // Refresh system information
        async function refreshSystemInfo() {
            try {
                const info = await invoke('get_system_info');
                updateSystemInfo(info);
                updateCharts(info);
            } catch (error) {
                console.error('Failed to get system info:', error);
            }
        }

        // Update system information display
        function updateSystemInfo(info) {
            // CPU
            const cpuUsage = Math.round(info.cpu_usage);
            document.getElementById('cpuUsage').textContent = cpuUsage + '%';
            updateProgressBar('cpuProgress', cpuUsage);

            // Memory
            const memoryUsedGB = (info.memory_used / (1024 * 1024 * 1024)).toFixed(1);
            const totalMemoryGB = (info.memory_total / (1024 * 1024 * 1024)).toFixed(1);
            const memoryUsage = Math.round(info.memory_usage);

            document.getElementById('memoryUsed').textContent = memoryUsedGB;
            document.getElementById('totalMemory').textContent = totalMemoryGB + ' GB';
            updateProgressBar('memoryProgress', memoryUsage);

            // Disk
            const diskUsage = Math.round(info.disk_usage);
            const totalDiskGB = (info.disk_total / (1024 * 1024 * 1024)).toFixed(1);

            document.getElementById('diskUsage').textContent = diskUsage + '%';
            document.getElementById('totalDisk').textContent = totalDiskGB + ' GB';
            updateProgressBar('diskProgress', diskUsage);

            // Other info
            const uptime = formatUptime(info.uptime);
            document.getElementById('uptime').textContent = uptime;
            document.getElementById('processCount').textContent = info.process_count;
        }

        // Update progress bar
        function updateProgressBar(id, percentage) {
            const bar = document.getElementById(id);
            bar.style.width = percentage + '%';

            // Change color based on usage
            bar.className = 'progress-fill';
            if (percentage >= 80) {
                bar.classList.add('high');
            } else if (percentage >= 60) {
                bar.classList.add('medium');
            }
        }

        // Format uptime
        function formatUptime(seconds) {
            const hours = Math.floor(seconds / 3600);
            const minutes = Math.floor((seconds % 3600) / 60);
            return `${hours}h ${minutes}m`;
        }

        // Initialize charts
        function initializeCharts() {
            const chartOptions = {
                responsive: true,
                maintainAspectRatio: false,
                scales: {
                    y: {
                        beginAtZero: true,
                        max: 100,
                        ticks: {
                            color: '#cccccc'
                        },
                        grid: {
                            color: '#3e3e42'
                        }
                    },
                    x: {
                        ticks: {
                            color: '#cccccc'
                        },
                        grid: {
                            color: '#3e3e42'
                        }
                    }
                },
                plugins: {
                    legend: {
                        display: false
                    }
                }
            };

            // CPU Chart
            const cpuCtx = document.getElementById('cpuChart').getContext('2d');
            charts.cpu = new Chart(cpuCtx, {
                type: 'line',
                data: {
                    labels: Array(20).fill(''),
                    datasets: [{
                        data: Array(20).fill(0),
                        borderColor: '#007acc',
                        backgroundColor: 'rgba(0, 122, 204, 0.1)',
                        borderWidth: 2,
                        tension: 0.4,
                        fill: true
                    }]
                },
                options: chartOptions
            });

            // Memory Chart
            const memoryCtx = document.getElementById('memoryChart').getContext('2d');
            charts.memory = new Chart(memoryCtx, {
                type: 'line',
                data: {
                    labels: Array(20).fill(''),
                    datasets: [{
                        data: Array(20).fill(0),
                        borderColor: '#5cb85c',
                        backgroundColor: 'rgba(92, 184, 92, 0.1)',
                        borderWidth: 2,
                        tension: 0.4,
                        fill: true
                    }]
                },
                options: chartOptions
            });

            // Disk Chart
            const diskCtx = document.getElementById('diskChart').getContext('2d');
            charts.disk = new Chart(diskCtx, {
                type: 'line',
                data: {
                    labels: Array(20).fill(''),
                    datasets: [{
                        data: Array(20).fill(0),
                        borderColor: '#f0ad4e',
                        backgroundColor: 'rgba(240, 173, 78, 0.1)',
                        borderWidth: 2,
                        tension: 0.4,
                        fill: true
                    }]
                },
                options: chartOptions
            });
        }

        // Update charts with new data
        function updateCharts(info) {
            if (charts.cpu) {
                const cpuData = charts.cpu.data.datasets[0].data;
                cpuData.shift();
                cpuData.push(Math.round(info.cpu_usage));
                charts.cpu.update('none');
            }

            if (charts.memory) {
                const memoryData = charts.memory.data.datasets[0].data;
                memoryData.shift();
                memoryData.push(Math.round(info.memory_usage));
                charts.memory.update('none');
            }

            if (charts.disk) {
                const diskData = charts.disk.data.datasets[0].data;
                diskData.shift();
                diskData.push(Math.round(info.disk_usage));
                charts.disk.update('none');
            }
        }

        // Refresh processes
        async function refreshProcesses() {
            try {
                const processes = await invoke('get_processes');
                displayProcesses(processes);
            } catch (error) {
                console.error('Failed to get processes:', error);
            }
        }

        // Display processes in table
        function displayProcesses(processes) {
            const tbody = document.getElementById('processTableBody');
            tbody.innerHTML = '';

            processes.forEach(process => {
                const row = document.createElement('tr');
                row.innerHTML = `
                    <td>${process.pid}</td>
                    <td>${process.name}</td>
                    <td>${process.cpu_usage.toFixed(1)}%</td>
                    <td>${formatBytes(process.memory_usage)}</td>
                    <td>${process.memory_percent.toFixed(1)}%</td>
                    <td>
                        <span class="status-indicator ${getStatusClass(process.status)}"></span>
                        ${process.status}
                    </td>
                    <td>
                        <button class="refresh-btn" onclick="killProcess(${process.pid})">Kill</button>
                    </td>
                `;
                tbody.appendChild(row);
            });
        }

        // Get status class for styling
        function getStatusClass(status) {
            if (status.includes('Run')) return 'status-running';
            if (status.includes('Sleep')) return 'status-sleeping';
            if (status.includes('Zombie')) return 'status-zombie';
            return '';
        }

        // Format bytes to human readable
        function formatBytes(bytes) {
            if (bytes === 0) return '0 B';

            const k = 1024;
            const sizes = ['B', 'KB', 'MB', 'GB'];
            const i = Math.floor(Math.log(bytes) / Math.log(k));

            return parseFloat((bytes / Math.pow(k, i)).toFixed(1)) + ' ' + sizes[i];
        }

        // Kill process
        async function killProcess(pid) {
            if (confirm(`Are you sure you want to kill process ${pid}?`)) {
                try {
                    await invoke('kill_process', { pid });
                    await refreshProcesses();
                } catch (error) {
                    alert('Failed to kill process: ' + error);
                }
            }
        }

        // Set process sort
        function setProcessSort(sortBy) {
            processSortBy = sortBy;

            // Update tab UI
            document.querySelectorAll('.tab').forEach(tab => {
                tab.classList.remove('active');
            });
            event.target.classList.add('active');

            refreshProcesses();
        }

        // Refresh disks
        async function refreshDisks() {
            try {
                const disks = await invoke('get_disks');
                displayDisks(disks);
            } catch (error) {
                console.error('Failed to get disk info:', error);
            }
        }

        // Display disk information
        function displayDisks(disks) {
            const tbody = document.getElementById('diskTableBody');
            tbody.innerHTML = '';

            disks.forEach(disk => {
                const row = document.createElement('tr');
                row.innerHTML = `
                    <td>${disk.name}</td>
                    <td>${disk.mount_point}</td>
                    <td>${disk.file_system}</td>
                    <td>${formatBytes(disk.used_space)}</td>
                    <td>${formatBytes(disk.available_space)}</td>
                    <td>${formatBytes(disk.total_space)}</td>
                    <td>
                        <div class="progress-bar" style="width: 100px;">
                            <div class="progress-fill ${disk.usage_percent > 80 ? 'high' : disk.usage_percent > 60 ? 'medium' : ''}"
                                 style="width: ${disk.usage_percent}%"></div>
                        </div>
                        ${disk.usage_percent.toFixed(1)}%
                    </td>
                `;
                tbody.appendChild(row);
            });
        }

        // Refresh network info
        async function refreshNetwork() {
            try {
                const networks = await invoke('get_network_info');
                displayNetworks(networks);
            } catch (error) {
                console.error('Failed to get network info:', error);
            }
        }

        // Display network information
        function displayNetworks(networks) {
            const tbody = document.getElementById('networkTableBody');
            tbody.innerHTML = '';

            networks.forEach(network => {
                const row = document.createElement('tr');
                row.innerHTML = `
                    <td>${network.interface}</td>
                    <td>${formatBytes(network.data_received)}</td>
                    <td>${formatBytes(network.data_transmitted)}</td>
                    <td>${network.packets_received.toLocaleString()}</td>
                    <td>${network.packets_transmitted.toLocaleString()}</td>
                    <td>${network.errors_on_received}</td>
                    <td>${network.errors_on_transmitted}</td>
                `;
                tbody.appendChild(row);
            });
        }

        // Start auto-update
        function startAutoUpdate() {
            updateInterval = setInterval(async () => {
                if (currentPanel === 'overview') {
                    await refreshSystemInfo();
                }
            }, 2000);
        }

        // Listen for system updates from backend
        if (window.__TAURI__) {
            window.__TAURI__.event.listen('system-update', async () => {
                if (currentPanel === 'overview') {
                    await refreshSystemInfo();
                }
            });
        }

        // Initialize when DOM is loaded
        document.addEventListener('DOMContentLoaded', init);
    </script>
</body>
</html>

Tools

Tools frequently paired with this sample

Related

Related sample collections

Tool usage guide

Sample-focused context for search and workflow understanding

Title

Tauri Samples

Description

Lightweight desktop application development examples using Tauri framework with Rust backend and web frontend

Overview

Lightweight desktop application development examples using Tauri framework with Rust backend and web frontend

When to use

  • Use this sample set when you want reference inputs for Tauri Samples.
  • Use it to preview output formats and compare related sample variants.

How it works

  1. 1Open a sample entry to inspect the prepared example payload or asset.
  2. 2Compare it with related tools to understand how the workflow connects.

Use cases

  • Tauri Hello World Application
  • Tauri File Manager Application
  • Tauri System Monitor Application

FAQ

What is included in Tauri Samples?

This page includes curated sample entries, related tools, and neighboring sample collections for Tauri Samples.

Home
Tools3197
Samples593
Visualizations461
Viewers103
Hubs229
Tags333
Images, Audio & Video655

Image, audio, and video processing, conversion, and optimization tools

Math, Date & Finance644

Calculators, numerics, date logic, statistics, and finance tools

Design & Color296

Color, layout, graphics, visual styling, and design helper tools

Text & Writing209

Writing, cleanup, formatting, extraction, and text analysis tools

Developer & Web193

Developer utilities, networking, web debugging, and automation helpers

Conversion & Encoding175

Format, file, archive, unit, and encoding conversion tools

UI Screenshot Structure Review and Development Handoff
Piano Sketch Creation, MIDI Review and Listening Demo Handoff
Retro Game Texture Review and Asset Handoff
Screenshot-Based Procedure Guide Review and Handoff
Responsive Page Change Review and Evidence Handoff

© 2026 Elysia Tools. All rights reserved.

DocsPricingAboutTerms of ServicePrivacy PolicyCookiesContact

Development

HTML Tags Reference

Complete reference guide for all standard HTML5 tags with categories and descriptions

Development

JSON to Rust Struct Converter

Convert JSON data into Rust structs with serde Serialize/Deserialize derives, snake_case fields, and serde rename attributes

Rust

Web Desktop Features Rust Samples

Web Rust desktop-like features examples including file dialogs, message boxes, and system integration