diff --git a/app/Http/Controllers/DashboardController.php b/app/Http/Controllers/DashboardController.php
index 1819152..2b1aaee 100755
--- a/app/Http/Controllers/DashboardController.php
+++ b/app/Http/Controllers/DashboardController.php
@@ -6,6 +6,7 @@ use App\Services\SystemStatsService;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Cache;
+use Inertia\Inertia;
class DashboardController extends Controller
{
@@ -21,10 +22,12 @@ class DashboardController extends Controller
public function admin()
{
- // Get Top Sorting Option
- $topSort = Cache::get('ps_aux_sort_by', 'cpu');
+ return Inertia::render('Dashboard/Admin/AdminDashboard');
+ }
- return view('dashboard/admin', ['topSort' => $topSort]);
+ public function getTopSort()
+ {
+ return ['sortBy' => Cache::get('ps_aux_sort_by', 'cpu')];
}
public function setTopSort(Request $r)
@@ -33,11 +36,11 @@ class DashboardController extends Controller
Cache::put('ps_aux_sort_by', $r->sortBy);
- return response()->noContent();
+ return ['sortBy' => $r->sortBy];
}
public function user()
{
- return view('dashboard/user');
+ return Inertia::render('Dashboard/User/UserDashboard');
}
}
diff --git a/app/Services/SystemStatsService.php b/app/Services/SystemStatsService.php
index c2a19df..6c6daa0 100755
--- a/app/Services/SystemStatsService.php
+++ b/app/Services/SystemStatsService.php
@@ -19,38 +19,47 @@ class SystemStatsService
/**
* Fetch memory usage.
*/
- public function getMemoryUsage(): string
+ public function getMemoryUsage(): array
{
$memory = Process::pipe([
'free -m',
- "awk '/Mem:/ {print $3 \"MB / \"$2\"\" }'"
+ "awk '/Mem:/ {print $4,$3,$6,$2}'"
]);
if ($memory->failed()) {
- return $memory->errorOutput();
+ return ['error' => $memory->errorOutput()];
}
- return $memory->output();
+ $stats = $memory->output();
+ $stats = explode(" ", $stats);
+
+ return [
+ 'free' => $stats[0],
+ 'used' => $stats[1],
+ 'buffcache' => $stats[2],
+ 'total' => $stats[3]
+ ];
}
/**
* Fetch disk usage.
*/
- public function getDiskUsage(): string
+ public function getDiskUsage(): array
{
// Fetch disk usage details
- $diskUsage = Process::run('df -h / | awk \'/\\// {print $3 " " $4 " " $5}\'')->output();
+ $diskUsage = Process::run('df -h / | awk \'/\\// {print $2, $3, $4, $5}\'')->output();
$diskUsageParts = preg_split('/\s+/', trim($diskUsage));
- if (count($diskUsageParts) >= 3) {
- $usedSpace = $diskUsageParts[0];
- $availableSpace = $diskUsageParts[1];
- $usagePercentage = $diskUsageParts[2];
-
- return "{$usedSpace} / {$availableSpace} ({$usagePercentage})";
+ if (count($diskUsageParts) >= 4) {
+ return [
+ 'size' => $diskUsageParts[0],
+ 'used' => $diskUsageParts[1],
+ 'free' => $diskUsageParts[2],
+ 'percent' => $diskUsageParts[3]
+ ];
}
- return 'N/A';
+ return [];
}
/**
@@ -228,19 +237,23 @@ class SystemStatsService
{
$stats = [
'whoami' => $this->getWhoami(),
- 'cpuUsage' => $this->getCpuUsage(),
- 'memoryUsage' => $this->getMemoryUsage(),
- 'diskUsage' => $this->getDiskUsage(),
- 'loadTimes' => $this->getLoadTimes(),
- 'uptime' => $this->getUptime(),
- 'processCount' => $this->getProcessCount(),
- 'userCount' => $this->getUserCount(),
+ 'cpuStats' => [
+ 'usage' => $this->getCpuUsage(),
+ 'loadTimes' => $this->getLoadTimes(),
+ 'uptime' => $this->getUptime(),
+ 'processCount' => $this->getProcessCount(),
+ ],
+ 'diskStats' => $this->getDiskUsage(),
+ 'memoryStats' => $this->getMemoryUsage(),
'nginxStatus' => $this->getNginxStatus(),
'phpStatus' => $this->getPhpFpmStatus(),
'sslStatus' => $this->getSslStatus(),
'nginxPort' => $this->getNginxPort(),
'apache' => $this->getApacheStatus(),
- 'mysql' => $this->getMysqlStatus()
+ 'mysql' => $this->getMysqlStatus(),
+
+ 'domainCount' => rand(1, 100),
+ 'userCount' => $this->getUserCount(),
];
return $stats;
diff --git a/resources/js/Components/StatCard.jsx b/resources/js/Components/StatCard.jsx
deleted file mode 100644
index d3e3e63..0000000
--- a/resources/js/Components/StatCard.jsx
+++ /dev/null
@@ -1,18 +0,0 @@
-
-const StatCard = ({ icon, label, value, status, subtext }) => {
- return (
-
-
- {icon}
-
-
{label}
-
{value}
- {status &&
Status: {status}
}
- {subtext &&
{subtext}
}
-
-
-
- );
-}
-
-export default StatCard
diff --git a/resources/js/Pages/Dashboard.jsx b/resources/js/Pages/Dashboard.jsx
deleted file mode 100644
index 79a742f..0000000
--- a/resources/js/Pages/Dashboard.jsx
+++ /dev/null
@@ -1,136 +0,0 @@
-import AuthenticatedLayout from '@/Layouts/AuthenticatedLayout';
-import { Head } from '@inertiajs/react';
-import { RiDashboard3Fill } from "react-icons/ri";
-import { useEffect, useState } from "react";
-import ShowError from '@/Components/ShowError';
-import StatCard from '@/Components/StatCard';
-import { FaMicrochip, FaMemory, FaHardDrive, FaBarsProgress, FaArrowUpShortWide, FaSitemap, FaUsers, FaLock } from "react-icons/fa6";
-import { SiApache, SiNginx, SiMysql, SiPhp } from "react-icons/si";
-
-
-
-export default function Dashboard() {
-
- const [liveStats, setLiveStats] = useState([]);
- const [topStats, setTopStats] = useState([]);
-
- const echo = window.Echo;
- const dashboardChannel = echo.private("systemstats");
- const topStatsChannel = echo.private("topstats");
-
-
- useEffect(() => {
-
- dashboardChannel.listen("SystemStatsEvent", (data) => {
- console.log(data);
- console.log(typeof data.phpStatus);
- setLiveStats(data);
- });
-
- topStatsChannel.listen("TopStatsEvent", (data) => {
- // console.log(data);
- setTopStats(data);
- });
-
- // Set interval to "whisper" every 2 seconds
- // Makes it so we get stats via sockets
- const whisperInterval = setInterval(() => {
- dashboardChannel.whisper("typing", { requesting: "dashboard-realtime-stats" });
- topStatsChannel.whisper("typing", { requesting: "dashboard-top-stats" });
- }, 2000);
-
- return () => {
- clearInterval(whisperInterval);
- echo.leave("systemstats");
- echo.leave("topstats");
- };
- }, []);
-
- return (
-
-
- Dashboard
-
- }
- >
-
-
-
- } label="CPU Usage" value={`${liveStats?.cpuUsage}%`} />
- } label="Memory Usage" value={`${liveStats?.memoryUsage} MB`} />
- } label="Disk Usage" value={liveStats?.diskUsage} />
- } label="Load Times" value={liveStats?.loadTimes} />
- } label="Uptime" value={liveStats?.uptime} />
- } label="Processes" value={liveStats?.processCount} />
- } label="Accounts" value={`${liveStats?.userCount} users, ${liveStats?.domainCount} domains`} />
- } label="Apache Server" value={liveStats?.apache?.memory} status={liveStats?.apache?.status} />
- } label="Nginx Status" value={liveStats?.nginxStatus} subtext={`Port: ${liveStats?.nginxPort || 'N/A'}`} />
- } label="MySQL Server" value={liveStats?.mysql?.memory} status={liveStats?.mysql?.status} />
- } label="SSL Status" value={liveStats?.sslStatus} />
-
-
-
-
-
-
Top 20 Processes
-
- TOGGLE CPu | MEm
-
-
-
-
-
- {topStats?.error &&
}
-
-
-
-
- | PID |
- %CPU |
- %MEM |
- USER |
- COMMAND |
-
-
-
- {topStats?.processes?.length > 0 ? (
- topStats?.processes?.map((process, index) => (
-
- |
- {process.pid}
- |
-
- {process.cpu}%
- |
-
- {process.mem}%
- |
-
- {process.user}
- |
-
-
- |
-
- ))
- ) : (
-
- |
- No processes found.
- |
-
- )}
-
-
-
-
-
- );
-}
diff --git a/resources/js/Pages/Dashboard/Admin/AdminDashboard.jsx b/resources/js/Pages/Dashboard/Admin/AdminDashboard.jsx
new file mode 100644
index 0000000..32bb073
--- /dev/null
+++ b/resources/js/Pages/Dashboard/Admin/AdminDashboard.jsx
@@ -0,0 +1,66 @@
+import AuthenticatedLayout from '@/Layouts/AuthenticatedLayout';
+import { Head, Link } from '@inertiajs/react';
+import { RiDashboard3Fill } from "react-icons/ri";
+import { useEffect, useState } from "react";
+import TopProcesses from './Components/TopProcesses';
+import CPULive from './Components/CPULive';
+import MemoryLive from './Components/MemoryLive';
+import DiskLive from './Components/DiskLive';
+
+
+export default function Dashboard() {
+
+ const [liveStats, setLiveStats] = useState([]);
+
+ const echo = window.Echo;
+ const dashboardChannel = echo.private("systemstats");
+
+ useEffect(() => {
+
+ dashboardChannel.listen("SystemStatsEvent", (data) => {
+ console.log(data);
+ setLiveStats(data);
+ });
+
+ const whisperInterval = setInterval(() => {
+ dashboardChannel.whisper("typing", { requesting: "dashboard-realtime-stats" });
+ }, 2000);
+
+ return () => {
+ clearInterval(whisperInterval);
+ echo.leave("systemstats");
+ };
+ }, []);
+
+ return (
+
+
+ Dashboard
+
+ }
+ >
+
+
+
+
+ {/* CPU Usage*/}
+
+
+ {/* Memory Usage*/}
+
+
+ {/* Disk Usage */}
+
+
+
+
+
+
+
+
+
+
+ );
+}
diff --git a/resources/js/Pages/Dashboard/Admin/Components/CPULive.jsx b/resources/js/Pages/Dashboard/Admin/Components/CPULive.jsx
new file mode 100644
index 0000000..fda7e18
--- /dev/null
+++ b/resources/js/Pages/Dashboard/Admin/Components/CPULive.jsx
@@ -0,0 +1,65 @@
+import { Link } from '@inertiajs/react';
+import { FaMicrochip, FaBarsProgress, FaArrowUpShortWide, FaSitemap } from "react-icons/fa6";
+import { FaAngleDoubleRight } from "react-icons/fa";
+import { TbAntennaBars5 } from "react-icons/tb";
+import { ImSpinner9 } from "react-icons/im";
+
+const CPULive = ({ cpuStats }) => {
+
+ return (
+
+
+
+
+
+
+
+
CPU Stats
+
+
+
+
+
+
+
+
+
+
+
+ Live Load: {cpuStats?.usage ? (
+ cpuStats.usage + "%"
+ ) : (
+
+ )}
+
+
+
+ Average: {cpuStats?.loadTimes ? (
+ cpuStats.loadTimes
+ ) : (
+
+ )}
+
+
+
+ Processes: {cpuStats?.processCount ? (
+ cpuStats.processCount
+ ) : (
+
+ )}
+
+
+
+ Uptime: {cpuStats?.uptime ? (
+ cpuStats.uptime
+ ) : (
+
+ )}
+
+
+
+
+ );
+}
+
+export default CPULive
diff --git a/resources/js/Pages/Dashboard/Admin/Components/DiskLive.jsx b/resources/js/Pages/Dashboard/Admin/Components/DiskLive.jsx
new file mode 100644
index 0000000..e67fe91
--- /dev/null
+++ b/resources/js/Pages/Dashboard/Admin/Components/DiskLive.jsx
@@ -0,0 +1,57 @@
+import { FaBuffer, FaHardDrive } from "react-icons/fa6";
+import { ImSpinner9 } from "react-icons/im";
+import { GiPenguin, GiProgression } from "react-icons/gi";
+import { MdOutlineSummarize } from "react-icons/md";
+
+const DiskLive = ({ diskStats }) => {
+
+ return (
+
+
+
+
+
+
+
+
Disk Usage at /
+
+
+
+
+
+ Used: {diskStats?.used ? (
+ diskStats.used
+ ) : (
+
+ )}
+
+
+
+ Free: {diskStats?.free ? (
+ diskStats.free
+ ) : (
+
+ )}
+
+
+
+ Size: {diskStats?.size ? (
+ diskStats.size
+ ) : (
+
+ )}
+
+
+
+ Percent Used : {diskStats?.percent ? (
+ diskStats.percent
+ ) : (
+
+ )}
+
+
+
+ );
+}
+
+export default DiskLive
diff --git a/resources/js/Pages/Dashboard/Admin/Components/MemoryLive.jsx b/resources/js/Pages/Dashboard/Admin/Components/MemoryLive.jsx
new file mode 100644
index 0000000..7197881
--- /dev/null
+++ b/resources/js/Pages/Dashboard/Admin/Components/MemoryLive.jsx
@@ -0,0 +1,66 @@
+import { Link } from '@inertiajs/react';
+
+import { FaMemory, FaBuffer, } from "react-icons/fa6";
+import { FaAngleDoubleRight } from "react-icons/fa";
+import { ImSpinner9 } from "react-icons/im";
+import { GiPenguin, GiProgression } from "react-icons/gi";
+import { MdOutlineSummarize } from "react-icons/md";
+
+const MemoryLive = ({ memoryStats }) => {
+
+ return (
+
+
+
+
+
+
+
+
Memory Usage
+
+
+
+
+
+
+
+
+
+
+
+ Used: {memoryStats?.used ? (
+ memoryStats.used + "MB"
+ ) : (
+
+ )}
+
+
+
+ Free: {memoryStats?.free ? (
+ memoryStats.free + "MB"
+ ) : (
+
+ )}
+
+
+
+ Buff/Cache: {memoryStats?.buffcache ? (
+ memoryStats.buffcache + "MB"
+ ) : (
+
+ )}
+
+
+
+ Total: {memoryStats?.total ? (
+ memoryStats.total + "MB"
+ ) : (
+
+ )}
+
+
+
+ );
+}
+
+export default MemoryLive
diff --git a/resources/js/Pages/Dashboard/Admin/Components/TopProcesses.jsx b/resources/js/Pages/Dashboard/Admin/Components/TopProcesses.jsx
new file mode 100644
index 0000000..c59c938
--- /dev/null
+++ b/resources/js/Pages/Dashboard/Admin/Components/TopProcesses.jsx
@@ -0,0 +1,92 @@
+import { Tooltip } from 'react-tooltip'
+import { useEffect, useState } from "react";
+
+
+const TopProcesses = () => {
+ const [topStats, setTopStats] = useState([]);
+
+ const echo = window.Echo;
+ const topStatsChannel = echo.private("topstats");
+
+ useEffect(() => {
+
+ topStatsChannel.listen("TopStatsEvent", (data) => {
+ setTopStats(data);
+ });
+
+ // Set interval to "whisper" every 2 seconds
+ // Makes it so we get stats via sockets
+ const whisperInterval = setInterval(() => {
+ topStatsChannel.whisper("typing", { requesting: "dashboard-top-stats" });
+ }, 2000);
+
+ return () => {
+ clearInterval(whisperInterval);
+ echo.leave("topstats");
+ };
+ }, []);
+
+
+ { topStats?.error && }
+
+ return (
+
+
+
Top 20 Processes
+
+ TOGGLE CPu | MEm
+
+
+
+
+
+ | PID |
+ %CPU |
+ %MEM |
+ USER |
+ COMMAND |
+
+
+
+ {topStats?.length > 0 ? (
+ topStats?.map((process, index) => (
+
+ |
+ {process.pid}
+ |
+
+ {process.cpu}%
+ |
+
+ {process.mem}%
+ |
+
+ {process.user}
+ |
+
+
+
+ |
+
+ ))
+ ) : (
+
+ |
+ No processes found.
+ |
+
+ )}
+
+
+
);
+}
+
+export default TopProcesses
diff --git a/resources/js/Pages/Profile/Edit.jsx b/resources/js/Pages/Profile/Edit.jsx
index b0fb272..53296e0 100644
--- a/resources/js/Pages/Profile/Edit.jsx
+++ b/resources/js/Pages/Profile/Edit.jsx
@@ -18,7 +18,7 @@ export default function Edit({ mustVerifyEmail, status }) {