// Page 7 — Configuration function ConfigPage({ pushToast }) { const [config, setConfig] = useState(() => TEAM.map(t => ({ id: t.id, name: t.name, handle: `@${t.id}`, role: t.role, email: t.email, envKey: t.envKey, planeUserId: t.planeUserId, modules: [...t.modulesCurrent, ...t.modulesHistorical.slice(0, 2).map(h => h.module)].filter((v, i, a) => a.indexOf(v) === i), enabled: t.enabled, }))); const [poll, setPoll] = useState(30); const [confirm, setConfirm] = useState(null); const [tg, setTg] = useState({ token: "8174583291:AAFxxxx****REDACTED****", chatId: "-1001234567890", enabled: true, }); const setAgentField = (id, field, val) => { setConfig((c) => c.map(r => r.id === id ? { ...r, [field]: val } : r)); }; const addModule = (id, mod) => { if (!mod) return; setConfig((c) => c.map(r => r.id === id ? { ...r, modules: r.modules.includes(mod) ? r.modules : [...r.modules, mod] } : r)); }; const removeModule = (id, mod) => { setConfig((c) => c.map(r => r.id === id ? { ...r, modules: r.modules.filter(m => m !== mod) } : r)); }; return (

Конфигурация

Edit'ы пишут в config/agents.yaml. После Save watchdog перечитает конфиг автоматически.
{/* Agents */}

Агенты · config/agents.yaml

{config.length} строк
{config.map((row) => ( ))}
Имя Handle Роль Email API-ключ (env) plane_user_id Модули Watcher
setAgentField(row.id, "name", e.target.value)} />
setAgentField(row.id, "handle", e.target.value)} /> setAgentField(row.id, "email", e.target.value)} /> setAgentField(row.id, "envKey", e.target.value)} /> {row.planeUserId} addModule(row.id, m)} onRemove={(m) => removeModule(row.id, m)} />
{/* Two columns: alerts + watchdog */}

Алерт-каналы

Telegram-бот
setTg({ ...tg, token: e.target.value })} style={{ width: "100%", fontSize: 12 }} /> setTg({ ...tg, chatId: e.target.value })} style={{ width: "100%", fontSize: 12 }} />
Email
SMTP для нотификаций
coming soon

Watchdog

setPoll(parseInt(e.target.value) || 30)} style={{ width: 120, fontSize: 13 }} /> текущее: каждые {poll}с
2026-05-10T00:00:00Z read-only
События до этой метки не обрабатываются.
Сбрасывает «известное состояние» Plane. Все текущие задачи будут пере-обработаны.
Источник
PLANE_URL = https://plane.multi-print.local
WORKSPACE = multi-print
PROJECT = PriceBot
{/* Save bar */}
Несохранённые изменения в config/agents.yaml
setConfirm(null)} onConfirm={() => { setConfirm(null); pushToast("Baseline сброшен. Watchdog обрабатывает 47 задач…", "warn"); }} />
); } function Field({ label, children }) { return (
{label}
{children}
); } function ModulesEditor({ modules, onAdd, onRemove }) { const [draft, setDraft] = useState(""); return (
{modules.map((m) => ( {m} ))} setDraft(e.target.value)} onKeyDown={(e) => { if (e.key === "Enter" && draft.trim()) { onAdd(draft.trim()); setDraft(""); } }} placeholder="+ модуль" className="input mono" style={{ width: 90, padding: "2px 6px", fontSize: 11 }} />
); } window.ConfigPage = ConfigPage;