neohtop is a beautiful desktop version of the htop command.

A modern, cross-platform system monitor built on top of Svelte, Rust, and Tauri.

In this blog, I will talk about how I converted neohtop to an extension.

It maybe simpler than you think.

TC;SC

Here is a screenshot of the extension, exactly the same as the desktop version.

Intro

neohtop is a Tauri app. It’s frontend is built with Svelte, and backend is built with Rust.

One of the reasons I created kunkun is to make it easy to write cross-platform apps and distribute them on different platforms.

And neohtop is a perfect example for this.

It’s a nice GUI wrapper over the sysinfo crate. See its Cargo.toml.

Luckily, Kunkun’s extension API also provides a sysInfo API, see docs. It is based on tauri-plugin-system-info, which is also a wrapper over the sysinfo crate. See Cargo.toml.

Since the data source are the same, then it should be straightforward to convert it to an extension.

I set a 30 minutes goal for myself, but it took me 90 minutes to complete the conversion. This is because neohtop did its data aggregation and preprocessing in rust, and I need to convert the logic to TypeScript. Kind of like how TypeScript is converted to Golang, I just needed to convert the rust code to TypeScript, not hard at all, just time-consuming.

Code

In this PR, I demonstrated all the changes I made for the conversion.

First of all, neohtop is written in frontend framework svelte, so obviously this is a custom UI extension.

Manifest

package.json

package.json
"kunkun": {
    "name": "neohtop",
    "shortDescription": "A modern, cross-platform system monitor",
    "longDescription": "A modern, cross-platform system monitor",
    "identifier": "neohtop",
    "demoImages": [
        "https://imgur.com/D8VHDEz.png"
    ],
    "permissions": [
        "system-info:all",
        "shell:kill-any"
    ],
    "icon": {
        "type": "remote-url",
        "value": "https://github.com/Abdenasser/neohtop/raw/main/app-icon.png"
    },
    "customUiCmds": [
        {
            "name": "neohtop",
            "main": "/",
            "dist": "build",
            "devMain": "http://localhost:1420",
            "cmds": [],
            "window": {
                "title": "Neohtop",
                "hiddenTitle": true,
                "titleBarStyle": "overlay",
                "width": 1400,
                "height": 1000
            }
        }
    ]
},
  • build folder is the default output folder of svelte projects, thus dist is set to build.
  • devMain is the local server that serves the svelte project, it is used when developing the extension with HMR.
  • system-info:all permission is required to access the system info data.
  • shell:kill-any permission is required to kill any process by a pid.

Frontend

neohtop has no default window title bar, but users can drag the window by clicking on the top of the app. This is achieved by simply including data-tauri-drag-region in a div element.

<div class="title-bar" data-tauri-drag-region></div>

In a KK extension, we use data-kunkun-drag-region instead, just remember to call ui.registerDragRegion in app initialization.

TitleBar.svelte
- <div class="title-bar" data-tauri-drag-region>
+ <div class="title-bar" data-kunkun-drag-region>
+page.svelte
+ import { ui } from "@kksh/api/ui/custom";
+ onMount(() => {
+   ui.registerDragRegion("kunkun");
+ });

Data Preprocessing/Aggregation

This is the most time-consuming part.

The source system info data is preprocessed before rendering. The preprocessing logic is written in Rust, thus I need to convert them to TypeScript.

Acknowledgements