Refactor Dashboard and App components to utilize new UI elements
Publish Docker image / build-and-push (push) Failing after 1m3s
Publish Docker image / build-and-push (push) Failing after 1m3s
- Updated App.jsx to enhance the SidebarInset and main content layout with improved styling. - Refactored Dashboard.jsx to replace traditional HTML elements with Card, CardContent, Button, and Badge components for a more consistent UI. - Improved error handling display and button interactions for better user experience. Made-with: Cursor
This commit is contained in:
@@ -211,8 +211,8 @@ function MainLayout() {
|
||||
</div>
|
||||
</SidebarFooter>
|
||||
</Sidebar>
|
||||
<SidebarInset>
|
||||
<header className="sticky top-0 z-10 flex h-14 items-center gap-2 border-b bg-background px-4">
|
||||
<SidebarInset className="bg-muted/20">
|
||||
<header className="sticky top-0 z-10 flex h-14 items-center gap-2 border-b bg-background/95 px-4 backdrop-blur">
|
||||
<SidebarTrigger />
|
||||
<Separator orientation="vertical" className="h-4" />
|
||||
<Breadcrumb>
|
||||
@@ -237,7 +237,7 @@ function MainLayout() {
|
||||
</DropdownMenu>
|
||||
</div>
|
||||
</header>
|
||||
<main id="main-content" className="p-4">
|
||||
<main id="main-content" className="mx-auto w-full max-w-[1600px] p-4">
|
||||
<AppRoutes />
|
||||
</main>
|
||||
<footer className="border-t p-3 text-sm text-muted-foreground">Версия UI: {import.meta?.env?.VITE_APP_VERSION || 'dev'}</footer>
|
||||
|
||||
+34
-27
@@ -32,11 +32,14 @@ import LastSaved from './components/LastSaved.jsx';
|
||||
import Tooltip from './components/Tooltip.jsx';
|
||||
import Sparkline from './components/Sparkline.jsx';
|
||||
import { useAlerts } from './contexts/AlertsContext.jsx';
|
||||
import { Card, CardContent } from '@/components/ui/card';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { Badge } from '@/components/ui/badge';
|
||||
|
||||
function StatCard({ icon: _Icon, color, value, title, subtitle, to, trend, previousValue }) {
|
||||
return (
|
||||
<div className="card h-100 position-relative card-hover">
|
||||
<div className="card-body d-flex align-items-center">
|
||||
<Card className="h-100 position-relative card-hover">
|
||||
<CardContent className="d-flex align-items-center p-3">
|
||||
<span className={`avatar avatar-lg me-3 bg-${color}-lt text-${color} border-0`}>
|
||||
<_Icon size={32} />
|
||||
</span>
|
||||
@@ -56,18 +59,18 @@ function StatCard({ icon: _Icon, color, value, title, subtitle, to, trend, previ
|
||||
<div className="text-muted small opacity-75">{subtitle}</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</CardContent>
|
||||
{to && (
|
||||
<Link to={to} className="stretched-link" aria-label={`Перейти к ${title}`}></Link>
|
||||
)}
|
||||
</div>
|
||||
</Card>
|
||||
);
|
||||
}
|
||||
|
||||
function MetricCard({ title, value, icon: _Icon, color, description }) {
|
||||
return (
|
||||
<div className="card h-100 position-relative">
|
||||
<div className="card-body d-flex align-items-center">
|
||||
<Card className="h-100 position-relative">
|
||||
<CardContent className="d-flex align-items-center p-3">
|
||||
<span className={`avatar avatar-lg me-3 bg-${color}-lt text-${color} border-0`}>
|
||||
<_Icon size={32} />
|
||||
</span>
|
||||
@@ -79,8 +82,8 @@ function MetricCard({ title, value, icon: _Icon, color, description }) {
|
||||
<div className="text-muted lh-1">{description}</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -357,10 +360,12 @@ function Dashboard() {
|
||||
|
||||
if (error) {
|
||||
return (
|
||||
<div className="alert alert-danger" role="alert">
|
||||
<IconAlertTriangle className="me-2" />
|
||||
{error}
|
||||
</div>
|
||||
<Card className="border-destructive">
|
||||
<CardContent className="p-3 text-destructive">
|
||||
<IconAlertTriangle className="me-2" />
|
||||
{error}
|
||||
</CardContent>
|
||||
</Card>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -377,9 +382,9 @@ function Dashboard() {
|
||||
<LastSaved timestamp={lastFetchTime} variant="compact" />
|
||||
)}
|
||||
<Tooltip content="Обновить данные" shortcut="⌘R">
|
||||
<button className="btn btn-outline-primary btn-sm" onClick={() => window.location.reload()}>
|
||||
<Button variant="outline" size="sm" onClick={() => window.location.reload()}>
|
||||
<IconRefresh className="me-2" /> Обновить
|
||||
</button>
|
||||
</Button>
|
||||
</Tooltip>
|
||||
</div>
|
||||
)}
|
||||
@@ -389,15 +394,16 @@ function Dashboard() {
|
||||
<div className="d-flex flex-column flex-sm-row align-items-start align-items-sm-center justify-content-between gap-2 mb-2">
|
||||
<h3 className="mb-0">Пинг сервисов</h3>
|
||||
<Tooltip content="Принудительно обновить пинг (без учёта кэша), история и тренд накапливаются">
|
||||
<button
|
||||
<Button
|
||||
type="button"
|
||||
className="btn btn-outline-primary btn-sm w-100 w-sm-auto"
|
||||
variant="outline"
|
||||
size="sm"
|
||||
onClick={() => fetchPingServices(true)}
|
||||
disabled={pingLoading}
|
||||
>
|
||||
<IconRefresh className={pingLoading ? 'spin me-1' : 'me-1'} size={16} />
|
||||
Обновить пинг
|
||||
</button>
|
||||
</Button>
|
||||
</Tooltip>
|
||||
</div>
|
||||
<div className="row g-3 mb-4">
|
||||
@@ -429,28 +435,29 @@ function Dashboard() {
|
||||
<IconBell size={24} />
|
||||
Активные оповещения
|
||||
{alerts.length > 0 && (
|
||||
<span className="badge bg-danger rounded-pill">{alerts.length}</span>
|
||||
<Badge variant="destructive">{alerts.length}</Badge>
|
||||
)}
|
||||
</h3>
|
||||
<button
|
||||
<Button
|
||||
type="button"
|
||||
className="btn btn-outline-primary btn-sm"
|
||||
variant="outline"
|
||||
size="sm"
|
||||
onClick={() => refreshAlerts()}
|
||||
disabled={alertsLoading}
|
||||
>
|
||||
<IconRefresh className={alertsLoading ? 'spin me-1' : 'me-1'} size={16} />
|
||||
Обновить
|
||||
</button>
|
||||
</Button>
|
||||
</div>
|
||||
{alerts.length === 0 && !alertsLoading && (
|
||||
<div className="card">
|
||||
<div className="card-body text-center text-muted py-4">
|
||||
<Card>
|
||||
<CardContent className="text-center text-muted py-4">
|
||||
Нет активных оповещений
|
||||
</div>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
)}
|
||||
{alerts.length > 0 && (
|
||||
<div className="card">
|
||||
<Card>
|
||||
<div className="list-group list-group-flush">
|
||||
{alerts.map((alert) => {
|
||||
const Icon = ALERT_ICONS[alert.type] || IconAlertTriangle;
|
||||
@@ -471,7 +478,7 @@ function Dashboard() {
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
</Card>
|
||||
)}
|
||||
</div>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user