diff --git a/apps/web/src/app/[locale]/action-logs/page.tsx b/apps/web/src/app/[locale]/action-logs/page.tsx index 09f247308..ea7fca0b4 100644 --- a/apps/web/src/app/[locale]/action-logs/page.tsx +++ b/apps/web/src/app/[locale]/action-logs/page.tsx @@ -139,12 +139,12 @@ function StatCard({ />
+
{label}
{value}
{subValue && ( -+
{subValue}
)} @@ -349,7 +349,7 @@ export default function ActionLogPage({+
{t('actionLog.noLogs')}
| + | {t('actionLog.columns.time')} | -+ | {t('actionLog.columns.operation')} | -+ | {t('actionLog.columns.target')} | -+ | {t('actionLog.columns.namespace')} | -+ | {t('actionLog.columns.status')} | -+ | {t('actionLog.columns.duration')} | -+ | {t('actionLog.columns.executor')} | + | {formatDate(log.created_at)} | - | + | {log.target_resource} | -+ | {log.namespace} |
{log.success ? (
|
- + | {formatDuration(log.execution_duration_ms)} | -+ | {log.executed_by} | @@ -497,7 +497,7 @@ export default function ActionLogPage({ {/* Pagination */} {totalPages > 1 && (
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| + | {h} | ))} @@ -230,25 +230,25 @@ export default function MonitoringPage({ params }: { params: { locale: string } 'border-b border-nothing-gray-100 last:border-0', i % 2 === 0 ? 'bg-white' : 'bg-nothing-gray-50/50' )}> -+ | {svc.name} | {STATUS_ICON[svc.status]} {svc.status} | -+ | {svc.latency_ms != null ? `${svc.latency_ms}ms` : '--'} | -+ | {svc.uptime_pct != null ? `${svc.uptime_pct.toFixed(2)}%` : '--'} | -+ |
{svc.last_checked
? new Date(svc.last_checked).toLocaleTimeString()
: '--'}
diff --git a/apps/web/src/app/[locale]/settings/page.tsx b/apps/web/src/app/[locale]/settings/page.tsx
index 2e7eab49b..7e2cffa6b 100644
--- a/apps/web/src/app/[locale]/settings/page.tsx
+++ b/apps/web/src/app/[locale]/settings/page.tsx
@@ -42,7 +42,7 @@ function SettingRow({
{label} - {description &&{description} } + {description &&{description} }{children}
- {t('appearanceSettings')}+{t('appearanceSettings')}
@@ -163,7 +163,7 @@ export default function SettingsPage({ params }: { params: { locale: string } })
{/* Language */}
{activeSection === 'language' && (
-
@@ -191,7 +191,7 @@ export default function SettingsPage({ params }: { params: { locale: string } })
{/* Notifications */}
{activeSection === 'notify' && (
{t('languageSettings')}+{t('languageSettings')}{[ { code: 'zh-TW', labelKey: 'zhTW', subKey: 'zhTWSub' }, { code: 'en', labelKey: 'en', subKey: 'enSub' }, @@ -180,7 +180,7 @@ export default function SettingsPage({ params }: { params: { locale: string } }) >{t(lang.labelKey)} -{t(lang.subKey)} +{t(lang.subKey)}
-
)}
@@ -207,7 +207,7 @@ export default function SettingsPage({ params }: { params: { locale: string } })
{/* System */}
{activeSection === 'system' && (
{t('notifySettings')}+{t('notifySettings')}
-
@@ -226,12 +226,12 @@ export default function SettingsPage({ params }: { params: { locale: string } })
{t('systemSettings')}+{t('systemSettings')}{[ { labelKey: 'frontendVersion', value: 'v1.0.0' }, { labelKey: 'apiEndpoint', value: process.env.NEXT_PUBLIC_API_URL ?? t('notConfigured') }, @@ -215,7 +215,7 @@ export default function SettingsPage({ params }: { params: { locale: string } }) { labelKey: 'phase', value: 'Phase 23 (2026-04-01)' }, ].map(item => (
{saved && (
-
+
-
+
{t('signatures')}
@@ -193,40 +193,40 @@ export function ApprovalCard({
{/* Blast Radius Section */}
-
+
-
+
{tBlast('affectedPods')}
-
+
{/* Estimated Downtime */}
{request.blastRadius?.affectedPods ?? 0}
-
+
{tBlast('estimatedDowntime')}
-
+
{/* Related Services */}
{request.blastRadius?.estimatedDowntime ?? '0'}
-
+
{tBlast('relatedServices')}
{(request.blastRadius?.relatedServices ?? []).map((service) => (
{service}
@@ -236,10 +236,10 @@ export function ApprovalCard({
{/* Data Impact */}
-
+
{tBlast('dataImpact')}
-
+
@@ -251,7 +251,7 @@ export function ApprovalCard({
{/* Dry-Run Checks */}
{dataImpactLabel}
-
{check.message && (
-
+
{check.message}
)}
@@ -291,7 +291,7 @@ export function ApprovalCard({
{/* Footer: Meta + Actions */}
+ |
+
{t('stream')}
-+
{status === 'streaming' ? ( ● LIVE ) : ( diff --git a/apps/web/src/components/agent/thinking-terminal.tsx b/apps/web/src/components/agent/thinking-terminal.tsx index dc7a9a49f..7ed3cfb05 100644 --- a/apps/web/src/components/agent/thinking-terminal.tsx +++ b/apps/web/src/components/agent/thinking-terminal.tsx @@ -59,7 +59,7 @@ function DependencyPathVisualizer({
+
{t('stream')}
-+
{t('events', { count: thinkingStream.length })}
+
{tApproval('noApprovals')}
+
[SYS] All clear. Awaiting alerts...
@@ -356,7 +356,7 @@ export function HITLSection({ locale: _locale, className }: HITLSectionProps) { {/* Phase 3: Permission Warning Badge */} {!hasPermission && ( -+
此操作需要更高權限簽核
-+
您的角色: {currentUserRole.toUpperCase()}
{/* Required Roles */}+
需要以下角色之一
+
{t('ai.standby')}
-+
{lastFetch ? `Last check: ${lastFetch.toLocaleTimeString()}` : 'Waiting for first fetch...'} @@ -544,7 +544,7 @@ export function OpenClawStateMachine({ {/* Demo mode warning */} {demoMode && (
+
Demo mode is enabled. Real API polling is disabled.
+
{request.action.split('|')[1].trim()}
)}
@@ -504,7 +504,7 @@ export function ApprovalCard({
{/* Blast Radius - 可折疊面板 */}
-
+
{tBlast('title')}
{/* 摘要預覽 */}
@@ -528,14 +528,14 @@ export function ApprovalCard({
/>
-
+
{tBlast('relatedServices')}
{(request.blastRadius.relatedServices ?? []).map((svc) => (
{svc}
@@ -552,7 +552,7 @@ export function ApprovalCard({
-
+
{tBlast('dataImpact')}: {dataImpactLabel}
@@ -562,12 +562,12 @@ export function ApprovalCard({
{/* Dry-Run Checks - 可折疊面板 (預設收合) */}
-
+
{tDryRun('validation')}
{/* 通過/失敗摘要 */}
)}
-
+
{check.name}
{check.message && (
{/* Meta */}
-
+
{t('requestedBy')}
{request.requestedBy}
|
@@ -636,7 +636,7 @@ export function ApprovalCard({
-
+
正在處理中...
@@ -646,7 +646,7 @@ export function ApprovalCard({
{/* 唯讀模式 - 不顯示按鈕 */}
{readOnly ? (
-
+
此紀錄為歷史存檔,僅供稽核參考
@@ -657,7 +657,7 @@ export function ApprovalCard({
-
+
{t('waitingSecondSig')}
@@ -673,7 +673,7 @@ export function ApprovalCard({
disabled={isLoading || isProcessing}
className={cn(
'flex-1 flex items-center justify-center gap-2',
- 'px-6 py-3.5 rounded-xl font-mono text-sm font-semibold',
+ 'px-6 py-3.5 rounded-xl font-body text-sm font-semibold',
'bg-nothing-gray-50 border-2 border-nothing-gray-200 text-nothing-gray-600',
'hover:border-nothing-gray-300 hover:bg-nothing-gray-100 hover:text-nothing-gray-800',
'active:scale-[0.97]',
@@ -707,7 +707,7 @@ export function ApprovalCard({
{/* Long Press Hint - Subtle */}
-
+
{t('holdHint', {
seconds: holdSeconds,
action: hasPartialSignatures ? t('actionSign') : isDestructive ? t('actionConfirm') : t('actionApprove')
@@ -740,9 +740,9 @@ function MetricBox({ label, value, className, highlight = false }: MetricBoxProp
highlight ? 'border-status-warning/30' : 'border-nothing-gray-200',
className
)}>
-
{label}
+ {label}
{value}
diff --git a/apps/web/src/components/approval/approval-thread-item.tsx b/apps/web/src/components/approval/approval-thread-item.tsx
index 6898498d5..02084872f 100644
--- a/apps/web/src/components/approval/approval-thread-item.tsx
+++ b/apps/web/src/components/approval/approval-thread-item.tsx
@@ -143,14 +143,14 @@ export function ApprovalThreadItem({
{/* 頂部: 風險指示器 + 時間 */}
{approval.riskLevel}
-
+
{relativeTime}
@@ -167,7 +167,7 @@ export function ApprovalThreadItem({
{/* 底部: 動作類型 + 狀態指示 */}
-
+
{actionSummary}
{tBatch('title')}
-
+
{stats.total} {t('pendingApprovals')}
@@ -192,25 +192,25 @@ export function BatchModeSelector({
-
+
LOW: {stats.low}
-
+
MED: {stats.medium}
-
+
HIGH: {stats.high}
-
+
CRIT: {stats.critical}
@@ -241,7 +241,7 @@ export function BatchModeSelector({
{tBatch('bulkApprove')}
-
+
{stats.canBulkApprove} {tBatch('eligible')}
@@ -263,7 +263,7 @@ export function BatchModeSelector({
{tBatch('sequential')}
-
+
{stats.total} {tBatch('items')}
@@ -287,7 +287,7 @@ export function BatchModeSelector({
{tBatch('criticalOnly')}
-
+
{stats.critical} {tBatch('items')}
diff --git a/apps/web/src/components/approval/compact-approval-item.tsx b/apps/web/src/components/approval/compact-approval-item.tsx
index 26af6ea94..fd3c95bcb 100644
--- a/apps/web/src/components/approval/compact-approval-item.tsx
+++ b/apps/web/src/components/approval/compact-approval-item.tsx
@@ -109,14 +109,14 @@ export function CompactApprovalItem({
{/* 標題與摘要 */}
-
+
{title}
{tRisk(request.riskLevel)}
-
+
{request.currentSignatures}/{request.requiredSignatures}
diff --git a/apps/web/src/components/approval/conversational-view.tsx b/apps/web/src/components/approval/conversational-view.tsx
index 209da89dd..28cd7beba 100644
--- a/apps/web/src/components/approval/conversational-view.tsx
+++ b/apps/web/src/components/approval/conversational-view.tsx
@@ -236,7 +236,7 @@ export function ConversationalView({
{/* SSE 連線狀態 */}
1 && (
-
+
{selectedIndex + 1} / {approvals.length}
@@ -302,7 +302,7 @@ export function ConversationalView({
{approvals.length === 0 ? (
- {t('noPendingApprovals')}
+ {t('noPendingApprovals')}
) : (
approvals.map((approval) => (
@@ -353,7 +353,7 @@ export function ConversationalView({
{/* 分頁指示器 */}
-
+
{selectedIndex + 1} / {approvals.length}
{/* 快速導航按鈕 */}
@@ -411,7 +411,7 @@ export function ConversationalView({
- {t('selectApproval')}
+ {t('selectApproval')}
)}
@@ -439,7 +439,7 @@ export function ConversationalView({
-
+
{t('holdToApproveHint')}
@@ -469,7 +469,7 @@ function ShortcutRow({
{t('pendingApprovals')}
-
+
{approvals.length}
@@ -254,14 +254,14 @@ export function LiveApprovalPanel({
{/* Error State */}
{error && (
- {t('fetchError')}: {error}
+ {t('fetchError')}: {error}
)}
{/* Phase 20: CSRF Error State */}
{csrfError && (
-
+
⚠️ CSRF Token 載入失敗,簽核功能暫時無法使用
@@ -270,7 +270,7 @@ export function LiveApprovalPanel({
{/* Phase 20: CSRF Loading State */}
{csrfLoading && (
-
+
🔐 正在載入安全憑證...
@@ -282,7 +282,7 @@ export function LiveApprovalPanel({
- {t('noApprovals')}
+ {t('noApprovals')}
@@ -291,11 +291,11 @@ export function LiveApprovalPanel({
{/* Current User Role Display (Phase 3 Demo) */}
-
+
登入身份: {currentUser.name}
+
需要 {getRequiredRolesDisplay(approval.riskLevel)}
@@ -356,7 +356,7 @@ export function LiveApprovalPanel({
-
+
{t('signSuccess')}
@@ -368,7 +368,7 @@ export function LiveApprovalPanel({
-
+
{tCommon('error')}
@@ -394,20 +394,20 @@ export function LiveApprovalPanel({
value={rejectReason}
onChange={(e) => setRejectReason(e.target.value)}
placeholder={t('enterReason')}
- className="w-full h-32 px-4 py-3 rounded-lg border border-nothing-gray-200 bg-white/50 resize-none font-mono text-sm focus:outline-none focus:ring-2 focus:ring-status-critical/50"
+ className="w-full h-32 px-4 py-3 rounded-lg border border-nothing-gray-200 bg-white/50 resize-none font-body text-sm focus:outline-none focus:ring-2 focus:ring-status-critical/50"
autoFocus
/>
setRejectModalId(null)}
- className="flex-1 px-6 py-3 rounded-lg border border-nothing-gray-300 text-nothing-gray-600 font-mono text-sm hover:bg-nothing-gray-100 transition-colors"
+ className="flex-1 px-6 py-3 rounded-lg border border-nothing-gray-300 text-nothing-gray-600 font-body text-sm hover:bg-nothing-gray-100 transition-colors"
>
{tCommon('cancel')}
{t('reject')}
@@ -438,29 +438,29 @@ export function LiveApprovalPanel({
{/* Risk Level Badge */}
-
+
{accessDeniedModal.riskLevel} RISK
{/* Message */}
-
+
此操作需要更高權限簽核
-
+
您的角色: {currentUser.role.toUpperCase()}
{/* Required Roles */}
-
+
需要以下角色之一
{accessDeniedModal.requiredRoles.split(' / ').map((role) => (
{role}
@@ -471,7 +471,7 @@ export function LiveApprovalPanel({
{/* Action Button */}
setAccessDeniedModal(null)}
- className="w-full px-6 py-3 rounded-xl font-mono text-sm font-semibold bg-nothing-gray-100 text-nothing-gray-700 hover:bg-nothing-gray-200 transition-colors"
+ className="w-full px-6 py-3 rounded-xl font-body text-sm font-semibold bg-nothing-gray-100 text-nothing-gray-700 hover:bg-nothing-gray-200 transition-colors"
>
了解,返回
diff --git a/apps/web/src/components/charts/ai-process-stepper.tsx b/apps/web/src/components/charts/ai-process-stepper.tsx
index 573d9e595..814978715 100644
--- a/apps/web/src/components/charts/ai-process-stepper.tsx
+++ b/apps/web/src/components/charts/ai-process-stepper.tsx
@@ -155,7 +155,7 @@ function Step({ step, index, isLast }: StepProps) {
diff --git a/apps/web/src/components/charts/global-pulse-chart.tsx b/apps/web/src/components/charts/global-pulse-chart.tsx
index 3bd4113a2..c43073ed5 100644
--- a/apps/web/src/components/charts/global-pulse-chart.tsx
+++ b/apps/web/src/components/charts/global-pulse-chart.tsx
@@ -139,7 +139,7 @@ function MetricCard({ metric }: MetricCardProps) {
{metric.value}
{metric.unit && (
-
+
{metric.unit}
)}
diff --git a/apps/web/src/components/charts/time-series-chart.tsx b/apps/web/src/components/charts/time-series-chart.tsx
index 7d8662d5d..3ceeb0302 100644
--- a/apps/web/src/components/charts/time-series-chart.tsx
+++ b/apps/web/src/components/charts/time-series-chart.tsx
@@ -98,7 +98,7 @@ function CustomTooltip({ active, payload, unit }: CustomTooltipProps) {
return (
{time}
-
+
{data.value.toFixed(2)}{unit && ` ${unit}`}
diff --git a/apps/web/src/components/cyber/data-pincer-card.tsx b/apps/web/src/components/cyber/data-pincer-card.tsx
index f479fd89e..d919a501c 100644
--- a/apps/web/src/components/cyber/data-pincer-card.tsx
+++ b/apps/web/src/components/cyber/data-pincer-card.tsx
@@ -93,7 +93,7 @@ export function DataPincerCard({
{/* 標題 (如有) */}
{title && (
-
+
{title}
diff --git a/apps/web/src/components/dashboard/connection-status.tsx b/apps/web/src/components/dashboard/connection-status.tsx
index 0338c1fa0..19717a92e 100644
--- a/apps/web/src/components/dashboard/connection-status.tsx
+++ b/apps/web/src/components/dashboard/connection-status.tsx
@@ -90,11 +90,11 @@ export function ConnectionStatus({
{showLabel && (
-
+
{t(labelKey)}
{showLastUpdate && lastUpdate && (
-
+
{lastUpdateStr}
)}
@@ -102,7 +102,7 @@ export function ConnectionStatus({
)}
{mockMode && (
-
+
{t('mockMode')}
)}
@@ -127,7 +127,7 @@ export function ConnectionStatusCompact({ className }: { className?: string }) {
)}
>
-
+
{t(connectionLabelKeys[connectionStatus])}
diff --git a/apps/web/src/components/dashboard/host-card.tsx b/apps/web/src/components/dashboard/host-card.tsx
index dafed01cb..586d46219 100644
--- a/apps/web/src/components/dashboard/host-card.tsx
+++ b/apps/web/src/components/dashboard/host-card.tsx
@@ -113,7 +113,7 @@ export function HostCard({
-
+
{ip}
@@ -140,18 +140,18 @@ export function HostCard({
>
-
+
{service.name}
{service.port && (
-
+
:{service.port}
)}
{service.latencyMs !== null && service.latencyMs !== undefined && (
-
+
{service.latencyMs.toFixed(1)}ms
)}
@@ -168,7 +168,7 @@ export function HostCard({
{tDashboard('cpu')}
-
+
{formatPercent(metrics.cpuPercent)}
@@ -191,7 +191,7 @@ export function HostCard({
{tDashboard('memory')}
-
+
{formatPercent(metrics.memoryPercent)}
@@ -218,7 +218,7 @@ export function HostCard({
-
+
{new Date().toLocaleTimeString('zh-TW', {
hour: '2-digit',
minute: '2-digit',
diff --git a/apps/web/src/components/dashboard/live-dashboard.tsx b/apps/web/src/components/dashboard/live-dashboard.tsx
index eafec884f..89c1d071e 100644
--- a/apps/web/src/components/dashboard/live-dashboard.tsx
+++ b/apps/web/src/components/dashboard/live-dashboard.tsx
@@ -225,12 +225,12 @@ function OpenClawPanel() {
{t('name')}
-
+
{t('monitoring')}
- v5.0.0
+ v5.0.0
@@ -243,7 +243,7 @@ function OpenClawPanel() {
-
+
{tCommon('loading')} {ip}
@@ -126,7 +126,7 @@ export function LiveHostCard({
-
+
{ip}
@@ -137,7 +137,7 @@ export function LiveHostCard({
{fallbackData.services.map((service) => (
-
+
{service.name}
@@ -197,7 +197,7 @@ export function LiveHostCard({
{getRoleIcon(host.role || '')}
-
+
{host.ip}
@@ -210,7 +210,7 @@ export function LiveHostCard({
{host.name}
{host.role && (
-
+
{host.role.replace('_', ' ')}
)}
@@ -226,20 +226,20 @@ export function LiveHostCard({
>
-
+
{service.name}
{service.port && (
-
+
:{service.port}
)}
{service.latency_ms !== null && service.latency_ms !== undefined && (
100
? 'text-status-warning'
: 'text-nothing-gray-500'
@@ -287,7 +287,7 @@ export function LiveHostCard({
-
+
{new Date(host.last_check).toLocaleTimeString('zh-TW', {
hour: '2-digit',
minute: '2-digit',
@@ -330,8 +330,8 @@ function MetricBar({
return (
- {label}
-
+ {label}
+
{collectingLabel}
@@ -372,12 +372,12 @@ function MetricBar({
) : (
)}
- {label}
+ {label}
= criticalThreshold
? 'text-status-critical'
: value >= warningThreshold
@@ -389,7 +389,7 @@ function MetricBar({
{/* Dynamic Baseline Display */}
{baselineValue !== null && baselineValue !== undefined && (
-
+
({formatPercent(baselineValue)})
)}
diff --git a/apps/web/src/components/genui/ApprovalCard.tsx b/apps/web/src/components/genui/ApprovalCard.tsx
index 546446e13..18d1669e5 100644
--- a/apps/web/src/components/genui/ApprovalCard.tsx
+++ b/apps/web/src/components/genui/ApprovalCard.tsx
@@ -84,7 +84,7 @@ export const ApprovalCard: React.FC = ({ data }) => {
Approval Required // {data.approvalId}
-
{data.riskLevel}
@@ -94,7 +94,7 @@ export const ApprovalCard: React.FC = ({ data }) => {
{/* Metadata */}
{(data.requestedBy || data.requestedAt) && (
-
+
{data.requestedBy && (
@@ -132,13 +132,13 @@ export const ApprovalCard: React.FC = ({ data }) => {
{/* Nuclear Key Authorization */}
{executionResult === 'success' ? (
-
+
✓
{t('executionAuthorized')}
{t('authorized')}
) : executionResult === 'error' ? (
-
+
✗
{t('executionFailed')}
@@ -158,7 +158,7 @@ export const ApprovalCard: React.FC = ({ data }) => {
}
const Label = ({ children }: { children: React.ReactNode }) => (
-
+
{children}
)
diff --git a/apps/web/src/components/genui/GenUIRenderer.tsx b/apps/web/src/components/genui/GenUIRenderer.tsx
index fac246434..b1258553e 100644
--- a/apps/web/src/components/genui/GenUIRenderer.tsx
+++ b/apps/web/src/components/genui/GenUIRenderer.tsx
@@ -127,7 +127,7 @@ const LoadingCard: React.FC<{ componentName: string }> = ({ componentName }) =>
-
+
Loading {componentName}...
@@ -139,8 +139,8 @@ const ErrorCard: React.FC<{ title: string; message: string }> = ({ title, messag
- {title}
- {message}
+ {title}
+ {message}
diff --git a/apps/web/src/components/genui/IncidentTimelineCard.tsx b/apps/web/src/components/genui/IncidentTimelineCard.tsx
index d8c33d0dc..ab632c66f 100644
--- a/apps/web/src/components/genui/IncidentTimelineCard.tsx
+++ b/apps/web/src/components/genui/IncidentTimelineCard.tsx
@@ -53,11 +53,11 @@ export const IncidentTimelineCard: React.FC = ({ data
{data.severity && (
-
+
{data.severity}
)}
-
+
{data.status}
@@ -67,18 +67,18 @@ export const IncidentTimelineCard: React.FC = ({ data
{data.events.map((event, i) => (
-
+
{event.timestamp}
-
{event.type}
- {event.message}
+ {event.message}
))}
diff --git a/apps/web/src/components/genui/K8sPodStatusCard.tsx b/apps/web/src/components/genui/K8sPodStatusCard.tsx
index a0bb99bba..78fbfe0c9 100644
--- a/apps/web/src/components/genui/K8sPodStatusCard.tsx
+++ b/apps/web/src/components/genui/K8sPodStatusCard.tsx
@@ -77,7 +77,7 @@ export const K8sPodStatusCard: React.FC = ({ data }) => {
K8s Pods // {data.namespace}
-
+
{summary.running}/{summary.total} RUNNING
@@ -87,7 +87,7 @@ export const K8sPodStatusCard: React.FC = ({ data }) => {
{data.pods.map((pod, i) => (
{statusIcon(pod.status)}
{pod.name}
diff --git a/apps/web/src/components/genui/MetricsSummaryCard.tsx b/apps/web/src/components/genui/MetricsSummaryCard.tsx
index 53d56d326..14f072175 100644
--- a/apps/web/src/components/genui/MetricsSummaryCard.tsx
+++ b/apps/web/src/components/genui/MetricsSummaryCard.tsx
@@ -55,7 +55,7 @@ export const MetricsSummaryCard: React.FC = ({ data })
SignOz Metrics // Real-time
-
+
{status}
@@ -93,26 +93,26 @@ export const MetricsSummaryCard: React.FC = ({ data })
{data.cpu !== undefined && (
- CPU:
+ CPU:
80 ? 'bg-red-500' : data.cpu > 60 ? 'bg-yellow-500' : 'bg-green-500'}`}
style={{ width: `${data.cpu}%` }}
/>
- {data.cpu}%
+ {data.cpu}%
)}
{data.memory !== undefined && (
- MEM:
+ MEM:
80 ? 'bg-red-500' : data.memory > 60 ? 'bg-yellow-500' : 'bg-green-500'}`}
style={{ width: `${data.memory}%` }}
/>
- {data.memory}%
+ {data.memory}%
)}
@@ -121,7 +121,7 @@ export const MetricsSummaryCard: React.FC = ({ data })
{/* Pods status */}
{data.pods && (
-
+
Pods: {data.pods.running}/{data.pods.total} running
@@ -141,7 +141,7 @@ const MetricBox: React.FC<{
{icon}
- {label}
+ {label}
{value}
diff --git a/apps/web/src/components/genui/NuclearKeyButton.tsx b/apps/web/src/components/genui/NuclearKeyButton.tsx
index b13e6a18b..0e489d28f 100644
--- a/apps/web/src/components/genui/NuclearKeyButton.tsx
+++ b/apps/web/src/components/genui/NuclearKeyButton.tsx
@@ -167,7 +167,7 @@ export const NuclearKeyButton: React.FC = ({
w-full py-4 px-6 rounded-sm border-2
bg-green-50 border-green-500
flex items-center justify-center gap-2
- font-mono font-bold text-green-700
+ font-body font-bold text-green-700
transition-all duration-300
`}>
@@ -218,7 +218,7 @@ export const NuclearKeyButton: React.FC = ({
className={`${config.textColor} ${isHolding ? 'animate-pulse' : ''} sm:w-5 sm:h-5`}
/>
-
+
{isHolding ? (
{label} ({Math.ceil((1 - progress) * (duration ?? 1500) / 1000)}s)
@@ -230,7 +230,7 @@ export const NuclearKeyButton: React.FC = ({
{/* Risk Badge */}
@@ -241,7 +241,7 @@ export const NuclearKeyButton: React.FC = ({
{/* Shortcut Hint - Hidden on mobile touch devices */}
{showShortcut && !disabled && (
-
+
{isHolding ? (
{t('keepHolding')}
@@ -271,7 +271,7 @@ export const NuclearKeyButton: React.FC = ({
{/* Critical Warning */}
{isCritical && !disabled && !isHolding && (
diff --git a/apps/web/src/components/genui/SentryErrorCard.tsx b/apps/web/src/components/genui/SentryErrorCard.tsx
index dd5d45809..33e2202c2 100644
--- a/apps/web/src/components/genui/SentryErrorCard.tsx
+++ b/apps/web/src/components/genui/SentryErrorCard.tsx
@@ -41,14 +41,14 @@ export const SentryErrorCard: React.FC = ({ data }) => {
Sentry // {data.errorId}
-
+
{level}
-
+
Error
@@ -56,7 +56,7 @@ export const SentryErrorCard: React.FC = ({ data }) => {
-
+
{data.count !== undefined && (
Count:{' '}
@@ -76,7 +76,7 @@ export const SentryErrorCard: React.FC = ({ data }) => {
href={data.url}
target="_blank"
rel="noopener noreferrer"
- className="inline-flex items-center gap-1 text-sm font-mono text-[#4A90D9] hover:underline"
+ className="inline-flex items-center gap-1 text-sm font-body text-[#4A90D9] hover:underline"
>
View in Sentry
diff --git a/apps/web/src/components/genui/TraceWaterfallCard.tsx b/apps/web/src/components/genui/TraceWaterfallCard.tsx
index 117dd80fe..212024d13 100644
--- a/apps/web/src/components/genui/TraceWaterfallCard.tsx
+++ b/apps/web/src/components/genui/TraceWaterfallCard.tsx
@@ -49,7 +49,7 @@ export const TraceWaterfallCard: React.FC = ({ data })
Trace // {data.traceId.slice(0, 16)}...
-
+
{data.duration}ms
@@ -58,7 +58,7 @@ export const TraceWaterfallCard: React.FC = ({ data })
{data.spans.map((span, i) => (
{/* Service name */}
-
+
{span.service}
@@ -74,7 +74,7 @@ export const TraceWaterfallCard: React.FC = ({ data })
}}
/>
= ({ data })
{/* Duration */}
-
+
{span.duration}ms
@@ -99,7 +99,7 @@ export const TraceWaterfallCard: React.FC = ({ data })
href={data.url}
target="_blank"
rel="noopener noreferrer"
- className="inline-flex items-center gap-1 text-sm font-mono text-[#4A90D9] hover:underline"
+ className="inline-flex items-center gap-1 text-sm font-body text-[#4A90D9] hover:underline"
>
View in SignOz
diff --git a/apps/web/src/components/incident/thinking-terminal.tsx b/apps/web/src/components/incident/thinking-terminal.tsx
index ab7d99149..0d6422381 100644
--- a/apps/web/src/components/incident/thinking-terminal.tsx
+++ b/apps/web/src/components/incident/thinking-terminal.tsx
@@ -8,7 +8,7 @@
*
* Nothing.tech 視覺規範:
* - 深色背景 (bg-black text-white) - 全站唯一深色區域
- * - 強制等寬字體 (font-mono)
+ * - 強制等寬字體 (font-body)
* - 打字機效果展示推論步驟
*
* 統帥鐵律: 禁止假數據!
@@ -168,7 +168,7 @@ export function ThinkingTerminal({
{/* Title */}
-
+
OpenClaw Terminal
@@ -177,7 +177,7 @@ export function ThinkingTerminal({
{/* Controls */}
{incidentId && (
-
+
{incidentId}
)}
@@ -214,7 +214,7 @@ export function ThinkingTerminal({
{isExpanded && (
{/* No Data State */}
@@ -291,10 +291,10 @@ export function ThinkingTerminal({
{/* Terminal Footer */}
-
+
{t('steps')}: {displayedSteps}/{totalSteps}
-
+
{isPlaying ? t('streaming') : t('paused')}
diff --git a/apps/web/src/components/layout/coming-soon.tsx b/apps/web/src/components/layout/coming-soon.tsx
index f8c26fdac..6a4fcbb83 100644
--- a/apps/web/src/components/layout/coming-soon.tsx
+++ b/apps/web/src/components/layout/coming-soon.tsx
@@ -30,11 +30,11 @@ export function ComingSoon({ icon: Icon, title, description, className }: Coming
)}
-
+
{title}
{description && (
-
+
{description}
)}
diff --git a/apps/web/src/components/layout/header.tsx b/apps/web/src/components/layout/header.tsx
index 92824373e..4194b740a 100644
--- a/apps/web/src/components/layout/header.tsx
+++ b/apps/web/src/components/layout/header.tsx
@@ -95,7 +95,7 @@ export function Header({
{pendingApprovals > 0 && (
-
+
{pendingApprovals} {tDashboard('pendingApprovals')}
@@ -105,13 +105,13 @@ export function Header({
{connectionLabel}
{mockMode && (
-
+
MOCK
)}
@@ -122,7 +122,7 @@ export function Header({
switchLocale('zh-TW')}
className={cn(
- 'px-3 py-1.5 rounded-md font-mono text-sm transition-all',
+ 'px-3 py-1.5 rounded-md font-body text-sm transition-all',
locale === 'zh-TW'
? 'bg-nothing-black text-white'
: 'text-nothing-gray-600 hover:text-nothing-black'
@@ -133,7 +133,7 @@ export function Header({
switchLocale('en')}
className={cn(
- 'px-3 py-1.5 rounded-md font-mono text-sm transition-all',
+ 'px-3 py-1.5 rounded-md font-body text-sm transition-all',
locale === 'en'
? 'bg-nothing-black text-white'
: 'text-nothing-gray-600 hover:text-nothing-black'
diff --git a/apps/web/src/components/layout/sidebar.tsx b/apps/web/src/components/layout/sidebar.tsx
index 4a7a9bca7..f36dfb821 100644
--- a/apps/web/src/components/layout/sidebar.tsx
+++ b/apps/web/src/components/layout/sidebar.tsx
@@ -323,7 +323,7 @@ export function Sidebar({
collapsed ? 'px-2 text-center' : 'px-4'
)}>
{!collapsed && (
-
+
v1.0.0
)}
diff --git a/apps/web/src/components/shared/auto-healing-error-boundary.tsx b/apps/web/src/components/shared/auto-healing-error-boundary.tsx
index ea5d87dce..93fc56303 100644
--- a/apps/web/src/components/shared/auto-healing-error-boundary.tsx
+++ b/apps/web/src/components/shared/auto-healing-error-boundary.tsx
@@ -90,12 +90,12 @@ class AutoHealingErrorBoundaryInner extends Component {
if (this.state.retryCount >= 3) {
return (
- {translations.systemFailure}
- {this.props.fallbackMessage || translations.criticalError}
- {translations.escalating}
+ {translations.systemFailure}
+ {this.props.fallbackMessage || translations.criticalError}
+ {translations.escalating}
window.location.reload()}
- className="px-6 py-2 bg-white text-black font-mono text-sm rounded-full hover:bg-gray-200 transition-colors"
+ className="px-6 py-2 bg-white text-black font-body text-sm rounded-full hover:bg-gray-200 transition-colors"
>
{translations.forceRestart}
@@ -105,8 +105,8 @@ class AutoHealingErrorBoundaryInner extends Component {
return (
- {translations.detectingAnomaly}
- {translations.autoHealingAttempt(this.state.retryCount + 1)}
+ {translations.detectingAnomaly}
+ {translations.autoHealingAttempt(this.state.retryCount + 1)}
diff --git a/apps/web/src/components/shared/language-switcher.tsx b/apps/web/src/components/shared/language-switcher.tsx
index 0d20a86bd..eb1c6f4ef 100644
--- a/apps/web/src/components/shared/language-switcher.tsx
+++ b/apps/web/src/components/shared/language-switcher.tsx
@@ -41,7 +41,7 @@ export function LanguageSwitcher({ className }: LanguageSwitcherProps) {
key={loc}
onClick={() => handleSwitch(loc)}
className={cn(
- 'px-3 py-1.5 rounded-sm font-mono text-xs transition-all duration-200',
+ 'px-3 py-1.5 rounded-sm font-body text-xs transition-all duration-200',
'focus:outline-none focus:ring-2 focus:ring-nothing-gray-400',
isActive
? 'bg-nothing-gray-900 text-nothing-white'
@@ -81,7 +81,7 @@ export function LanguageSwitcherCompact({ className }: LanguageSwitcherProps) {
className={cn(
'px-3 py-1.5 rounded-button',
'bg-nothing-gray-100 border border-nothing-gray-200',
- 'font-mono text-xs text-nothing-gray-600',
+ 'font-body text-xs text-nothing-gray-600',
'hover:text-nothing-gray-900 hover:bg-nothing-gray-200',
'transition-all duration-200',
'focus:outline-none focus:ring-2 focus:ring-nothing-gray-400',
diff --git a/apps/web/src/components/status-orb.tsx b/apps/web/src/components/status-orb.tsx
index e06ef2714..539dd3035 100644
--- a/apps/web/src/components/status-orb.tsx
+++ b/apps/web/src/components/status-orb.tsx
@@ -83,7 +83,7 @@ export function StatusOrb({ status, size = 'md', className }: StatusOrbProps) {
{/* Label */}
-
+
{label}
diff --git a/apps/web/src/components/terminal/OmniTerminal.tsx b/apps/web/src/components/terminal/OmniTerminal.tsx
index e25800eb8..c32a9cc7c 100644
--- a/apps/web/src/components/terminal/OmniTerminal.tsx
+++ b/apps/web/src/components/terminal/OmniTerminal.tsx
@@ -141,7 +141,7 @@ export const OmniTerminal = () => {
const result = msg.payload.result as Record | undefined
return (
-
+
[{tool ?? 'unknown'}]{' '}
{status ?? 'executing'}
{result && (
@@ -205,12 +205,12 @@ export const OmniTerminal = () => {
- {isConnected ? t('sseLive') : t('offline')}
+ {isConnected ? t('sseLive') : t('offline')}
[x]
diff --git a/apps/web/src/components/thinking-stream-test.tsx b/apps/web/src/components/thinking-stream-test.tsx
index fb512ff12..ac42f110d 100644
--- a/apps/web/src/components/thinking-stream-test.tsx
+++ b/apps/web/src/components/thinking-stream-test.tsx
@@ -128,7 +128,7 @@ export function ThinkingStreamTest() {
{/* Header - Nothing.tech 風格 */}
AWOOOI Terminal
-
+
v0.1.0 | SSE
@@ -138,7 +138,7 @@ export function ThinkingStreamTest() {
onClick={startStream}
disabled={isStreaming}
className={cn(
- 'w-full py-3 px-4 rounded-button font-mono text-sm transition-all border',
+ 'w-full py-3 px-4 rounded-button font-body text-sm transition-all border',
isStreaming
? 'bg-nothing-gray-800 text-nothing-gray-500 border-nothing-gray-700 cursor-not-allowed'
: 'bg-nothing-white text-nothing-black border-transparent hover:bg-nothing-gray-200'
@@ -150,7 +150,7 @@ export function ThinkingStreamTest() {
{/* Terminal Output */}
{thinkingStream.length === 0 && !isStreaming && (
-
+
{'>'} Waiting for command...
)}
@@ -159,7 +159,7 @@ export function ThinkingStreamTest() {
- {'>'}
+ {'>'}
)}
@@ -180,7 +180,7 @@ export function ThinkingStreamTest() {
{/* Connection Info */}
-
+
ENDPOINT: {API_BASE_URL}/agent/thinking
diff --git a/apps/web/src/components/timeline/action-timeline.tsx b/apps/web/src/components/timeline/action-timeline.tsx
index 2da1a6144..0867eccb3 100644
--- a/apps/web/src/components/timeline/action-timeline.tsx
+++ b/apps/web/src/components/timeline/action-timeline.tsx
@@ -135,7 +135,7 @@ function TimelineItem({ event, isLast, isNewest = false, isPulsingExec = false }
{/* Title */}
-
+
{event.title}
@@ -143,7 +143,7 @@ function TimelineItem({ event, isLast, isNewest = false, isPulsingExec = false }
{event.status === 'error' && event.description && (
!
-
+
{event.description}
@@ -153,12 +153,12 @@ function TimelineItem({ event, isLast, isNewest = false, isPulsingExec = false }
{event.actor && (
-
+
{event.actor}
{event.actorRole && (
+
CRITICAL
)}
diff --git a/apps/web/src/components/ui/approval-modal.tsx b/apps/web/src/components/ui/approval-modal.tsx
index 5e3713656..fbd1856bf 100644
--- a/apps/web/src/components/ui/approval-modal.tsx
+++ b/apps/web/src/components/ui/approval-modal.tsx
@@ -104,7 +104,7 @@ export function ApprovalModal({
{displayTitle}
-
+
Multi-Sig Authorization Required
@@ -127,7 +127,7 @@ export function ApprovalModal({
>
-
+
{current} / {total}
-
+
{current} / {total}
diff --git a/apps/web/src/components/ui/status-orb.tsx b/apps/web/src/components/ui/status-orb.tsx
index 3683f22fa..959ba9e00 100644
--- a/apps/web/src/components/ui/status-orb.tsx
+++ b/apps/web/src/components/ui/status-orb.tsx
@@ -242,7 +242,7 @@ export const StatusBadge = forwardRef(
)}
>
-
+
{displayLabel}
diff --git a/apps/web/src/components/ui/toast.tsx b/apps/web/src/components/ui/toast.tsx
index 2c1eff06e..094546d5b 100644
--- a/apps/web/src/components/ui/toast.tsx
+++ b/apps/web/src/components/ui/toast.tsx
@@ -155,7 +155,7 @@ function ToastItem({ toast, onClose }: { toast: ToastItem; onClose: () => void }
toast.type === 'loading' && 'animate-spin'
)}
/>
- {toast.message}
+ {toast.message}
)
}