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/MonitorPage.tsx b/src/pages/MonitorPage.tsx index b739ab2..8c00785 100644 --- a/src/pages/MonitorPage.tsx +++ b/src/pages/MonitorPage.tsx @@ -11,6 +11,8 @@ interface ProviderRow { fetched_at?: string | null reset_at?: string | null window?: string | null + used?: number | null + limit?: number | null } interface ServerRow { @@ -144,102 +146,139 @@ export default function MonitorPage() { const createChallenge = async (id: number) => { const r = await api.post<{ identifier: string; challenge_uuid: string; expires_at: string }>('/monitor/admin/servers/' + id + '/challenge') - alert('identifier=' + r.data.identifier + '\nchallenge_uuid=' + r.data.challenge_uuid + '\nexpires_at=' + r.data.expires_at) + alert('identifier=' + r.data.identifier + ' | challenge_uuid=' + r.data.challenge_uuid + ' | expires_at=' + r.data.expires_at) } - if (loading) return
Monitor loading...
- if (!data) return
Monitor load failed
+ if (loading) return
Monitor loading...
+ if (!data) return
Monitor load failed
return ( -
+

📡 Monitor

-
-

Issue 概览(24小时窗口)

-
    -
  • 所有项目总 Issue:{data.issues.total_issues}
  • -
  • 24小时新增:{data.issues.new_issues_24h}
  • -
  • 24小时已处理(resolved/closed):{data.issues.processed_issues_24h}
  • -
-
+
+
+ {data.issues.total_issues} + 总 Issues +
+
+ {data.issues.new_issues_24h} + 24小时新增 +
+
+ {data.issues.processed_issues_24h} + 24小时已处理 +
+
-
-

Provider Usage

- {data.providers.length === 0 ?

暂无 provider 账号

: ( -
    - {data.providers.map((p) => ( -
  • - {p.provider} / {p.label} · status: {p.status} - {p.usage_pct !== null ? (' · usage: ' + p.usage_pct + '%') : ''} - {p.reset_at ? (' · reset: ' + p.reset_at) : ''} - {p.window ? (' · window: ' + p.window) : ''} - {p.fetched_at ? (' · updated: ' + p.fetched_at) : ''} - {p.error ? (' · error: ' + p.error) : ''} -
  • - ))} -
+
+
+

Provider Usage

+ 更新于 {data.generated_at} +
+ {data.providers.length === 0 ?

暂无 provider 账号

: ( + + + + + + + + + + + + + + {data.providers.map((p) => ( + + + + + + + + + + ))} + +
ProviderLabelUsageWindowResetStatusUpdated
{p.provider}{p.label}{p.usage_pct !== null ? p.usage_pct + '%' : '-'}{p.window || '-'}{p.reset_at || '-'}{p.status}{p.fetched_at || '-'}
)} -
+
-
+

服务器监测

- {data.servers.length === 0 ?

暂无监测服务器

: ( -
+ {data.servers.length === 0 ?

暂无监测服务器

: ( +
{data.servers.map((s) => ( -
-
- {s.display_name} ({s.identifier}) · {s.online ? '🟢 在线' : '🔴 离线'} +
+
+
+ {s.display_name} +
{s.identifier}
+
+ {s.online ? 'online' : 'offline'}
-
- CPU: {s.cpu_pct ?? '-'}% · MEM: {s.mem_pct ?? '-'}% · DISK: {s.disk_pct ?? '-'}% · SWAP: {s.swap_pct ?? '-'}% +
+ CPU {s.cpu_pct ?? '-'}% · MEM {s.mem_pct ?? '-'}% · DISK {s.disk_pct ?? '-'}% · SWAP {s.swap_pct ?? '-'}%
-
OpenClaw: {s.openclaw_version || '-'}
-
Agents: {s.agents?.length || 0}
+
OpenClaw: {s.openclaw_version || '-'}
+
Agents: {s.agents?.length || 0}
))}
)} -
+
{canAdmin && ( -
-

Admin: Provider 管理

-
- - setProviderForm({ ...providerForm, label: e.target.value })} /> - setProviderForm({ ...providerForm, credential: e.target.value })} /> - - -
- {providerTestMsg &&

{providerTestMsg}

} - +
+

Admin 管理

-

Admin: 服务器管理

-
- setServerForm({ ...serverForm, identifier: e.target.value })} /> - setServerForm({ ...serverForm, display_name: e.target.value })} /> - +
+
+

Provider 账号

+
+ + setProviderForm({ ...providerForm, label: e.target.value })} /> + setProviderForm({ ...providerForm, credential: e.target.value })} /> + + +
+ {providerTestMsg &&

{providerTestMsg}

} +
    + {providerAccounts.map((p) => ( +
  • {p.provider} / {p.label} / {p.credential_masked}
  • + ))} +
+
+ +
+

服务器

+
+ setServerForm({ ...serverForm, identifier: e.target.value })} /> + setServerForm({ ...serverForm, display_name: e.target.value })} /> + +
+
    + {servers.map((s) => ( +
  • + {s.display_name} ({s.identifier}) + + +
  • + ))} +
+
-
    - {servers.map((s) => ( -
  • - {s.display_name} ({s.identifier}) - - -
  • - ))} -
-
+ )} )