Skip to content

Commit

Permalink
feat(ui): quick stats
Browse files Browse the repository at this point in the history
  • Loading branch information
SpikeHD committed Sep 24, 2023
1 parent 17f6d23 commit 9958a68
Show file tree
Hide file tree
Showing 11 changed files with 228 additions and 32 deletions.
2 changes: 1 addition & 1 deletion frontend/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
<meta name="color-scheme" content="light dark" />
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Dela+Gothic+One&display=swap" rel="stylesheet">
<link href="https://fonts.googleapis.com/css2?family=Dela+Gothic+One&family=Montserrat:ital,wght@0,400;0,700;1,400&display=swap" rel="stylesheet">
<title>Procchi</title>
</head>
<body>
Expand Down
28 changes: 28 additions & 0 deletions frontend/src/components/Loader.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
/* https://loading.io/css/ */
.loader {
display: inline-block;
width: 80px;
height: 80px;
}

.loader:after {
content: " ";
display: block;
width: 64px;
height: 64px;
margin: 8px;
border-radius: 50%;
border: 6px solid var(--color-primary);
border-color: var(--color-primary) transparent var(--color-primary) transparent;
animation: loader-anim 1.2s linear infinite;
}

@keyframes loader-anim {
0% {
transform: rotate(0deg);
}

100% {
transform: rotate(360deg);
}
}
7 changes: 7 additions & 0 deletions frontend/src/components/Loader.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import './Loader.css'

export function Loader() {
return (
<div className="loader"></div>
)
}
31 changes: 31 additions & 0 deletions frontend/src/components/QuickStats.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
.quick-stats {
display: flex;
flex-direction: row;
justify-content: space-around;
align-items: center;

width: 80%;
height: 120px;

margin: 24px;

border: 1px solid var(--color-accent);
border-radius: 6px;
}

.stat {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
}

.stat-big {
font-size: 32px;
font-weight: bold;
}

.stat-small {
font-size: 16px;
font-weight: normal;
}
31 changes: 31 additions & 0 deletions frontend/src/components/QuickStats.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { bytesToReadable } from '../util/byte'
import './QuickStats.css'

interface Props {
sysinfo: SystemInfo;
memoryData: Memory[];
swapData: Memory[];
cpuData: CPU[];
processList: Process[];
}

export function QuickStats(props: Props) {
const memoryUse = props.memoryData[props.memoryData.length - 1]?.used
const cpuPct = props.cpuData[props.cpuData.length - 1]?.used

return (
<div className="quick-stats">
<div className="stat">
<span className="stat-big">{bytesToReadable(memoryUse)}</span>
<span className="stat-small">{
(memoryUse / props.sysinfo.mem_size * 100).toFixed(2)
}% of total memory ({bytesToReadable(props.sysinfo.mem_size)})</span>
</div>

<div className="stat">
<span className="stat-big">{cpuPct.toFixed(2)}%</span>
<span className="stat-small">CPU usage</span>
</div>
</div>
)
}
26 changes: 0 additions & 26 deletions frontend/src/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,34 +4,8 @@ import { LocationProvider, Router, Route } from 'preact-iso'
import { Home } from './pages/Home/index.jsx'
import { NotFound } from './pages/_404.jsx'
import './style.css'
import { useEffect, useState } from 'preact/hooks'

export function App() {
const [memoryData, setMemoryData] = useState([])
const [swapData, setSwapData] = useState([])
const [cpuData, setCpuData] = useState([])

// TODO: Unused for now
//const [diskData, setDiskData] = useState([])

useEffect(() => {
async function grabLatestData() {
const mres = await fetch('/api/memory')
const mdata = await mres.json()
setMemoryData(mdata)

const sres = await fetch('/api/swap')
const sdata = await sres.json()
setSwapData(sdata)

const cres = await fetch('/api/cpu')
const cdata = await cres.json()
setCpuData(cdata)
}

setInterval(grabLatestData, 5000)
}, [])

return (
<div id="root">
<div id="header">
Expand Down
65 changes: 61 additions & 4 deletions frontend/src/pages/Home/index.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,68 @@


import { useEffect, useState } from 'preact/hooks'
import { Loader } from '../../components/Loader'
import { QuickStats } from '../../components/QuickStats'
import './style.css'

export function Home() {
const [sysinfo, setSysinfo] = useState({} as SystemInfo)
const [memoryData, setMemoryData] = useState([] as Memory[])
const [swapData, setSwapData] = useState([] as Memory[])
const [cpuData, setCpuData] = useState([] as CPU[])
const [processList, setProcessList] = useState([] as Process[])

// TODO: Unused for now
// const [diskData, setDiskData] = useState([])

useEffect(() => {
async function grabLatestData() {
const mres = await fetch('/api/memory')
const mdata = await mres.json()
setMemoryData(mdata)

const sres = await fetch('/api/swap')
const sdata = await sres.json()
setSwapData(sdata)

const cres = await fetch('/api/cpu')
const cdata = await cres.json()
setCpuData(cdata)

const pres = await fetch('/api/processes')
const pdata = await pres.json()
setProcessList(pdata)
}

// This only needs to run once
(async () => {
await grabLatestData()

const res = await fetch('/api/sysinfo')
const data = await res.json()
setSysinfo(data)
})()

setInterval(grabLatestData, 5000)
}, [])

return (
<div className="root">

<div className="home-root">
{
sysinfo?.os_name ? (
<>
<QuickStats
sysinfo={sysinfo}
memoryData={memoryData}
swapData={swapData}
cpuData={cpuData}
processList={processList}
/>
</>
) : (
<div className="loading">
<Loader />
</div>
)
}
</div>
)
}
19 changes: 19 additions & 0 deletions frontend/src/pages/Home/style.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
.loading {
display: flex;
justify-content: center;
align-items: center;
height: 100px;
width: 100px;

margin: auto;
}

.home-root {
height: 100%;
width: 100%;

display: flex;
flex-direction: column;
justify-content: flex-start;
align-items: center;
}
8 changes: 7 additions & 1 deletion frontend/src/style.css
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
--background: #fbfefb;
--text-primary: var(--background);
--text-secondary: #092207;
--color-primary: #9eeb99;
--color-primary: #824f92;
--color-secondary: #efc3ef;
--color-accent: #c832c8;
}
Expand All @@ -12,8 +12,14 @@ body {
padding: 0;
background: var(--background);
color: var(--text-secondary);

font-family: 'Montserrat', sans-serif;

width: 100vw;
height: 100vh;
}

main,
#root {
height: 100%;
width: 100%;
Expand Down
11 changes: 11 additions & 0 deletions frontend/src/util/byte.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
export function bytesToReadable(bytes: number) {
const sizes = ['B', 'KB', 'MB', 'GB', 'TB']

if (bytes === 0) return '0B'

const i = Math.floor(Math.log(bytes) / Math.log(1024))

if (i === 0) return `${bytes}${sizes[i]}`

return `${(bytes / Math.pow(1024, i)).toFixed(2)}${sizes[i]}`
}
32 changes: 32 additions & 0 deletions frontend/types.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
interface Memory {
timestamp: number;
total: number;
used: number;
available: number;
}

interface CPU {
timestamp: number;
used: number; // This is a percentage
}

interface Process {
name: string;
pid: number;
cpu: number;
mem: number;
}

interface SystemInfo {
mem_size: number;
swap_size: number;
cpu_count: number;
cpu_brand: string;
cpu_model: string;
cpu_vendor: string;
cpu_frequency: number;
os_name: string;
os_version: string;
hostname: string;
uptime: number;
}

0 comments on commit 9958a68

Please sign in to comment.