mirror of
https://github.com/YspCoder/clawgo.git
synced 2026-04-28 03:47:29 +08:00
webui phase2: add native nodes/cron api endpoints and management UI
This commit is contained in:
@@ -1,8 +1,8 @@
|
||||
import { useEffect, useMemo, useState } from 'react'
|
||||
|
||||
type ChatItem = { role: 'user' | 'assistant'; text: string }
|
||||
|
||||
type Session = { key: string; title: string }
|
||||
type CronJob = { id: string; name: string; enabled: boolean; schedule?: { kind?: string } }
|
||||
|
||||
const defaultSessions: Session[] = [{ key: 'webui:default', title: 'Default' }]
|
||||
|
||||
@@ -14,6 +14,7 @@ export function App() {
|
||||
const [chat, setChat] = useState<Record<string, ChatItem[]>>({ 'webui:default': [] })
|
||||
const [msg, setMsg] = useState('')
|
||||
const [nodes, setNodes] = useState<string>('[]')
|
||||
const [cron, setCron] = useState<CronJob[]>([])
|
||||
const activeChat = useMemo(() => chat[active] || [], [chat, active])
|
||||
|
||||
const q = token ? `?token=${encodeURIComponent(token)}` : ''
|
||||
@@ -34,17 +35,24 @@ export function App() {
|
||||
}
|
||||
|
||||
async function refreshNodes() {
|
||||
const payload = {
|
||||
session: active,
|
||||
message: '调用nodes工具,action=status,并输出JSON。',
|
||||
}
|
||||
const r = await fetch(`/webui/api/chat${q}`, {
|
||||
const r = await fetch(`/webui/api/nodes${q}`)
|
||||
const j = await r.json()
|
||||
setNodes(JSON.stringify(j.nodes || [], null, 2))
|
||||
}
|
||||
|
||||
async function refreshCron() {
|
||||
const r = await fetch(`/webui/api/cron${q}`)
|
||||
const j = await r.json()
|
||||
setCron(j.jobs || [])
|
||||
}
|
||||
|
||||
async function cronAction(action: 'delete' | 'enable' | 'disable', id: string) {
|
||||
await fetch(`/webui/api/cron${q}`, {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify(payload),
|
||||
body: JSON.stringify({ action, id }),
|
||||
})
|
||||
const t = await r.text()
|
||||
setNodes(t)
|
||||
await refreshCron()
|
||||
}
|
||||
|
||||
async function send() {
|
||||
@@ -84,6 +92,8 @@ export function App() {
|
||||
|
||||
useEffect(() => {
|
||||
loadConfig().catch(() => {})
|
||||
refreshNodes().catch(() => {})
|
||||
refreshCron().catch(() => {})
|
||||
}, [])
|
||||
|
||||
return (
|
||||
@@ -122,6 +132,19 @@ export function App() {
|
||||
<div className="panel-title">Config</div>
|
||||
<div className="row"><button onClick={loadConfig}>Load</button><button onClick={saveConfig}>Save+Reload</button></div>
|
||||
<textarea value={cfgText} onChange={(e) => setCfgText(e.target.value)} />
|
||||
<div className="panel-title">Cron</div>
|
||||
<div className="row"><button onClick={refreshCron}>Refresh</button></div>
|
||||
<div className="cron-list">
|
||||
{cron.map((j) => (
|
||||
<div key={j.id} className="cron-item">
|
||||
<div><strong>{j.name || j.id}</strong><div className="muted">{j.id}</div></div>
|
||||
<div className="row">
|
||||
<button onClick={() => cronAction(j.enabled ? 'disable' : 'enable', j.id)}>{j.enabled ? 'Disable' : 'Enable'}</button>
|
||||
<button onClick={() => cronAction('delete', j.id)}>Delete</button>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
<div className="panel-title">Nodes</div>
|
||||
<div className="row"><button onClick={refreshNodes}>Refresh</button></div>
|
||||
<pre>{nodes}</pre>
|
||||
|
||||
@@ -17,5 +17,9 @@ button{cursor:pointer;border:1px solid #374151;background:#0f172a;color:#fff;pad
|
||||
.row{display:flex;gap:8px;margin-bottom:8px}
|
||||
textarea{width:100%;min-height:180px;background:#0b1220;color:#e5e7eb;border:1px solid #374151;border-radius:8px;padding:8px}
|
||||
pre{flex:1;overflow:auto;background:#0b1220;border:1px solid #374151;border-radius:8px;padding:8px;white-space:pre-wrap}
|
||||
.cron-list{max-height:180px;overflow:auto;border:1px solid #374151;border-radius:8px;padding:6px;margin-bottom:8px;background:#0b1220}
|
||||
.cron-item{display:flex;justify-content:space-between;gap:8px;align-items:center;border-bottom:1px solid #1f2937;padding:6px 0}
|
||||
.cron-item:last-child{border-bottom:none}
|
||||
.muted{font-size:12px;color:#9ca3af}
|
||||
@media (max-width: 1024px){.layout{grid-template-columns:200px 1fr}.right{grid-column:1 / span 2;max-height:42vh}}
|
||||
@media (max-width: 768px){.layout{grid-template-columns:1fr}.sessions{order:2}.chat{order:1;min-height:50vh}.right{order:3}.topbar input{min-width:160px;width:52%}}
|
||||
|
||||
Reference in New Issue
Block a user