Команды (спец 12.2): - ui.Commands: действия UI → текстовые команды канала (start/cancel/skip/ retry/continue/approve/send), единый путь через chat.Channel. - ui.Window = chat.Channel + View; NilWindow для headless/тестов. Snapshots (спец 12.5): - ui.Store: чтение-модель, возвращает только копии (ListTasks/GetTask/ GetHistory/GetTraces); ui.DBStore поверх storage. Fyne-окно (internal/ui/desktop, build-tag cgo): - список задач слева, сплиты рабочей области и панели «Логи»/«Состояние», ввод+кнопки команд, тёмная тема, fullscreen, сохранение layout в Preferences, сворачивание при закрытии крестиком. - Колбэки View через fyne.Do (спец 12.4). Интеграция: - app.New(..., noUI); флаг --noui; UI собирается только с cgo (ui_cgo/ ui_noui фабрики), приложение headless без него. - Run: окно блокирует главную горутину; «Завершить» → cancel → graceful shutdown (спец 12.6). - go.mod: fyne.io/fyne/v2 v2.6.0 (direct).
69 lines
2.8 KiB
Go
69 lines
2.8 KiB
Go
package ui
|
|
|
|
import (
|
|
"context"
|
|
|
|
"github.com/kamelion/ratatoskr-go/internal/chat"
|
|
"github.com/kamelion/ratatoskr-go/internal/events"
|
|
)
|
|
|
|
// UID — фиксированный пользовательский идентификатор UI-канала (один пользователь).
|
|
const UID = chat.UserID("ui://local")
|
|
|
|
// Address — адрес доставки для UI-канала.
|
|
const Address = chat.Address("ui://local")
|
|
|
|
// Window — окно десктопного UI.
|
|
//
|
|
// Объединяет две роли:
|
|
// - chat.Channel — ещё одна реализация канала (спец 12.1): входящие от
|
|
// пользователя (ввод) уходят в Router → Core; исходящие (Send/Ask) — из
|
|
// Core/Router попадают в окно (диалог).
|
|
// - View — событийный мост из Controller (статусы, история, трейсы, логи).
|
|
//
|
|
// Реализация (Fyne) живёт в internal/ui/desktop под build-tag `cgo`.
|
|
type Window interface {
|
|
chat.Channel
|
|
View
|
|
// SetOnQuit задаёт колбэк полного выхода (кнопка «Завершить»).
|
|
SetOnQuit(func())
|
|
}
|
|
|
|
// NilWindow — no-op окно для headless-режима (--noui) и тестов.
|
|
// Реализует Window: канал без доставки и View без действий.
|
|
type NilWindow struct {
|
|
handler chat.Handler
|
|
}
|
|
|
|
// NewNilWindow создаёт NilWindow.
|
|
func NewNilWindow() *NilWindow { return &NilWindow{} }
|
|
|
|
func (n *NilWindow) OnMessage(h chat.Handler) { n.handler = h }
|
|
|
|
func (n *NilWindow) SetOnQuit(func()) {}
|
|
|
|
func (n *NilWindow) Run(ctx context.Context) error {
|
|
<-ctx.Done()
|
|
return ctx.Err()
|
|
}
|
|
|
|
func (n *NilWindow) Send(context.Context, chat.Address, chat.Message) error { return nil }
|
|
func (n *NilWindow) Ask(context.Context, chat.Address, chat.Message) error { return nil }
|
|
func (n *NilWindow) Close() error { return nil }
|
|
|
|
// Submit отправляет текст пользователя в Router (ввод в окне).
|
|
func (n *NilWindow) Submit(text string) {
|
|
if n.handler != nil {
|
|
n.handler(chat.Incoming{UserID: UID, Address: Address, Channel: n, Msg: chat.Message{Text: text}})
|
|
}
|
|
}
|
|
|
|
func (n *NilWindow) OnTaskCreated(events.TaskCreated) {}
|
|
func (n *NilWindow) OnTaskUpdated(events.TaskUpdated) {}
|
|
func (n *NilWindow) OnTaskDeleted(events.TaskDeleted) {}
|
|
func (n *NilWindow) OnTaskStatusChanged(events.TaskStatusChanged) {}
|
|
func (n *NilWindow) OnHistoryAppended(events.HistoryAppended) {}
|
|
func (n *NilWindow) OnTraceAppended(events.TraceAppended) {}
|
|
func (n *NilWindow) OnAgentActivity(events.AgentActivity) {}
|
|
func (n *NilWindow) OnLog(events.LogLine) {}
|