add some stuff
This commit is contained in:
parent
c23af50f0f
commit
2d9e0ef66e
11
package.json
11
package.json
|
@ -27,11 +27,12 @@
|
|||
"svelte-check": "^3.6.9",
|
||||
"tslib": "^2.6.2",
|
||||
"typescript": "^5.4.5",
|
||||
"vite": "^5.2.8"
|
||||
"vite": "^5.2.8",
|
||||
"@fontsource-variable/inter": "^5.0.17",
|
||||
"@fontsource/iosevka": "^5.0.7",
|
||||
"unplugin-icons": "^0.18.5",
|
||||
"@iconify-json/ri": "^1.1.20"
|
||||
},
|
||||
"type": "module",
|
||||
"dependencies": {
|
||||
"@fontsource-variable/inter": "^5.0.17",
|
||||
"@fontsource/iosevka": "^5.0.7"
|
||||
}
|
||||
"dependencies": {}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,38 @@
|
|||
import { fetchAPI } from './api';
|
||||
|
||||
enum MountPointTypeEnum {
|
||||
EMPTY = '',
|
||||
BIND = 'bind',
|
||||
VOLUME = 'volume',
|
||||
TMPFS = 'tmpfs',
|
||||
NPIPE = 'npipe',
|
||||
CLUSTER = 'cluster'
|
||||
}
|
||||
|
||||
interface MountPoint {
|
||||
Type?: MountPointTypeEnum;
|
||||
Name?: string;
|
||||
Source?: string;
|
||||
Destination?: string;
|
||||
Driver?: string;
|
||||
Mode?: string;
|
||||
RW?: boolean;
|
||||
Propagation?: string;
|
||||
}
|
||||
|
||||
export interface ContainerInfo {
|
||||
id: string;
|
||||
name: string;
|
||||
state: string;
|
||||
image: string;
|
||||
image_id: string;
|
||||
created_at: string;
|
||||
volumes?: MountPoint[];
|
||||
env?: string[];
|
||||
labels?: Record<string, string>;
|
||||
}
|
||||
|
||||
export async function getContainerList(): Promise<ContainerInfo[]> {
|
||||
const res = await fetchAPI('/containers');
|
||||
return res.json();
|
||||
}
|
|
@ -31,6 +31,7 @@ export interface SystemInfo {
|
|||
disks: DiskInfo[];
|
||||
|
||||
// CPU
|
||||
cpu_count: number;
|
||||
load_average: [number, number, number];
|
||||
}
|
||||
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
|
||||
& header {
|
||||
margin-bottom: var(--padding-normal);
|
||||
font-weight: bold;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -57,4 +57,9 @@
|
|||
font-family: var(--font-sans);
|
||||
scrollbar-width: thin;
|
||||
}
|
||||
|
||||
:global(p) {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -1,8 +1,10 @@
|
|||
import { getContainerList } from '$lib/server/containers';
|
||||
import { getSystemInfo } from '$lib/server/system';
|
||||
import type { PageServerLoad } from './$types';
|
||||
|
||||
export const load: PageServerLoad = async ({ params }) => {
|
||||
export const load: PageServerLoad = async ({}) => {
|
||||
return {
|
||||
systemInfo: await getSystemInfo()
|
||||
systemInfo: await getSystemInfo(),
|
||||
containers: await getContainerList()
|
||||
};
|
||||
};
|
||||
|
|
|
@ -1,8 +1,10 @@
|
|||
<script lang="ts">
|
||||
import type { PageData } from './$types';
|
||||
import HardwareInfo from './HardwareInfo.svelte';
|
||||
import ContainerList from './ContainerList.svelte';
|
||||
import SystemInfo from './SystemInfo.svelte';
|
||||
|
||||
export let data: PageData;
|
||||
</script>
|
||||
|
||||
<HardwareInfo data={data.systemInfo} />
|
||||
<SystemInfo data={data.systemInfo} />
|
||||
<ContainerList data={data.containers} />
|
||||
|
|
|
@ -0,0 +1,11 @@
|
|||
<script lang="ts">
|
||||
import type { ContainerInfo } from '$lib/server/containers';
|
||||
|
||||
export let data: ContainerInfo[];
|
||||
</script>
|
||||
|
||||
<ul>
|
||||
{#each data as container}
|
||||
<li>{container.name}</li>
|
||||
{/each}
|
||||
</ul>
|
|
@ -1,15 +0,0 @@
|
|||
<script lang="ts">
|
||||
import type { SystemInfo } from '$lib/server/system';
|
||||
import Panel from '$lib/ui/Panel.svelte';
|
||||
|
||||
export let data: SystemInfo;
|
||||
</script>
|
||||
|
||||
<Panel title="Hardware Info">
|
||||
{data.host_name}
|
||||
</Panel>
|
||||
|
||||
<style>
|
||||
.hardware-info {
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,145 @@
|
|||
<script lang="ts">
|
||||
import type { SystemInfo } from '$lib/server/system';
|
||||
import Panel from '$lib/ui/Panel.svelte';
|
||||
import IconCPU from '~icons/ri/cpu-fill';
|
||||
import IconRAM from '~icons/ri/ram-fill';
|
||||
import IconDrive from '~icons/ri/hard-drive-2-fill';
|
||||
|
||||
export let data: SystemInfo;
|
||||
|
||||
function formatBytes(bytes: number): string {
|
||||
const sizes = ['B', 'KiB', 'MiB', 'GiB', 'TiB'];
|
||||
if (bytes === 0) {
|
||||
return 'n/a';
|
||||
}
|
||||
const i = Math.floor(Math.log(bytes) / Math.log(1024));
|
||||
return `${(bytes / 1024 ** i).toFixed(1)} ${sizes[i]}`;
|
||||
}
|
||||
</script>
|
||||
|
||||
<Panel title="System info">
|
||||
<div class="sections">
|
||||
<section class="info">
|
||||
<dl>
|
||||
<dt>Hostname</dt>
|
||||
<dd>{data.host_name}</dd>
|
||||
<dt>Hardware</dt>
|
||||
<dd>
|
||||
<IconCPU />
|
||||
{data.cpu_count}
|
||||
<IconRAM />
|
||||
{formatBytes(data.total_memory)}
|
||||
<IconDrive />
|
||||
{formatBytes(data.disks[0].total_space)}
|
||||
</dd>
|
||||
<dt>OS</dt>
|
||||
<dd>
|
||||
{data.name}
|
||||
{data.os_version} (kernel {data.kernel_version})
|
||||
</dd>
|
||||
</dl>
|
||||
</section>
|
||||
<section class="stats">
|
||||
<header>Load Avg</header>
|
||||
<article>{data.load_average[0]} - {data.load_average[1]} - {data.load_average[2]}</article>
|
||||
</section>
|
||||
<section class="stats">
|
||||
<header>RAM usage</header>
|
||||
<article>
|
||||
<p>{formatBytes(data.used_memory)} / {formatBytes(data.total_memory)}</p>
|
||||
<progress value={data.used_memory} max={data.total_memory} />
|
||||
</article>
|
||||
</section>
|
||||
<section class="stats">
|
||||
<header>Disk usage</header>
|
||||
<article>
|
||||
<p>
|
||||
{formatBytes(data.disks[0].total_space - data.disks[0].available_space)}
|
||||
/
|
||||
{formatBytes(data.disks[0].total_space)}
|
||||
</p>
|
||||
<progress
|
||||
value={data.disks[0].total_space - data.disks[0].available_space}
|
||||
max={data.disks[0].total_space}
|
||||
/>
|
||||
</article>
|
||||
</section>
|
||||
</div>
|
||||
</Panel>
|
||||
|
||||
<style scoped>
|
||||
.sections {
|
||||
display: flex;
|
||||
gap: 1rem;
|
||||
flex-wrap: wrap;
|
||||
|
||||
& > * {
|
||||
background-color: var(--table-bg);
|
||||
padding: var(--padding-normal);
|
||||
border: 1px solid var(--table-border-color);
|
||||
border-radius: 3px;
|
||||
}
|
||||
}
|
||||
|
||||
.stats {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: stretch;
|
||||
padding: 0;
|
||||
min-width: 100px;
|
||||
flex: 1;
|
||||
text-align: center;
|
||||
|
||||
& > header {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
background-color: var(--table-bg);
|
||||
border-bottom: 1px solid var(--table-border-color);
|
||||
padding: var(--padding-narrow) 0;
|
||||
margin-bottom: var(--padding-narrow);
|
||||
}
|
||||
|
||||
& > article {
|
||||
flex: 1;
|
||||
justify-content: center;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: stretch;
|
||||
gap: var(--padding-narrow);
|
||||
padding: var(--padding-narrow) var(--padding-wide);
|
||||
|
||||
& progress {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.info {
|
||||
& dl {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
display: grid;
|
||||
grid-template-columns: 4fr 10fr;
|
||||
|
||||
& dt {
|
||||
color: var(--header-color);
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
& dd {
|
||||
display: flex;
|
||||
gap: 0.5rem;
|
||||
align-items: center;
|
||||
|
||||
& > * {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
& .right-align {
|
||||
text-align: right;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
|
@ -9,11 +9,14 @@
|
|||
"skipLibCheck": true,
|
||||
"sourceMap": true,
|
||||
"strict": true,
|
||||
"moduleResolution": "bundler"
|
||||
"moduleResolution": "bundler",
|
||||
"types": [
|
||||
"unplugin-icons/types/svelte"
|
||||
]
|
||||
}
|
||||
// Path aliases are handled by https://kit.svelte.dev/docs/configuration#alias
|
||||
// except $lib which is handled by https://kit.svelte.dev/docs/configuration#files
|
||||
//
|
||||
// If you want to overwrite includes/excludes, make sure to copy over the relevant includes/excludes
|
||||
// from the referenced tsconfig.json - TypeScript does not merge them in
|
||||
}
|
||||
}
|
|
@ -1,6 +1,12 @@
|
|||
import { sveltekit } from '@sveltejs/kit/vite';
|
||||
import { defineConfig } from 'vite';
|
||||
import Icons from 'unplugin-icons/vite';
|
||||
|
||||
export default defineConfig({
|
||||
plugins: [sveltekit()]
|
||||
plugins: [
|
||||
sveltekit(),
|
||||
Icons({
|
||||
compiler: 'svelte'
|
||||
})
|
||||
]
|
||||
});
|
||||
|
|
Loading…
Reference in New Issue