diff --git a/src/App.tsx b/src/App.tsx index f489fed..94ef3f5 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -13,6 +13,7 @@ import ProjectDetailPage from '@/pages/ProjectDetailPage' import MilestonesPage from '@/pages/MilestonesPage' import MilestoneDetailPage from '@/pages/MilestoneDetailPage' import NotificationsPage from '@/pages/NotificationsPage' +import MonitorPage from '@/pages/MonitorPage' import axios from 'axios' const WIZARD_PORT = Number(import.meta.env.VITE_WIZARD_PORT) || 18080 @@ -49,19 +50,28 @@ export default function App() { } if (appState === 'checking') { - return
检查配置状态...
+ return
Checking configuration status...
} if (appState === 'setup') { return } - if (loading) return
加载中...
+ if (loading) return
Loading...
if (!user) { return ( - +
+ +
+ + } /> + } /> + } /> + +
+
) } @@ -81,6 +91,7 @@ export default function App() { } /> } /> } /> + } /> } /> diff --git a/src/components/Sidebar.tsx b/src/components/Sidebar.tsx index 749d8bf..5999a9e 100644 --- a/src/components/Sidebar.tsx +++ b/src/components/Sidebar.tsx @@ -1,5 +1,5 @@ import { useState, useEffect } from 'react' -import { Link, useLocation } from 'react-router-dom' +import { Link, useLocation, useNavigate } from 'react-router-dom' import api from '@/services/api' import type { User } from '@/types' @@ -10,9 +10,14 @@ interface Props { export default function Sidebar({ user, onLogout }: Props) { const { pathname } = useLocation() + const navigate = useNavigate() const [unreadCount, setUnreadCount] = useState(0) useEffect(() => { + if (!user) { + setUnreadCount(0) + return + } api.get<{ count: number }>('/notifications/count') .then(({ data }) => setUnreadCount(data.count)) .catch(() => {}) @@ -22,14 +27,17 @@ export default function Sidebar({ user, onLogout }: Props) { .catch(() => {}) }, 30000) return () => clearInterval(timer) - }, []) + }, [user]) - const links = [ - { to: '/', icon: '📊', label: '仪表盘' }, + const links = user ? [ + { to: '/', icon: '📊', label: 'Dashboard' }, { to: '/issues', icon: '📋', label: 'Issues' }, - { to: '/projects', icon: '📁', label: '项目' }, - { to: '/milestones', icon: '🏁', label: '里程碑' }, - { to: '/notifications', icon: '🔔', label: `通知${unreadCount > 0 ? ` (${unreadCount})` : ''}` }, + { to: '/projects', icon: '📁', label: 'Projects' }, + { to: '/milestones', icon: '🏁', label: 'Milestones' }, + { to: '/notifications', icon: '🔔', label: 'Notifications' + (unreadCount > 0 ? ' (' + unreadCount + ')' : '') }, + { to: '/monitor', icon: '📡', label: 'Monitor' }, + ] : [ + { to: '/monitor', icon: '📡', label: 'Monitor' }, ] return ( @@ -44,12 +52,14 @@ export default function Sidebar({ user, onLogout }: Props) { ))} - {user && ( -
- 👤 {user.username} - -
- )} +
+ 👤 {user ? user.username : 'Guest'} + {user ? ( + + ) : ( + + )} +
) } diff --git a/src/index.css b/src/index.css index adc51c4..1b351bf 100644 --- a/src/index.css +++ b/src/index.css @@ -183,3 +183,21 @@ dd { font-size: .9rem; } .setup-done { text-align: center; } .setup-done h2 { color: var(--success); margin-bottom: 12px; } @keyframes fadeIn { from { opacity: 0; transform: translateY(8px); } to { opacity: 1; transform: none; } } + + +/* Monitor */ +.monitor-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(260px, 1fr)); gap: 16px; margin-top: 12px; } +.monitor-card { background: var(--bg-card); border: 1px solid var(--border); border-radius: 8px; padding: 16px; } +.monitor-card-header { display: flex; justify-content: space-between; align-items: flex-start; margin-bottom: 8px; } +.monitor-metrics { margin: 8px 0; font-size: .9rem; } +.monitor-admin { display: grid; grid-template-columns: repeat(auto-fit, minmax(320px, 1fr)); gap: 16px; } + +.status-ok { background: var(--success); } +.status-error { background: var(--danger); } +.status-pending { background: var(--warning); } +.status-online { background: var(--success); } +.status-offline { background: var(--danger); } + +.btn-secondary { background: none; border: 1px solid var(--border); color: var(--text); padding: 6px 12px; border-radius: 6px; cursor: pointer; } +.btn-danger { background: var(--danger); color: #fff; border: none; padding: 6px 12px; border-radius: 6px; cursor: pointer; } +.btn-danger:hover { opacity: .9; } diff --git a/src/pages/CreateIssuePage.tsx b/src/pages/CreateIssuePage.tsx index 86a175d..4f0cc0f 100644 --- a/src/pages/CreateIssuePage.tsx +++ b/src/pages/CreateIssuePage.tsx @@ -27,16 +27,16 @@ export default function CreateIssuePage() { return (
-

新建 Issue

+

Create Issue

- -