feat(ui): команды, snapshots, Fyne-окно и интеграция (--noui)
Команды (спец 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).
This commit is contained in:
68
internal/ui/window.go
Normal file
68
internal/ui/window.go
Normal file
@@ -0,0 +1,68 @@
|
||||
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) {}
|
||||
Reference in New Issue
Block a user