feat: add auto-refresh and toggle detail view for process list

This commit is contained in:
Huakun Shen 2025-02-26 10:58:52 -05:00
parent 18ca061dd6
commit 4638edaef2
No known key found for this signature in database

View File

@ -14,13 +14,14 @@ import {
class ExtensionTemplate extends TemplateUiCommand {
processes: Awaited<ReturnType<typeof sysInfo.processes>> = [];
lockRefresh = false;
async onFormSubmit(value: Record<string, any>): Promise<void> {
toast.success(`Form submitted: ${JSON.stringify(value)}`);
}
onHighlightedListItemChanged(value: string): Promise<void> {
super.onHighlightedListItemChanged(value);
console.log("Highlighted list item changed:", value);
// console.log("Highlighted list item changed:", value);
if (!this.highlightedListItemValue) {
return toast.warning("No process selected");
}
@ -29,96 +30,76 @@ class ExtensionTemplate extends TemplateUiCommand {
if (!process) {
return toast.warning("Process not found");
}
ui.render(
new List.List({
inherits: ["items"],
detail: new List.ItemDetail({
children: [
new List.ItemDetailMetadata([
new List.ItemDetailMetadataLabel({
title: "Name",
text: name,
}),
new List.ItemDetailMetadataLabel({
title: "PID",
text: pid.toString(),
}),
new List.ItemDetailMetadataLabel({
title: "CPU Usage",
text: `${(process.cpu_usage ?? 0).toFixed(2)}%`,
}),
new List.ItemDetailMetadataLabel({
title: "Memory Usage",
text: prettyBytes(process.memory ?? 0),
}),
new List.ItemDetailMetadataLabel({
title: "Parent",
text: process.parent?.toString() ?? "Unknown",
}),
new List.ItemDetailMetadataLabel({
title: "Group",
text: process.group_id?.toString() ?? "Unknown",
}),
]),
new Markdown(`
- **exe:** ${process.exe}
- **Virtual Memory:** ${prettyBytes(process.virtual_memory ?? 0)}
`),
],
width: 50,
}),
})
);
return Promise.resolve();
}
async reload() {
if (!this.lockRefresh) {
sysInfo
.refreshProcesses()
.then(() => sysInfo.processes())
.then((processes) => {
this.processes = processes;
this.processes.sort(
(a, b) => (b.cpu_usage ?? 0) - (a.cpu_usage ?? 0)
);
// console.log(this.processes);
ui.setSearchBarPlaceholder("Search by process name or pid");
ui.render(
new List.List({
items: this.processes.map((p) => {
// const exe = p.exe ?? "Unknown Executable";
// const trimmedExe = exe.length > 50 ? "..." + exe.slice(-47) : exe;
return new List.Item({
title: p.name,
subTitle: `pid: ${p.pid}`,
// subTitle: `${trimmedExe} (${p.pid})`,
value: JSON.stringify({
pid: p.pid,
name: p.name,
}),
actions: new Action.ActionPanel({
items: [
new Action.Action({
title: "Kill",
value: "kill",
}),
new Action.Action({
title: "Copy Executable",
value: "copy-exe",
}),
new Action.Action({
title: "Copy PID",
value: "copy-pid",
}),
],
}),
accessories: [
new List.ItemAccessory({
text: `CPU: ${(p.cpu_usage ?? 0).toFixed(2)}%`,
}),
new List.ItemAccessory({
text: `${prettyBytes(p.memory ?? 0)}`,
}),
],
});
}),
defaultAction: "Toggle Refresh",
})
);
})
.catch((err) => {
toast.error(err.message);
});
}
setTimeout(() => {
this.reload();
}, 5_000);
}
async load() {
ui.render(new List.List({ items: [] }));
sysInfo
.refreshProcesses()
.then(() => sysInfo.processes())
.then((processes) => {
this.processes = processes;
this.processes.sort((a, b) => (b.cpu_usage ?? 0) - (a.cpu_usage ?? 0));
console.log(this.processes);
ui.setSearchBarPlaceholder("Search by process name or pid");
ui.render(
new List.List({
items: this.processes.map((p) => {
// const exe = p.exe ?? "Unknown Executable";
// const trimmedExe = exe.length > 50 ? "..." + exe.slice(-47) : exe;
return new List.Item({
title: p.name,
subTitle: `pid: ${p.pid}`,
// subTitle: `${trimmedExe} (${p.pid})`,
value: JSON.stringify({
pid: p.pid,
name: p.name,
}),
actions: new Action.ActionPanel({
items: [
new Action.Action({
title: "Kill",
value: "kill",
}),
new Action.Action({
title: "Copy Executable",
value: "copy-exe",
}),
new Action.Action({
title: "Copy PID",
value: "copy-pid",
}),
],
}),
});
}),
})
);
})
.catch((err) => {
toast.error(err.message);
});
this.reload();
}
async onActionSelected(actionValue: string): Promise<void> {
@ -129,7 +110,9 @@ class ExtensionTemplate extends TemplateUiCommand {
const process = this.processes.find((p) => p.pid === pid);
switch (actionValue) {
case "kill":
console.log("Killing process:", pid);
shell.killPid(pid);
this.lockRefresh = false; // need to refresh after killing
break;
case "copy-exe":
if (!process?.exe) {
@ -144,6 +127,59 @@ class ExtensionTemplate extends TemplateUiCommand {
break;
}
}
async onListItemSelected(value: string): Promise<void> {
this.lockRefresh = !this.lockRefresh; // toggle refresh
if (this.lockRefresh) {
// this.onHighlightedListItemChanged(value);
const { pid, name } = JSON.parse(value);
const process = this.processes.find((p) => p.pid === pid);
if (!process) {
return toast.warning("Process not found");
}
console.log("ListItem selected:", value);
ui.render(
new List.List({
inherits: ["items"],
detail: new List.ItemDetail({
children: [
new List.ItemDetailMetadata([
new List.ItemDetailMetadataLabel({
title: "Name",
text: name,
}),
new List.ItemDetailMetadataLabel({
title: "PID",
text: pid.toString(),
}),
new List.ItemDetailMetadataLabel({
title: "CPU Usage",
text: `${(process.cpu_usage ?? 0).toFixed(2)}%`,
}),
new List.ItemDetailMetadataLabel({
title: "Memory Usage",
text: prettyBytes(process.memory ?? 0),
}),
new List.ItemDetailMetadataLabel({
title: "Parent",
text: process.parent?.toString() ?? "Unknown",
}),
new List.ItemDetailMetadataLabel({
title: "Group",
text: process.group_id?.toString() ?? "Unknown",
}),
]),
new Markdown(`
- **exe:** ${process.exe}
- **Virtual Memory:** ${prettyBytes(process.virtual_memory ?? 0)}
`),
],
width: 30,
}),
})
);
}
}
}
expose(new ExtensionTemplate());