feat: Integrate Dashboard component into MainLayout and update routing to redirect home path to /dashboard
Publish Fast Tabler Docker image / build-and-push-fast (push) Successful in 7m6s
Publish Fast Tabler Docker image / build-and-push-fast (push) Successful in 7m6s
This commit is contained in:
+5
-102
@@ -32,6 +32,7 @@ import IPRangesManager from './IPRangesManager';
|
||||
import ASNsNewManager from './ASNsNewManager';
|
||||
import AutoUrlManager from './AutoUrlManager';
|
||||
import BillingManager from './BillingManager';
|
||||
import Dashboard from './Dashboard';
|
||||
import './App.css';
|
||||
import axios from 'axios';
|
||||
import {
|
||||
@@ -107,7 +108,7 @@ function MainLayout() {
|
||||
id: 'home',
|
||||
title: 'Главная',
|
||||
icon: IconHome,
|
||||
path: '/',
|
||||
path: '/dashboard',
|
||||
single: true
|
||||
},
|
||||
{
|
||||
@@ -136,11 +137,7 @@ function MainLayout() {
|
||||
title: 'Инструменты',
|
||||
icon: IconSettings,
|
||||
items: [
|
||||
{ id: 'auto-urls', title: 'Авто URL', path: '/auto-urls', icon: IconDownload },
|
||||
{ id: 'files', title: 'Файлы', path: '/files', icon: IconFileText },
|
||||
{ id: 'cloud', title: 'Облако', path: '/cloud', icon: IconCloud },
|
||||
{ id: 'security', title: 'Безопасность', path: '/security', icon: IconShield },
|
||||
{ id: 'activity', title: 'Активность', path: '/activity', icon: IconActivity }
|
||||
{ id: 'auto-urls', title: 'Авто URL', path: '/auto-urls', icon: IconDownload }
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -288,6 +285,7 @@ function MainLayout() {
|
||||
</header>
|
||||
<div className="container-xl mt-4">
|
||||
<Routes>
|
||||
<Route path="/dashboard" element={<Dashboard />} />
|
||||
<Route path="/domains" element={
|
||||
<DataManager
|
||||
entityName="домен"
|
||||
@@ -302,108 +300,13 @@ function MainLayout() {
|
||||
<Route path="/servers" element={<ServerManager />} />
|
||||
<Route path="/billing" element={<BillingManager />} />
|
||||
<Route path="/filters" element={<FilterManager />} />
|
||||
<Route path="/" element={<Navigate to="/domains" replace />} />
|
||||
<Route path="/" element={<Navigate to="/dashboard" replace />} />
|
||||
</Routes>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function StatCard({ icon: Icon, color, value, title, subtitle }) {
|
||||
return (
|
||||
<div className="card h-100">
|
||||
<div className="card-body d-flex align-items-center">
|
||||
<span className={`avatar avatar-lg me-3 bg-${color}-lt text-${color} border-0`}>
|
||||
<Icon size={32} />
|
||||
</span>
|
||||
<div>
|
||||
<div className="h3 mb-0 fw-bold">{value} <span className="fs-5 fw-normal">{title}</span></div>
|
||||
<div className="text-muted lh-1">{subtitle}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function Dashboard() {
|
||||
const [stats, setStats] = useState({ domainsCount: null, asnsCount: null, serversCount: null, lastModified: null });
|
||||
const [loading, setLoading] = useState(true);
|
||||
|
||||
useEffect(() => {
|
||||
async function fetchStats() {
|
||||
setLoading(true);
|
||||
try {
|
||||
const [domainsRes, asnsRes, serversRes, s3Res] = await Promise.all([
|
||||
axios.get('/api/domains'),
|
||||
axios.get('/api/asns'),
|
||||
axios.get('/api/servers'),
|
||||
axios.get('/api/s3/last-modified')
|
||||
]);
|
||||
setStats({
|
||||
domainsCount: domainsRes.data.length,
|
||||
asnsCount: asnsRes.data.length,
|
||||
serversCount: serversRes.data.length,
|
||||
lastModified: s3Res.data.domainsLastModified
|
||||
});
|
||||
} catch (e) {
|
||||
setStats({ domainsCount: null, asnsCount: null, serversCount: null, lastModified: null });
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
}
|
||||
fetchStats();
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div className="row g-3 mb-4">
|
||||
<div className="col-md-3">
|
||||
<StatCard
|
||||
icon={IconWorld}
|
||||
color="blue"
|
||||
value={loading ? '...' : stats.domainsCount ?? '—'}
|
||||
title="Доменов"
|
||||
subtitle="Всего доменов"
|
||||
/>
|
||||
</div>
|
||||
<div className="col-md-3">
|
||||
<StatCard
|
||||
icon={IconNetwork}
|
||||
color="green"
|
||||
value={loading ? '...' : stats.asnsCount ?? '—'}
|
||||
title="AS"
|
||||
subtitle="Всего AS"
|
||||
/>
|
||||
</div>
|
||||
<div className="col-md-3">
|
||||
<StatCard
|
||||
icon={IconServer}
|
||||
color="purple"
|
||||
value={loading ? '...' : stats.serversCount ?? '—'}
|
||||
title="Серверов"
|
||||
subtitle="Всего серверов"
|
||||
/>
|
||||
</div>
|
||||
<div className="col-md-3">
|
||||
<StatCard
|
||||
icon={IconDatabase}
|
||||
color="orange"
|
||||
value={loading ? '...' : (stats.lastModified ? new Date(stats.lastModified).toLocaleString() : '—')}
|
||||
title="Обновление"
|
||||
subtitle="Последнее изменение S3"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div className="page-header d-print-none mb-4">
|
||||
<div className="row align-items-center">
|
||||
<div className="col">
|
||||
<h2 className="page-title">Dashboard</h2>
|
||||
<div className="page-pretitle">Главная / Dashboard</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default App;
|
||||
|
||||
Reference in New Issue
Block a user