mirror of
https://github.com/Crosstalk-Solutions/project-nomad.git
synced 2026-04-05 00:06:17 +02:00
feat(Settings): display system information
This commit is contained in:
parent
5244fed549
commit
791ee1488e
|
|
@ -9,11 +9,11 @@ export default class SettingsController {
|
||||||
) { }
|
) { }
|
||||||
|
|
||||||
async system({ inertia }: HttpContext) {
|
async system({ inertia }: HttpContext) {
|
||||||
// const services = await this.systemService.getServices();
|
const systemInfo = await this.systemService.getSystemInfo();
|
||||||
return inertia.render('settings/system', {
|
return inertia.render('settings/system', {
|
||||||
// system: {
|
system: {
|
||||||
// services
|
info: systemInfo
|
||||||
// }
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,10 @@ export default class SystemController {
|
||||||
private dockerService: DockerService
|
private dockerService: DockerService
|
||||||
) { }
|
) { }
|
||||||
|
|
||||||
|
async getSystemInfo({ }: HttpContext) {
|
||||||
|
return await this.systemService.getSystemInfo();
|
||||||
|
}
|
||||||
|
|
||||||
async getServices({ }: HttpContext) {
|
async getServices({ }: HttpContext) {
|
||||||
return await this.systemService.getServices({ installedOnly: true });
|
return await this.systemService.getServices({ installedOnly: true });
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,9 @@ import Service from "#models/service"
|
||||||
import { inject } from "@adonisjs/core";
|
import { inject } from "@adonisjs/core";
|
||||||
import { DockerService } from "#services/docker_service";
|
import { DockerService } from "#services/docker_service";
|
||||||
import { ServiceSlim } from "../../types/services.js";
|
import { ServiceSlim } from "../../types/services.js";
|
||||||
|
import logger from "@adonisjs/core/services/logger";
|
||||||
|
import si from 'systeminformation';
|
||||||
|
import { SystemInformationResponse } from "../../types/system.js";
|
||||||
|
|
||||||
@inject()
|
@inject()
|
||||||
export class SystemService {
|
export class SystemService {
|
||||||
|
|
@ -41,4 +44,25 @@ export class SystemService {
|
||||||
return toReturn;
|
return toReturn;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async getSystemInfo(): Promise<SystemInformationResponse | undefined> {
|
||||||
|
try {
|
||||||
|
const [cpu, mem, os, disk] = await Promise.all([
|
||||||
|
si.cpu(),
|
||||||
|
si.mem(),
|
||||||
|
si.osInfo(),
|
||||||
|
si.diskLayout()
|
||||||
|
]);;
|
||||||
|
|
||||||
|
return {
|
||||||
|
cpu,
|
||||||
|
mem,
|
||||||
|
os,
|
||||||
|
disk
|
||||||
|
};
|
||||||
|
} catch (error) {
|
||||||
|
logger.error('Error getting system info:', error);
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1,307 +1,71 @@
|
||||||
import { useState } from 'react'
|
|
||||||
import { Bars3Icon, MagnifyingGlassIcon } from '@heroicons/react/20/solid'
|
|
||||||
import { ChevronDownIcon } from '@heroicons/react/16/solid'
|
|
||||||
import { Head } from '@inertiajs/react'
|
import { Head } from '@inertiajs/react'
|
||||||
import SettingsLayout from '~/layouts/SettingsLayout'
|
import SettingsLayout from '~/layouts/SettingsLayout'
|
||||||
|
import { SystemInformationResponse } from '../../../types/system'
|
||||||
|
import { IconPaperclip } from '@tabler/icons-react'
|
||||||
|
import { formatBytes } from '~/lib/util'
|
||||||
|
|
||||||
export default function SettingsPage() {
|
const Section = ({ title, children }: { title: string; children: React.ReactNode }) => {
|
||||||
|
return (
|
||||||
|
<div className="px-4 sm:px-0 mt-8">
|
||||||
|
<h3 className="text-base/7 font-semibold text-gray-900">{title}</h3>
|
||||||
|
<div className="mt-1 border-t border-gray-300">
|
||||||
|
<dl className="divide-y divide-gray-200">{children}</dl>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
const Row = ({ label, value }: { label: string; value: string | number | undefined }) => {
|
||||||
|
return (
|
||||||
|
<div className="px-4 py-2 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-0">
|
||||||
|
<dt className="text-sm/6 font-medium text-gray-900">{label}</dt>
|
||||||
|
<dd className="mt-1 text-sm/6 text-gray-700 sm:col-span-2 sm:mt-0">{value}</dd>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function SettingsPage(props: {
|
||||||
|
system: { info: SystemInformationResponse | undefined }
|
||||||
|
}) {
|
||||||
|
console.log(props.system.info)
|
||||||
return (
|
return (
|
||||||
<SettingsLayout>
|
<SettingsLayout>
|
||||||
<Head title="Settings | Project N.O.M.A.D." />
|
<Head title="Settings | Project N.O.M.A.D." />
|
||||||
<div className="xl:pl-72">
|
<div className="xl:pl-72 w-full">
|
||||||
{/* Sticky search header */}
|
<main className="px-12 py-6">
|
||||||
{/* <div className="sticky top-0 z-40 flex h-16 shrink-0 items-center gap-x-6 border-b border-white/5 bg-gray-900 px-4 shadow-sm sm:px-6 lg:px-8">
|
<h1 className="text-4xl font-semibold mb-6">System Information</h1>
|
||||||
<button
|
<div>
|
||||||
type="button"
|
<Section title="OS Information">
|
||||||
onClick={() => setSidebarOpen(true)}
|
<Row label="Distro" value={props.system.info?.os.distro} />
|
||||||
className="-m-2.5 p-2.5 text-white xl:hidden"
|
<Row label="Kernel" value={props.system.info?.os.kernel} />
|
||||||
>
|
<Row label="Architecture" value={props.system.info?.os.arch} />
|
||||||
<span className="sr-only">Open sidebar</span>
|
<Row label="Hostname" value={props.system.info?.os.hostname} />
|
||||||
<Bars3Icon aria-hidden="true" className="size-5" />
|
</Section>
|
||||||
</button>
|
<Section title="CPU Manufacturer">
|
||||||
|
<Row label="Manufacturer" value={props.system.info?.cpu.manufacturer} />
|
||||||
<div className="flex flex-1 gap-x-4 self-stretch lg:gap-x-6">
|
<Row label="Brand Name" value={props.system.info?.cpu.brand} />
|
||||||
<form action="#" method="GET" className="grid flex-1 grid-cols-1">
|
<Row label="Cores" value={props.system.info?.cpu.cores} />
|
||||||
<input
|
<Row
|
||||||
name="search"
|
label="Virtualization Enabled"
|
||||||
type="search"
|
value={props.system.info?.cpu.virtualization ? 'Yes' : 'No'}
|
||||||
placeholder="Search"
|
|
||||||
aria-label="Search"
|
|
||||||
className="col-start-1 row-start-1 block size-full bg-transparent pl-8 text-base text-white outline-none placeholder:text-gray-500 sm:text-sm/6"
|
|
||||||
/>
|
/>
|
||||||
<MagnifyingGlassIcon
|
</Section>
|
||||||
aria-hidden="true"
|
<Section title="Memory Information">
|
||||||
className="pointer-events-none col-start-1 row-start-1 size-5 self-center text-gray-500"
|
<Row label="Total" value={formatBytes(props.system.info?.mem.total || 0)} />
|
||||||
/>
|
<Row label="Used" value={formatBytes(props.system.info?.mem.used || 0)} />
|
||||||
</form>
|
<Row label="Free" value={formatBytes(props.system.info?.mem.free || 0)} />
|
||||||
</div>
|
<Row label="Swap Total" value={formatBytes(props.system.info?.mem.swaptotal || 0)} />
|
||||||
</div> */}
|
<Row label="Swap Used" value={formatBytes(props.system.info?.mem.swapused || 0)} />
|
||||||
|
</Section>
|
||||||
<main>
|
<Section title="Disk Information">
|
||||||
<h1 className="sr-only">Settings</h1>
|
{props.system.info?.disk.map((disk, index) => (
|
||||||
{/* Settings forms */}
|
<div key={index}>
|
||||||
<div className="divide-y divide-white/5">
|
<Row label={`Disk ${index + 1} Name`} value={disk.name} />
|
||||||
<div className="grid max-w-7xl grid-cols-1 gap-x-8 gap-y-10 px-4 py-16 sm:px-6 md:grid-cols-3 lg:px-8">
|
<Row label={`Disk ${index + 1} Size`} value={formatBytes(disk.size || 0)} />
|
||||||
<div>
|
<Row label={`Disk ${index + 1} Type`} value={disk.type} />
|
||||||
<h2 className="text-base/7 font-semibold text-white">Personal Information</h2>
|
|
||||||
<p className="mt-1 text-sm/6 text-gray-400">
|
|
||||||
Use a permanent address where you can receive mail.
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<form className="md:col-span-2">
|
|
||||||
<div className="grid grid-cols-1 gap-x-6 gap-y-8 sm:max-w-xl sm:grid-cols-6">
|
|
||||||
<div className="col-span-full flex items-center gap-x-8">
|
|
||||||
<img
|
|
||||||
alt=""
|
|
||||||
src="https://images.unsplash.com/photo-1472099645785-5658abf4ff4e?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=facearea&facepad=2&w=256&h=256&q=80"
|
|
||||||
className="size-24 flex-none rounded-lg bg-gray-800 object-cover"
|
|
||||||
/>
|
|
||||||
<div>
|
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
className="rounded-md bg-white/10 px-3 py-2 text-sm font-semibold text-white shadow-sm hover:bg-white/20"
|
|
||||||
>
|
|
||||||
Change avatar
|
|
||||||
</button>
|
|
||||||
<p className="mt-2 text-xs/5 text-gray-400">JPG, GIF or PNG. 1MB max.</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="sm:col-span-3">
|
|
||||||
<label htmlFor="first-name" className="block text-sm/6 font-medium text-white">
|
|
||||||
First name
|
|
||||||
</label>
|
|
||||||
<div className="mt-2">
|
|
||||||
<input
|
|
||||||
id="first-name"
|
|
||||||
name="first-name"
|
|
||||||
type="text"
|
|
||||||
autoComplete="given-name"
|
|
||||||
className="block w-full rounded-md bg-white/5 px-3 py-1.5 text-base text-white outline outline-1 -outline-offset-1 outline-white/10 placeholder:text-gray-500 focus:outline focus:outline-2 focus:-outline-offset-2 focus:outline-indigo-500 sm:text-sm/6"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="sm:col-span-3">
|
|
||||||
<label htmlFor="last-name" className="block text-sm/6 font-medium text-white">
|
|
||||||
Last name
|
|
||||||
</label>
|
|
||||||
<div className="mt-2">
|
|
||||||
<input
|
|
||||||
id="last-name"
|
|
||||||
name="last-name"
|
|
||||||
type="text"
|
|
||||||
autoComplete="family-name"
|
|
||||||
className="block w-full rounded-md bg-white/5 px-3 py-1.5 text-base text-white outline outline-1 -outline-offset-1 outline-white/10 placeholder:text-gray-500 focus:outline focus:outline-2 focus:-outline-offset-2 focus:outline-indigo-500 sm:text-sm/6"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="col-span-full">
|
|
||||||
<label htmlFor="email" className="block text-sm/6 font-medium text-white">
|
|
||||||
Email address
|
|
||||||
</label>
|
|
||||||
<div className="mt-2">
|
|
||||||
<input
|
|
||||||
id="email"
|
|
||||||
name="email"
|
|
||||||
type="email"
|
|
||||||
autoComplete="email"
|
|
||||||
className="block w-full rounded-md bg-white/5 px-3 py-1.5 text-base text-white outline outline-1 -outline-offset-1 outline-white/10 placeholder:text-gray-500 focus:outline focus:outline-2 focus:-outline-offset-2 focus:outline-indigo-500 sm:text-sm/6"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="col-span-full">
|
|
||||||
<label htmlFor="username" className="block text-sm/6 font-medium text-white">
|
|
||||||
Username
|
|
||||||
</label>
|
|
||||||
<div className="mt-2">
|
|
||||||
<div className="flex items-center rounded-md bg-white/5 pl-3 outline outline-1 -outline-offset-1 outline-white/10 focus-within:outline focus-within:outline-2 focus-within:-outline-offset-2 focus-within:outline-indigo-500">
|
|
||||||
<div className="shrink-0 select-none text-base text-gray-500 sm:text-sm/6">
|
|
||||||
example.com/
|
|
||||||
</div>
|
|
||||||
<input
|
|
||||||
id="username"
|
|
||||||
name="username"
|
|
||||||
type="text"
|
|
||||||
placeholder="janesmith"
|
|
||||||
className="block min-w-0 grow bg-transparent py-1.5 pl-1 pr-3 text-base text-white placeholder:text-gray-500 focus:outline focus:outline-0 sm:text-sm/6"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="col-span-full">
|
|
||||||
<label htmlFor="timezone" className="block text-sm/6 font-medium text-white">
|
|
||||||
Timezone
|
|
||||||
</label>
|
|
||||||
<div className="mt-2 grid grid-cols-1">
|
|
||||||
<select
|
|
||||||
id="timezone"
|
|
||||||
name="timezone"
|
|
||||||
className="col-start-1 row-start-1 w-full appearance-none rounded-md bg-white/5 py-1.5 pl-3 pr-8 text-base text-white outline outline-1 -outline-offset-1 outline-white/10 *:bg-gray-800 focus:outline focus:outline-2 focus:-outline-offset-2 focus:outline-indigo-500 sm:text-sm/6"
|
|
||||||
>
|
|
||||||
<option>Pacific Standard Time</option>
|
|
||||||
<option>Eastern Standard Time</option>
|
|
||||||
<option>Greenwich Mean Time</option>
|
|
||||||
</select>
|
|
||||||
<ChevronDownIcon
|
|
||||||
aria-hidden="true"
|
|
||||||
className="pointer-events-none col-start-1 row-start-1 mr-2 size-5 self-center justify-self-end text-gray-400 sm:size-4"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
))}
|
||||||
<div className="mt-8 flex">
|
</Section>
|
||||||
<button
|
|
||||||
type="submit"
|
|
||||||
className="rounded-md bg-indigo-500 px-3 py-2 text-sm font-semibold text-white shadow-sm hover:bg-indigo-400 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-500"
|
|
||||||
>
|
|
||||||
Save
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="grid max-w-7xl grid-cols-1 gap-x-8 gap-y-10 px-4 py-16 sm:px-6 md:grid-cols-3 lg:px-8">
|
|
||||||
<div>
|
|
||||||
<h2 className="text-base/7 font-semibold text-white">Change password</h2>
|
|
||||||
<p className="mt-1 text-sm/6 text-gray-400">
|
|
||||||
Update your password associated with your account.
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<form className="md:col-span-2">
|
|
||||||
<div className="grid grid-cols-1 gap-x-6 gap-y-8 sm:max-w-xl sm:grid-cols-6">
|
|
||||||
<div className="col-span-full">
|
|
||||||
<label
|
|
||||||
htmlFor="current-password"
|
|
||||||
className="block text-sm/6 font-medium text-white"
|
|
||||||
>
|
|
||||||
Current password
|
|
||||||
</label>
|
|
||||||
<div className="mt-2">
|
|
||||||
<input
|
|
||||||
id="current-password"
|
|
||||||
name="current_password"
|
|
||||||
type="password"
|
|
||||||
autoComplete="current-password"
|
|
||||||
className="block w-full rounded-md bg-white/5 px-3 py-1.5 text-base text-white outline outline-1 -outline-offset-1 outline-white/10 placeholder:text-gray-500 focus:outline focus:outline-2 focus:-outline-offset-2 focus:outline-indigo-500 sm:text-sm/6"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="col-span-full">
|
|
||||||
<label
|
|
||||||
htmlFor="new-password"
|
|
||||||
className="block text-sm/6 font-medium text-white"
|
|
||||||
>
|
|
||||||
New password
|
|
||||||
</label>
|
|
||||||
<div className="mt-2">
|
|
||||||
<input
|
|
||||||
id="new-password"
|
|
||||||
name="new_password"
|
|
||||||
type="password"
|
|
||||||
autoComplete="new-password"
|
|
||||||
className="block w-full rounded-md bg-white/5 px-3 py-1.5 text-base text-white outline outline-1 -outline-offset-1 outline-white/10 placeholder:text-gray-500 focus:outline focus:outline-2 focus:-outline-offset-2 focus:outline-indigo-500 sm:text-sm/6"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="col-span-full">
|
|
||||||
<label
|
|
||||||
htmlFor="confirm-password"
|
|
||||||
className="block text-sm/6 font-medium text-white"
|
|
||||||
>
|
|
||||||
Confirm password
|
|
||||||
</label>
|
|
||||||
<div className="mt-2">
|
|
||||||
<input
|
|
||||||
id="confirm-password"
|
|
||||||
name="confirm_password"
|
|
||||||
type="password"
|
|
||||||
autoComplete="new-password"
|
|
||||||
className="block w-full rounded-md bg-white/5 px-3 py-1.5 text-base text-white outline outline-1 -outline-offset-1 outline-white/10 placeholder:text-gray-500 focus:outline focus:outline-2 focus:-outline-offset-2 focus:outline-indigo-500 sm:text-sm/6"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="mt-8 flex">
|
|
||||||
<button
|
|
||||||
type="submit"
|
|
||||||
className="rounded-md bg-indigo-500 px-3 py-2 text-sm font-semibold text-white shadow-sm hover:bg-indigo-400 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-500"
|
|
||||||
>
|
|
||||||
Save
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="grid max-w-7xl grid-cols-1 gap-x-8 gap-y-10 px-4 py-16 sm:px-6 md:grid-cols-3 lg:px-8">
|
|
||||||
<div>
|
|
||||||
<h2 className="text-base/7 font-semibold text-white">Log out other sessions</h2>
|
|
||||||
<p className="mt-1 text-sm/6 text-gray-400">
|
|
||||||
Please enter your password to confirm you would like to log out of your other
|
|
||||||
sessions across all of your devices.
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<form className="md:col-span-2">
|
|
||||||
<div className="grid grid-cols-1 gap-x-6 gap-y-8 sm:max-w-xl sm:grid-cols-6">
|
|
||||||
<div className="col-span-full">
|
|
||||||
<label
|
|
||||||
htmlFor="logout-password"
|
|
||||||
className="block text-sm/6 font-medium text-white"
|
|
||||||
>
|
|
||||||
Your password
|
|
||||||
</label>
|
|
||||||
<div className="mt-2">
|
|
||||||
<input
|
|
||||||
id="logout-password"
|
|
||||||
name="password"
|
|
||||||
type="password"
|
|
||||||
autoComplete="current-password"
|
|
||||||
className="block w-full rounded-md bg-white/5 px-3 py-1.5 text-base text-white outline outline-1 -outline-offset-1 outline-white/10 placeholder:text-gray-500 focus:outline focus:outline-2 focus:-outline-offset-2 focus:outline-indigo-500 sm:text-sm/6"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="mt-8 flex">
|
|
||||||
<button
|
|
||||||
type="submit"
|
|
||||||
className="rounded-md bg-indigo-500 px-3 py-2 text-sm font-semibold text-white shadow-sm hover:bg-indigo-400 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-500"
|
|
||||||
>
|
|
||||||
Log out other sessions
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="grid max-w-7xl grid-cols-1 gap-x-8 gap-y-10 px-4 py-16 sm:px-6 md:grid-cols-3 lg:px-8">
|
|
||||||
<div>
|
|
||||||
<h2 className="text-base/7 font-semibold text-white">Delete account</h2>
|
|
||||||
<p className="mt-1 text-sm/6 text-gray-400">
|
|
||||||
No longer want to use our service? You can delete your account here. This action
|
|
||||||
is not reversible. All information related to this account will be deleted
|
|
||||||
permanently.
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<form className="flex items-start md:col-span-2">
|
|
||||||
<button
|
|
||||||
type="submit"
|
|
||||||
className="rounded-md bg-red-500 px-3 py-2 text-sm font-semibold text-white shadow-sm hover:bg-red-400"
|
|
||||||
>
|
|
||||||
Yes, delete my account
|
|
||||||
</button>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</main>
|
</main>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
27
admin/package-lock.json
generated
27
admin/package-lock.json
generated
|
|
@ -46,6 +46,7 @@
|
||||||
"react-adonis-transmit": "^1.0.1",
|
"react-adonis-transmit": "^1.0.1",
|
||||||
"react-dom": "^19.1.0",
|
"react-dom": "^19.1.0",
|
||||||
"reflect-metadata": "^0.2.2",
|
"reflect-metadata": "^0.2.2",
|
||||||
|
"systeminformation": "^5.27.7",
|
||||||
"tailwindcss": "^4.1.10",
|
"tailwindcss": "^4.1.10",
|
||||||
"yaml": "^2.8.0"
|
"yaml": "^2.8.0"
|
||||||
},
|
},
|
||||||
|
|
@ -10494,6 +10495,32 @@
|
||||||
"url": "https://opencollective.com/synckit"
|
"url": "https://opencollective.com/synckit"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/systeminformation": {
|
||||||
|
"version": "5.27.7",
|
||||||
|
"resolved": "https://registry.npmjs.org/systeminformation/-/systeminformation-5.27.7.tgz",
|
||||||
|
"integrity": "sha512-saaqOoVEEFaux4v0K8Q7caiauRwjXC4XbD2eH60dxHXbpKxQ8kH9Rf7Jh+nryKpOUSEFxtCdBlSUx0/lO6rwRg==",
|
||||||
|
"license": "MIT",
|
||||||
|
"os": [
|
||||||
|
"darwin",
|
||||||
|
"linux",
|
||||||
|
"win32",
|
||||||
|
"freebsd",
|
||||||
|
"openbsd",
|
||||||
|
"netbsd",
|
||||||
|
"sunos",
|
||||||
|
"android"
|
||||||
|
],
|
||||||
|
"bin": {
|
||||||
|
"systeminformation": "lib/cli.js"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=8.0.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"type": "Buy me a coffee",
|
||||||
|
"url": "https://www.buymeacoffee.com/systeminfo"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/tabbable": {
|
"node_modules/tabbable": {
|
||||||
"version": "6.2.0",
|
"version": "6.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/tabbable/-/tabbable-6.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/tabbable/-/tabbable-6.2.0.tgz",
|
||||||
|
|
|
||||||
|
|
@ -92,6 +92,7 @@
|
||||||
"react-adonis-transmit": "^1.0.1",
|
"react-adonis-transmit": "^1.0.1",
|
||||||
"react-dom": "^19.1.0",
|
"react-dom": "^19.1.0",
|
||||||
"reflect-metadata": "^0.2.2",
|
"reflect-metadata": "^0.2.2",
|
||||||
|
"systeminformation": "^5.27.7",
|
||||||
"tailwindcss": "^4.1.10",
|
"tailwindcss": "^4.1.10",
|
||||||
"yaml": "^2.8.0"
|
"yaml": "^2.8.0"
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -43,6 +43,7 @@ router.group(() => {
|
||||||
}).prefix('/api/docs')
|
}).prefix('/api/docs')
|
||||||
|
|
||||||
router.group(() => {
|
router.group(() => {
|
||||||
|
router.get('/info', [SystemController, 'getSystemInfo'])
|
||||||
router.get('/services', [SystemController, 'getServices'])
|
router.get('/services', [SystemController, 'getServices'])
|
||||||
router.post('/services/affect', [SystemController, 'affectService'])
|
router.post('/services/affect', [SystemController, 'affectService'])
|
||||||
router.post('/services/install', [SystemController, 'installService'])
|
router.post('/services/install', [SystemController, 'installService'])
|
||||||
|
|
|
||||||
9
admin/types/system.ts
Normal file
9
admin/types/system.ts
Normal file
|
|
@ -0,0 +1,9 @@
|
||||||
|
import { Systeminformation } from "systeminformation"
|
||||||
|
|
||||||
|
|
||||||
|
export type SystemInformationResponse = {
|
||||||
|
cpu: Systeminformation.CpuData
|
||||||
|
mem: Systeminformation.MemData
|
||||||
|
os: Systeminformation.OsData
|
||||||
|
disk: Systeminformation.DiskLayoutData[]
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue
Block a user