Merge branch 'feat/admin-console': Administration page (Users + Server tabs)

This commit is contained in:
2026-10-15 16:44:09 +07:00
20 changed files with 1333 additions and 22 deletions
+44
View File
@@ -569,6 +569,46 @@ export interface MemberTmux {
users: MemberTmuxRow[];
}
/** One account's (or the host's / other accounts') live share of the machine (`GET /api/host`). */
export interface HostUsageGroup {
/** `user:<id>`, `host` (the host account outside any workspace) or `system`. */
key: string;
kind: "user" | "host" | "system";
userId?: number;
username?: string;
/** % of the whole machine's CPU (100 = every core busy) over the sample. */
cpu: number;
/** Resident memory, bytes (shared pages count in every process). */
memory: number;
memoryPercent: number;
processes: number;
/** Busiest processes, by the kernel's short name only. */
top: { pid: number; name: string; cpu: number; memory: number }[];
}
/** `GET /api/host` — hardware, load, disks and per-user usage. */
export interface HostStats {
at: string;
hostname: string;
os: { platform: string; release: string; distro: string | null; arch: string };
uptime: number;
cpu: { model: string | null; cores: number; load: number[] };
memory: { total: number; available: number; used: number; swapTotal: number; swapUsed: number };
disks: {
device: string;
mount: string;
type: string;
kind: "HDD" | "SSD" | null;
total: number;
used: number;
free: number;
}[];
/** The mount holding the users' homes, or null. */
homesMount: string | null;
gpus: { name: string; utilization: number; memoryUsed: number; memoryTotal: number }[];
/** null off Linux. */
usage: { cpu: number; sampleMs: number; groups: HostUsageGroup[] } | null;
}
/** One user's home folder on disk (`GET /api/users/storage`); null = not measured. */
export type UserStorage = {
bytes: number;
@@ -918,6 +958,10 @@ export const api = {
/** DELETE /api/me/avatar — back to the initials. */
removeAvatar: () => request<MyAccount>("/me/avatar", { method: "DELETE" }),
},
/** GET /api/host — the Server tab: hardware and each user's CPU/memory share (staff). */
host: {
stats: () => request<HostStats>("/host"),
},
// ───────────────────────── Server mode staff views (routes/users.js) ─────────────────────────
users: {
/** URL of one account's avatar (admin/analyst), versioned by `avatarAt` (null = none). */