feat: Add new endpoint to fetch last modified dates of S3 files and update Dashboard to display this information
Publish Fast Tabler Docker image / build-and-push-fast (push) Successful in 16m53s
Publish Fast Tabler Docker image / build-and-push-fast (push) Successful in 16m53s
This commit is contained in:
@@ -126,6 +126,23 @@ app.post('/api/asns', async (req, res) => {
|
||||
}
|
||||
});
|
||||
|
||||
// Новый эндпоинт для получения дат последнего изменения файлов S3
|
||||
app.get('/api/s3/last-modified', async (req, res) => {
|
||||
try {
|
||||
const [domainsHead, asnsHead] = await Promise.all([
|
||||
s3.headObject({ Bucket: BUCKET_NAME, Key: 'domains.txt' }).promise(),
|
||||
s3.headObject({ Bucket: BUCKET_NAME, Key: 'asns.txt' }).promise()
|
||||
]);
|
||||
res.json({
|
||||
domainsLastModified: domainsHead.LastModified ? domainsHead.LastModified.toISOString() : null,
|
||||
asnsLastModified: asnsHead.LastModified ? asnsHead.LastModified.toISOString() : null
|
||||
});
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
res.status(500).send('Error fetching last modified dates from S3');
|
||||
}
|
||||
});
|
||||
|
||||
// The "catchall" handler: for any request that doesn't
|
||||
// match one above, send back React's index.html file.
|
||||
app.get('*', (req, res) => {
|
||||
|
||||
+42
-86
@@ -1,4 +1,4 @@
|
||||
import { useState } from 'react';
|
||||
import { useState, useEffect } from 'react';
|
||||
import { Container } from 'react-bootstrap';
|
||||
import {
|
||||
IconBrandTabler,
|
||||
@@ -19,6 +19,7 @@ import {
|
||||
} from '@tabler/icons-react';
|
||||
import DataManager from './DataManager';
|
||||
import './App.css';
|
||||
import axios from 'axios';
|
||||
|
||||
function App() {
|
||||
const [activeTab, setActiveTab] = useState('dashboard');
|
||||
@@ -171,34 +172,60 @@ function StatCard({ icon: Icon, color, value, title, subtitle }) {
|
||||
}
|
||||
|
||||
function Dashboard() {
|
||||
const [stats, setStats] = useState({ domainsCount: null, asnsCount: null, lastModified: null });
|
||||
const [loading, setLoading] = useState(true);
|
||||
|
||||
useEffect(() => {
|
||||
async function fetchStats() {
|
||||
setLoading(true);
|
||||
try {
|
||||
const [domainsRes, asnsRes, s3Res] = await Promise.all([
|
||||
axios.get('/api/domains'),
|
||||
axios.get('/api/asns'),
|
||||
axios.get('/api/s3/last-modified')
|
||||
]);
|
||||
setStats({
|
||||
domainsCount: domainsRes.data.length,
|
||||
asnsCount: asnsRes.data.length,
|
||||
lastModified: s3Res.data.domainsLastModified
|
||||
});
|
||||
} catch (e) {
|
||||
setStats({ domainsCount: null, asnsCount: null, lastModified: null });
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
}
|
||||
fetchStats();
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div className="row g-3 mb-4">
|
||||
<div className="col-md-4">
|
||||
<StatCard
|
||||
icon={IconDatabase}
|
||||
icon={IconWorld}
|
||||
color="blue"
|
||||
value={6}
|
||||
title="Событий"
|
||||
subtitle="Всего событий"
|
||||
value={loading ? '...' : stats.domainsCount ?? '—'}
|
||||
title="Доменов"
|
||||
subtitle="Всего доменов"
|
||||
/>
|
||||
</div>
|
||||
<div className="col-md-4">
|
||||
<StatCard
|
||||
icon={IconAlertTriangle}
|
||||
color="red"
|
||||
value={3}
|
||||
title="Ошибок"
|
||||
subtitle="Критические ошибки"
|
||||
icon={IconNetwork}
|
||||
color="green"
|
||||
value={loading ? '...' : stats.asnsCount ?? '—'}
|
||||
title="AS"
|
||||
subtitle="Всего AS"
|
||||
/>
|
||||
</div>
|
||||
<div className="col-md-4">
|
||||
<StatCard
|
||||
icon={IconAlertCircle}
|
||||
color="yellow"
|
||||
value={0}
|
||||
title="Предупреждений"
|
||||
subtitle="Системные предупреждения"
|
||||
icon={IconDatabase}
|
||||
color="orange"
|
||||
value={loading ? '...' : (stats.lastModified ? new Date(stats.lastModified).toLocaleString() : '—')}
|
||||
title="Обновление"
|
||||
subtitle="Последнее изменение S3"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
@@ -210,77 +237,6 @@ function Dashboard() {
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="row row-deck">
|
||||
<div className="col-sm-6 col-lg-3">
|
||||
<div className="card">
|
||||
<div className="card-body">
|
||||
<div className="h1 mb-3">1,234</div>
|
||||
<div className="d-flex align-items-center">
|
||||
<IconWorld className="icon me-2" />
|
||||
<span className="text-muted">Всего доменов</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="col-sm-6 col-lg-3">
|
||||
<div className="card">
|
||||
<div className="card-body">
|
||||
<div className="h1 mb-3">567</div>
|
||||
<div className="d-flex align-items-center">
|
||||
<IconNetwork className="icon me-2" />
|
||||
<span className="text-muted">Всего AS</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="col-sm-6 col-lg-3">
|
||||
<div className="card">
|
||||
<div className="card-body">
|
||||
<div className="h1 mb-3">12</div>
|
||||
<div className="d-flex align-items-center">
|
||||
<IconCloud className="icon me-2" />
|
||||
<span className="text-muted">Активные шлюзы</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="col-sm-6 col-lg-3">
|
||||
<div className="card">
|
||||
<div className="card-body">
|
||||
<div className="h1 mb-3">3</div>
|
||||
<div className="d-flex align-items-center">
|
||||
<IconActivity className="icon me-2" />
|
||||
<span className="text-muted">Последние изменения</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="card mt-4">
|
||||
<div className="card-body">
|
||||
<h3 className="card-title mb-3">Добро пожаловать в S3 Lists Manager</h3>
|
||||
<div className="row">
|
||||
<div className="col-md-6 mb-3">
|
||||
<div className="d-flex align-items-center">
|
||||
<IconWorld className="icon me-2" size={32} />
|
||||
<div>
|
||||
<div className="fw-bold">Управление доменами</div>
|
||||
<div className="text-muted">Добавляйте, редактируйте и управляйте списками доменов</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="col-md-6 mb-3">
|
||||
<div className="d-flex align-items-center">
|
||||
<IconNetwork className="icon me-2" size={32} />
|
||||
<div>
|
||||
<div className="fw-bold">Управление AS</div>
|
||||
<div className="text-muted">Добавляйте, редактируйте и управляйте списками AS</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user