// 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} строк
| Имя |
Handle |
Роль |
Email |
API-ключ (env) |
plane_user_id |
Модули |
Watcher |
{config.map((row) => (
|
|
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 */}
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 (
);
}
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;