mirror of
https://github.com/xmanrui/OpenClaw-bot-review.git
synced 2026-07-27 21:01:08 +00:00
fix: restore deployment and cleanup after pr 24
This commit is contained in:
@@ -3,4 +3,5 @@ node_modules
|
|||||||
*.tsbuildinfo
|
*.tsbuildinfo
|
||||||
next-env.d.ts
|
next-env.d.ts
|
||||||
.idea
|
.idea
|
||||||
|
.DS_Store
|
||||||
/public/assets/pixel-office/*.mp3
|
/public/assets/pixel-office/*.mp3
|
||||||
|
|||||||
+47
-19
@@ -26,6 +26,12 @@ interface Agent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const RULE_DESCRIPTIONS: Record<string, Record<string, string>> = {
|
const RULE_DESCRIPTIONS: Record<string, Record<string, string>> = {
|
||||||
|
"zh-TW": {
|
||||||
|
model_unavailable: "模型不可用 - 當測試模型失敗時觸發",
|
||||||
|
bot_no_response: "Bot 長時間無回應 - 當機器人超過設定時間未回應時觸發",
|
||||||
|
message_failure_rate: "訊息失敗率升高 - 當訊息失敗率超過閾值時觸發",
|
||||||
|
cron连续_failure: "Cron 連續失敗 - 當定時任務連續失敗超過設定次數時觸發",
|
||||||
|
},
|
||||||
zh: {
|
zh: {
|
||||||
model_unavailable: "模型不可用 - 当测试模型失败时触发",
|
model_unavailable: "模型不可用 - 当测试模型失败时触发",
|
||||||
bot_no_response: "Bot 长时间无响应 - 当机器人超过设定时间未响应时触发",
|
bot_no_response: "Bot 长时间无响应 - 当机器人超过设定时间未响应时触发",
|
||||||
@@ -60,6 +66,28 @@ export default function AlertsPage() {
|
|||||||
}, [config?.checkInterval]);
|
}, [config?.checkInterval]);
|
||||||
|
|
||||||
const ruleDescriptions = RULE_DESCRIPTIONS[locale as keyof typeof RULE_DESCRIPTIONS] || RULE_DESCRIPTIONS.zh;
|
const ruleDescriptions = RULE_DESCRIPTIONS[locale as keyof typeof RULE_DESCRIPTIONS] || RULE_DESCRIPTIONS.zh;
|
||||||
|
const isEnglish = locale === "en";
|
||||||
|
const isTraditionalChinese = locale === "zh-TW";
|
||||||
|
const timeLocale = isEnglish ? "en-US" : isTraditionalChinese ? "zh-TW" : "zh-CN";
|
||||||
|
const ui = {
|
||||||
|
minutes5: isEnglish ? "5 minutes" : isTraditionalChinese ? "5 分鐘" : "5 分钟",
|
||||||
|
minutes10: isEnglish ? "10 minutes" : isTraditionalChinese ? "10 分鐘" : "10 分钟",
|
||||||
|
minutes30: isEnglish ? "30 minutes" : isTraditionalChinese ? "30 分鐘" : "30 分钟",
|
||||||
|
hour1: isEnglish ? "1 hour" : isTraditionalChinese ? "1 小時" : "1 小时",
|
||||||
|
hours2: isEnglish ? "2 hours" : isTraditionalChinese ? "2 小時" : "2 小时",
|
||||||
|
hours5: isEnglish ? "5 hours" : isTraditionalChinese ? "5 小時" : "5 小时",
|
||||||
|
checking: isEnglish ? "⏳ Checking..." : isTraditionalChinese ? "⏳ 檢查中..." : "⏳ 检查中...",
|
||||||
|
checkNow: isEnglish ? "🔄 Check Now" : isTraditionalChinese ? "🔄 立即檢查" : "🔄 立即检查",
|
||||||
|
alertsTriggered: isEnglish ? "⚠️ Alerts Triggered" : isTraditionalChinese ? "⚠️ 警報觸發" : "⚠️ 告警触发",
|
||||||
|
checkingAlerts: isEnglish ? "⏳ Checking alerts..." : isTraditionalChinese ? "⏳ 正在檢查警報..." : "⏳ 正在检查告警...",
|
||||||
|
timeout: isEnglish ? "Timeout (s):" : isTraditionalChinese ? "超時 (秒):" : "超时 (秒):",
|
||||||
|
failureRate: isEnglish ? "Failure rate (%):" : isTraditionalChinese ? "失敗率 (%):" : "失败率 (%):",
|
||||||
|
maxFailures: isEnglish ? "Max failures:" : isTraditionalChinese ? "最大失敗數:" : "最大失败数:",
|
||||||
|
threshold: isEnglish ? "Threshold:" : isTraditionalChinese ? "閾值:" : "阈值:",
|
||||||
|
monitor: isEnglish ? "Monitor:" : isTraditionalChinese ? "檢測機器人:" : "检测机器人:",
|
||||||
|
emptyMeansAll: isEnglish ? "(empty = all)" : isTraditionalChinese ? "(不選則檢測所有)" : "(不选则检测所有)",
|
||||||
|
saved: isEnglish ? "Saved" : isTraditionalChinese ? "已保存" : "已保存",
|
||||||
|
};
|
||||||
|
|
||||||
// 加载配置
|
// 加载配置
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@@ -86,7 +114,7 @@ export default function AlertsPage() {
|
|||||||
.then((data) => {
|
.then((data) => {
|
||||||
if (data.results && data.results.length > 0) {
|
if (data.results && data.results.length > 0) {
|
||||||
setCheckResults(data.results);
|
setCheckResults(data.results);
|
||||||
setLastCheckTime(new Date().toLocaleTimeString(locale === "zh" ? "zh-CN" : "en-US"));
|
setLastCheckTime(new Date().toLocaleTimeString(timeLocale));
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.catch(console.error)
|
.catch(console.error)
|
||||||
@@ -105,7 +133,7 @@ export default function AlertsPage() {
|
|||||||
.then((data) => {
|
.then((data) => {
|
||||||
if (data.results && data.results.length > 0) {
|
if (data.results && data.results.length > 0) {
|
||||||
setCheckResults(data.results);
|
setCheckResults(data.results);
|
||||||
setLastCheckTime(new Date().toLocaleTimeString(locale === "zh" ? "zh-CN" : "en-US"));
|
setLastCheckTime(new Date().toLocaleTimeString(timeLocale));
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.catch(console.error)
|
.catch(console.error)
|
||||||
@@ -241,12 +269,12 @@ export default function AlertsPage() {
|
|||||||
onChange={(e) => handleIntervalChange(Number(e.target.value))}
|
onChange={(e) => handleIntervalChange(Number(e.target.value))}
|
||||||
className="px-2 py-1 text-sm rounded border border-[var(--border)] bg-[var(--card)] text-[var(--text)]"
|
className="px-2 py-1 text-sm rounded border border-[var(--border)] bg-[var(--card)] text-[var(--text)]"
|
||||||
>
|
>
|
||||||
<option value={5}>{locale === "zh" ? "5 分钟" : "5 minutes"}</option>
|
<option value={5}>{ui.minutes5}</option>
|
||||||
<option value={10}>{locale === "zh" ? "10 分钟" : "10 minutes"}</option>
|
<option value={10}>{ui.minutes10}</option>
|
||||||
<option value={30}>{locale === "zh" ? "30 分钟" : "30 minutes"}</option>
|
<option value={30}>{ui.minutes30}</option>
|
||||||
<option value={60}>{locale === "zh" ? "1 小时" : "1 hour"}</option>
|
<option value={60}>{ui.hour1}</option>
|
||||||
<option value={120}>{locale === "zh" ? "2 小时" : "2 hours"}</option>
|
<option value={120}>{ui.hours2}</option>
|
||||||
<option value={300}>{locale === "zh" ? "5 小时" : "5 hours"}</option>
|
<option value={300}>{ui.hours5}</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
@@ -257,7 +285,7 @@ export default function AlertsPage() {
|
|||||||
disabled={checking}
|
disabled={checking}
|
||||||
className="px-4 py-2 rounded-lg bg-[var(--card)] border border-[var(--border)] text-sm hover:border-[var(--accent)] transition disabled:opacity-50"
|
className="px-4 py-2 rounded-lg bg-[var(--card)] border border-[var(--border)] text-sm hover:border-[var(--accent)] transition disabled:opacity-50"
|
||||||
>
|
>
|
||||||
{checking ? (locale === "zh" ? "⏳ 检查中..." : "⏳ Checking...") : (locale === "zh" ? "🔄 立即检查" : "🔄 Check Now")}
|
{checking ? ui.checking : ui.checkNow}
|
||||||
</button>
|
</button>
|
||||||
)}
|
)}
|
||||||
<Link
|
<Link
|
||||||
@@ -274,7 +302,7 @@ export default function AlertsPage() {
|
|||||||
<div className="p-4 rounded-xl border border-yellow-500/30 bg-yellow-500/10 mb-6">
|
<div className="p-4 rounded-xl border border-yellow-500/30 bg-yellow-500/10 mb-6">
|
||||||
<div className="flex items-center justify-between mb-2">
|
<div className="flex items-center justify-between mb-2">
|
||||||
<h3 className="font-semibold text-yellow-400">
|
<h3 className="font-semibold text-yellow-400">
|
||||||
{locale === "zh" ? "⚠️ 告警触发" : "⚠️ Alerts Triggered"} ({checkResults.length})
|
{ui.alertsTriggered} ({checkResults.length})
|
||||||
</h3>
|
</h3>
|
||||||
{lastCheckTime && <span className="text-xs text-[var(--text-muted)]">{lastCheckTime}</span>}
|
{lastCheckTime && <span className="text-xs text-[var(--text-muted)]">{lastCheckTime}</span>}
|
||||||
</div>
|
</div>
|
||||||
@@ -288,7 +316,7 @@ export default function AlertsPage() {
|
|||||||
|
|
||||||
{config.enabled && checking && (
|
{config.enabled && checking && (
|
||||||
<div className="p-4 rounded-xl border border-[var(--border)] bg-[var(--card)] mb-6 text-center text-[var(--text-muted)]">
|
<div className="p-4 rounded-xl border border-[var(--border)] bg-[var(--card)] mb-6 text-center text-[var(--text-muted)]">
|
||||||
{locale === "zh" ? "⏳ 正在检查告警..." : "⏳ Checking alerts..."}
|
{ui.checkingAlerts}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
@@ -375,10 +403,10 @@ export default function AlertsPage() {
|
|||||||
{rule.threshold !== undefined && rule.id !== "bot_no_response" && (
|
{rule.threshold !== undefined && rule.id !== "bot_no_response" && (
|
||||||
<div className="flex items-center gap-2">
|
<div className="flex items-center gap-2">
|
||||||
<span className="text-xs text-[var(--text-muted)]">
|
<span className="text-xs text-[var(--text-muted)]">
|
||||||
{rule.id === "bot_no_response" ? (locale === "zh" ? "超时 (秒):" : "Timeout (s):") :
|
{rule.id === "bot_no_response" ? ui.timeout :
|
||||||
rule.id === "message_failure_rate" ? (locale === "zh" ? "失败率 (%):" : "Failure rate (%):") :
|
rule.id === "message_failure_rate" ? ui.failureRate :
|
||||||
rule.id === "cron连续_failure" ? (locale === "zh" ? "最大失败数:" : "Max failures:") :
|
rule.id === "cron连续_failure" ? ui.maxFailures :
|
||||||
(locale === "zh" ? "阈值:" : "Threshold:")}
|
ui.threshold}
|
||||||
</span>
|
</span>
|
||||||
<input
|
<input
|
||||||
type="number"
|
type="number"
|
||||||
@@ -392,7 +420,7 @@ export default function AlertsPage() {
|
|||||||
{rule.id === "bot_no_response" && rule.threshold !== undefined && (
|
{rule.id === "bot_no_response" && rule.threshold !== undefined && (
|
||||||
<div className="flex items-center gap-2">
|
<div className="flex items-center gap-2">
|
||||||
<span className="text-xs text-[var(--text-muted)]">
|
<span className="text-xs text-[var(--text-muted)]">
|
||||||
{locale === "zh" ? "超时 (秒):" : "Timeout (s):"}
|
{ui.timeout}
|
||||||
</span>
|
</span>
|
||||||
<input
|
<input
|
||||||
type="number"
|
type="number"
|
||||||
@@ -409,7 +437,7 @@ export default function AlertsPage() {
|
|||||||
<div className="mt-3 pt-3 border-t border-[var(--border)]">
|
<div className="mt-3 pt-3 border-t border-[var(--border)]">
|
||||||
<div className="flex flex-wrap gap-2 items-center">
|
<div className="flex flex-wrap gap-2 items-center">
|
||||||
<span className="text-xs text-[var(--text-muted)]">
|
<span className="text-xs text-[var(--text-muted)]">
|
||||||
{locale === "zh" ? "检测机器人:" : "Monitor:"}
|
{ui.monitor}
|
||||||
</span>
|
</span>
|
||||||
{agents.map((agent) => {
|
{agents.map((agent) => {
|
||||||
const selected = rule.targetAgents?.includes(agent.id) ?? true;
|
const selected = rule.targetAgents?.includes(agent.id) ?? true;
|
||||||
@@ -454,7 +482,7 @@ export default function AlertsPage() {
|
|||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
<span className="text-xs text-[var(--text-muted)] ml-2">
|
<span className="text-xs text-[var(--text-muted)] ml-2">
|
||||||
{locale === "zh" ? "(不选则检测所有)" : "(empty = all)"}
|
{ui.emptyMeansAll}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -467,7 +495,7 @@ export default function AlertsPage() {
|
|||||||
{/* 保存提示 */}
|
{/* 保存提示 */}
|
||||||
{saved && (
|
{saved && (
|
||||||
<div className="fixed bottom-8 right-8 px-4 py-2 rounded-lg bg-green-500 text-white text-sm animate-fade-in">
|
<div className="fixed bottom-8 right-8 px-4 py-2 rounded-lg bg-green-500 text-white text-sm animate-fade-in">
|
||||||
✓ {locale === "zh" ? "已保存" : "Saved"}
|
✓ {ui.saved}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</main>
|
</main>
|
||||||
|
|||||||
Vendored
BIN
Binary file not shown.
Vendored
BIN
Binary file not shown.
@@ -523,7 +523,24 @@ export function renderScene(
|
|||||||
const now = Date.now()
|
const now = Date.now()
|
||||||
// Blink effect for working state: use time-based alpha
|
// Blink effect for working state: use time-based alpha
|
||||||
const labelAlpha = isWorking ? 0.7 + 0.3 * Math.sin(now / 300) : 1.0
|
const labelAlpha = isWorking ? 0.7 + 0.3 * Math.sin(now / 300) : 1.0
|
||||||
const labelColor = isWorking ? `rgba(34,197,94,${labelAlpha})` : '#FFD700'
|
let labelColor = ch.isSubagent
|
||||||
|
? (isWorking ? `rgba(220,38,38,${labelAlpha})` : '#991B1B')
|
||||||
|
: (isWorking ? `rgba(34,197,94,${labelAlpha})` : '#FFD700')
|
||||||
|
if (ch.systemRoleType === 'gateway_sre') {
|
||||||
|
const state = ch.systemStatus ?? 'unknown'
|
||||||
|
if (state === 'healthy') {
|
||||||
|
const alpha = 0.65 + 0.3 * ((Math.sin(now / 760) + 1) / 2)
|
||||||
|
labelColor = `rgba(34,197,94,${alpha})`
|
||||||
|
} else if (state === 'degraded') {
|
||||||
|
const alpha = 0.45 + 0.55 * ((Math.sin(now / 220) + 1) / 2)
|
||||||
|
labelColor = `rgba(250,204,21,${alpha})`
|
||||||
|
} else if (state === 'down') {
|
||||||
|
const alpha = 0.28 + 0.72 * ((Math.sin(now / 110) + 1) / 2)
|
||||||
|
labelColor = `rgba(153,27,27,${alpha})`
|
||||||
|
} else {
|
||||||
|
labelColor = '#9CA3AF'
|
||||||
|
}
|
||||||
|
}
|
||||||
drawables.push({
|
drawables.push({
|
||||||
zY: charZY + 0.1,
|
zY: charZY + 0.1,
|
||||||
draw: (c) => {
|
draw: (c) => {
|
||||||
@@ -552,6 +569,8 @@ export function renderScene(
|
|||||||
c.closePath()
|
c.closePath()
|
||||||
c.fillStyle = 'rgba(0,0,0,0.55)'
|
c.fillStyle = 'rgba(0,0,0,0.55)'
|
||||||
c.fill()
|
c.fill()
|
||||||
|
c.fillStyle = 'rgba(0,0,0,0.9)'
|
||||||
|
c.fillText(ch.label, labelX, labelY + 1)
|
||||||
c.fillStyle = labelColor
|
c.fillStyle = labelColor
|
||||||
c.fillText(ch.label, labelX, labelY)
|
c.fillText(ch.label, labelX, labelY)
|
||||||
c.restore()
|
c.restore()
|
||||||
|
|||||||
+3
-1
@@ -1,3 +1,5 @@
|
|||||||
/** @type {import('next').NextConfig} */
|
/** @type {import('next').NextConfig} */
|
||||||
const nextConfig = {};
|
const nextConfig = {
|
||||||
|
output: 'standalone',
|
||||||
|
};
|
||||||
export default nextConfig;
|
export default nextConfig;
|
||||||
|
|||||||
Vendored
BIN
Binary file not shown.
Vendored
BIN
Binary file not shown.
Vendored
BIN
Binary file not shown.
Reference in New Issue
Block a user