fix(web): I3 approve/reject API + I4 SIGNOZ_URL env + I5 ErrorsPanel nothing-gray
Some checks failed
CD Pipeline / build-and-deploy (push) Has been cancelled

- I3: Approve/Reject 按鈕串接 /api/v1/approvals/{id}/sign|reject
- I4: ApmPanel SIGNOZ_URL 改用 NEXT_PUBLIC_SIGNOZ_URL 環境變數
- I5: ErrorsPanel 外框改用 nothing-gray 調色盤 inline style

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
OG T
2026-04-09 11:20:44 +08:00
parent 28d2ff704e
commit 4a94588766
3 changed files with 26 additions and 12 deletions

View File

@@ -80,8 +80,22 @@ function AlertsAndApprovalsTab() {
<div style={{ fontSize: 12, fontWeight: 600, color: '#cc2200' }}>{ap.action || ap.title || '--'}</div>
<div style={{ fontSize: 10, color: '#555550', marginTop: 2, fontFamily: "'JetBrains Mono', monospace" }}>{ap.resource || '--'}</div>
<div style={{ display: 'flex', gap: 6, marginTop: 6 }}>
<button style={{ flex: 1, padding: '5px 0', border: 'none', borderRadius: 5, fontSize: 11, fontWeight: 600, cursor: 'pointer', background: '#22C55E', color: '#fff' }}>{t('approve')}</button>
<button style={{ flex: 1, padding: '5px 0', border: '0.5px solid #e0ddd4', borderRadius: 5, fontSize: 11, cursor: 'pointer', background: '#fff', color: '#87867f' }}>{t('reject')}</button>
<button
onClick={() => {
fetch(`${API_BASE}/api/v1/approvals/${ap.id}/sign`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ signer: 'web-ui' }) })
.then(() => setApprovals(prev => prev.filter(x => x.id !== ap.id)))
.catch(() => {})
}}
style={{ flex: 1, padding: '5px 0', border: 'none', borderRadius: 5, fontSize: 11, fontWeight: 600, cursor: 'pointer', background: '#22C55E', color: '#fff' }}
>{t('approve')}</button>
<button
onClick={() => {
fetch(`${API_BASE}/api/v1/approvals/${ap.id}/reject`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ reason: 'rejected-from-web' }) })
.then(() => setApprovals(prev => prev.filter(x => x.id !== ap.id)))
.catch(() => {})
}}
style={{ flex: 1, padding: '5px 0', border: '0.5px solid #e0ddd4', borderRadius: 5, fontSize: 11, cursor: 'pointer', background: '#fff', color: '#87867f' }}
>{t('reject')}</button>
</div>
</div>
))}

View File

@@ -10,7 +10,7 @@ import { useTranslations } from 'next-intl'
import { TimeSeriesChart } from '@/components/charts/time-series-chart'
const API_BASE = process.env.NEXT_PUBLIC_API_URL ?? ''
const SIGNOZ_URL = 'http://192.168.0.188:3301'
const SIGNOZ_URL = process.env.NEXT_PUBLIC_SIGNOZ_URL ?? '/signoz'
interface GoldMetricItem {
label: string; value: number | string; unit: string | null; trend: number[]; status: string

View File

@@ -27,21 +27,21 @@ export function ErrorsPanel() {
}
return (
<div className="p-6 max-w-7xl mx-auto">
<div className="flex items-center justify-between mb-6">
<div className="flex items-center gap-3">
<Bug className="h-6 w-6 text-gray-700" />
<div style={{ padding: 24, maxWidth: 1280, margin: '0 auto' }}>
<div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', marginBottom: 24 }}>
<div style={{ display: 'flex', alignItems: 'center', gap: 12 }}>
<Bug style={{ width: 24, height: 24, color: '#555550' }} />
<div>
<h1 className="text-xl font-semibold text-gray-900">{t('title')}</h1>
<p className="text-sm text-gray-500">{t('subtitle')}</p>
<h1 style={{ fontSize: 18, fontWeight: 700, color: '#141413', margin: 0 }}>{t('title')}</h1>
<p style={{ fontSize: 12, color: '#87867f', margin: '4px 0 0' }}>{t('subtitle')}</p>
</div>
</div>
<button onClick={refetch} disabled={loading} className="flex items-center gap-1.5 px-3 py-1.5 text-sm bg-gray-100 hover:bg-gray-200 rounded transition-colors disabled:opacity-50 disabled:cursor-not-allowed">
<button onClick={refetch} disabled={loading} style={{ display: 'flex', alignItems: 'center', gap: 6, padding: '6px 12px', fontSize: 13, background: '#f0efe8', border: '0.5px solid #e0ddd4', borderRadius: 6, cursor: loading ? 'not-allowed' : 'pointer', opacity: loading ? 0.5 : 1 }}>
<RefreshCw className={`h-4 w-4 ${loading ? 'animate-spin' : ''}`} />
{loading ? t('loading') : t('refresh')}
</button>
</div>
{error && <div className="mb-6 p-4 bg-red-50 border border-red-200 rounded-sm"><p className="text-sm text-red-700">{error}</p></div>}
{error && <div style={{ marginBottom: 24, padding: 16, background: 'rgba(204,34,0,0.05)', border: '0.5px solid rgba(204,34,0,0.2)', borderRadius: 8 }}><p style={{ fontSize: 13, color: '#cc2200' }}>{error}</p></div>}
<div className="grid grid-cols-1 lg:grid-cols-3 gap-6">
<div className="lg:col-span-1 space-y-6">
<ErrorOverviewCard stats={stats} loading={loading} changePercent={trends?.change_percent} />
@@ -52,7 +52,7 @@ export function ErrorsPanel() {
<RecentIssuesList issues={issues} loading={loading} onIssueClick={handleIssueClick} />
</div>
</div>
<div className="mt-6 pt-4 border-t border-gray-100"><p className="text-xs text-gray-400 text-center">{t('footerInfo')}</p></div>
<div style={{ marginTop: 24, paddingTop: 16, borderTop: '0.5px solid #e0ddd4' }}><p style={{ fontSize: 11, color: '#b0ad9f', textAlign: 'center' }}>{t('footerInfo')}</p></div>
</div>
)
}