From 82ad7c633aaeb7667aeb9eabfa31d95586eda412 Mon Sep 17 00:00:00 2001 From: Denozordec Date: Fri, 20 Mar 2026 23:21:00 +0700 Subject: [PATCH] Implement tab navigation and health check display in DashboardPage - Added tab navigation to switch between 'Overview' and 'Health Check' sections. - Introduced health issues count badge in the 'Health Check' tab. - Refactored the layout to display account balances and upcoming payment expirations in a structured format. - Enhanced user interface for better visibility of account statuses and health metrics. --- src/pages/DashboardPage.jsx | 309 ++++++++++++++++++++---------------- 1 file changed, 173 insertions(+), 136 deletions(-) diff --git a/src/pages/DashboardPage.jsx b/src/pages/DashboardPage.jsx index 5a2ea25..2ed81b1 100644 --- a/src/pages/DashboardPage.jsx +++ b/src/pages/DashboardPage.jsx @@ -17,6 +17,7 @@ import { } from '@tabler/icons-react' export function DashboardPage({ db = {}, settings, ratesData }) { + const [dashTab, setDashTab] = useState('overview') const vps = Array.isArray(db.vps) ? db.vps : [] const providerAccounts = Array.isArray(db.providerAccounts) ? db.providerAccounts : [] const balanceLedger = Array.isArray(db.balanceLedger) ? db.balanceLedger : [] @@ -234,85 +235,37 @@ export function DashboardPage({ db = {}, settings, ratesData }) { .sort((a, b) => a.paidUntil - b.paidUntil) .slice(0, 10) + const healthIssuesCount = inventoryIssues.reduce((n, i) => n + (i.count || 0), 0) + return ( <> -
- {inventoryIssues.length > 0 ? ( -
-
-
-

Здоровье инвентаря

-
-
-
- {inventoryIssues.map((issue) => ( -
- -
-
- {issue.title} - {issue.count} -
- {issue.hint ?
{issue.hint}
: null} -
- -
- ))} -
-
-
-
- ) : null} - -
-
-
-

Последние синхронизации

-
- - Аккаунты - -
-
-
- {recentSyncFeed.map((row) => { - const acc = providerAccounts.find((a) => a.id === row.accountId) - const line = formatSyncSummaryLine(row.summary) - return ( -
-
-
-
{acc?.name || row.accountId}
-
- {row.status === 'error' ? ( - {row.error || line} - ) : ( - line || 'OK' - )} -
-
- - {row.status === 'ok' ? 'OK' : 'Ошибка'} - -
-
- {row.finishedAt - ? new Date(row.finishedAt).toLocaleString('ru-RU') - : '—'} -
-
- ) - })} - {recentSyncFeed.length === 0 ? ( -
- Запустите синхронизацию на странице аккаунтов — здесь появится краткий итог -
+
    +
  • + +
  • +
  • +
-
-
+ + + + {dashTab === 'overview' ? ( +
@@ -372,6 +325,79 @@ export function DashboardPage({ db = {}, settings, ratesData }) {
+
+
+
+

Остатки по аккаунтам хостеров

+
+
+ + + + + + + + + + {accountBalances.map((item) => ( + + + + + + ))} + {accountBalances.length === 0 ? ( + + ) : null} + +
АккаунтВалютаБаланс
{item.name}{item.currency} + provider.id === item.providerId)} + settings={settings} + ratesData={ratesData} + /> +
+
+
+
+ +
+
+
+

Истекающая оплата (ближайшие {UPCOMING_DAYS} дней)

+
+
+ {upcoming.map(({ vps: item, paidUntil }) => { + const provider = providers.find((p) => p.id === item.providerId) + const account = providerAccounts.find((a) => a.id === item.providerAccountId) + return ( +
+
+
+
{item.dns || item.ip}
+
+ {provider?.name || '—'} / {account?.name || '—'} +
+
+
+ {paidUntil.toLocaleDateString('ru-RU')} +
+
+
+ ) + })} + {upcoming.length === 0 ? ( +
+ Нет VPS с истекающей оплатой в ближайшие {UPCOMING_DAYS} дней +
+ ) : null} +
+
+
+
@@ -463,80 +489,91 @@ export function DashboardPage({ db = {}, settings, ratesData }) {
+
+ ) : null} -
-
-
-

Остатки по аккаунтам хостеров

-
-
- - - - - - - - - - {accountBalances.map((item) => ( - - - - - - ))} - {accountBalances.length === 0 ? ( - - ) : null} - -
АккаунтВалютаБаланс
{item.name}{item.currency} - provider.id === item.providerId)} - settings={settings} - ratesData={ratesData} - /> -
+ {dashTab === 'health' ? ( +
+
+
0 ? 'border-warning' : ''}`}> +
+

Health Check

+
+
+ {inventoryIssues.length > 0 ? ( +
+ {inventoryIssues.map((issue) => ( +
+ +
+
+ {issue.title} + {issue.count} +
+ {issue.hint ?
{issue.hint}
: null} +
+ +
+ ))} +
+ ) : ( +
+ Замечаний по инвентарю нет. При появлении проблем они отобразятся здесь со ссылками на списки. +
+ )} +
-
-
-
-
-

Истекающая оплата (ближайшие {UPCOMING_DAYS} дней)

-
-
- {upcoming.map(({ vps: item, paidUntil }) => { - const provider = providers.find((p) => p.id === item.providerId) - const account = providerAccounts.find((a) => a.id === item.providerAccountId) - return ( -
-
-
-
{item.dns || item.ip}
-
- {provider?.name || '—'} / {account?.name || '—'} +
+
+
+

Последние синхронизации

+
+ + Аккаунты + +
+
+
+ {recentSyncFeed.map((row) => { + const acc = providerAccounts.find((a) => a.id === row.accountId) + const line = formatSyncSummaryLine(row.summary) + return ( +
+
+
+
{acc?.name || row.accountId}
+
+ {row.status === 'error' ? ( + {row.error || line} + ) : ( + line || 'OK' + )} +
+ + {row.status === 'ok' ? 'OK' : 'Ошибка'} +
-
- {paidUntil.toLocaleDateString('ru-RU')} +
+ {row.finishedAt + ? new Date(row.finishedAt).toLocaleString('ru-RU') + : '—'}
+ ) + })} + {recentSyncFeed.length === 0 ? ( +
+ Запустите синхронизацию на странице аккаунтов — здесь появится краткий итог
- ) - })} - {upcoming.length === 0 ? ( -
- Нет VPS с истекающей оплатой в ближайшие {UPCOMING_DAYS} дней -
- ) : null} + ) : null} +
-
+ ) : null} ) }