feat(gui): add event info and layout query fixes
Some checks are pending
Security Scan / security (push) Waiting to run
Test / test (push) Waiting to run

This commit is contained in:
Virgil 2026-04-02 19:21:28 +00:00
parent 3d7998a9ca
commit cf284e9954
5 changed files with 83 additions and 6 deletions

View file

@ -573,6 +573,16 @@ func (s *Service) handleWSMessage(msg WSMessage) (any, bool, error) {
return nil, false, e
}
result, handled, err = s.Core().PERFORM(webview.TaskCloseDevTools{Window: w})
case "webview:errors":
w, e := wsRequire(msg.Data, "window")
if e != nil {
return nil, false, e
}
limit := 0
if l, ok := msg.Data["limit"].(float64); ok {
limit = int(l)
}
result, handled, err = s.Core().QUERY(webview.QueryExceptions{Window: w, Limit: limit})
case "layout:beside-editor":
editor, _ := msg.Data["editor"].(string)
windowName, _ := msg.Data["window"].(string)
@ -663,9 +673,12 @@ func (s *Service) handleWSMessage(msg WSMessage) (any, bool, error) {
if h, ok := msg.Data["height"].(float64); ok {
height = int(h)
}
screenWidth, screenHeight := s.primaryScreenSize()
result, handled, err = s.Core().QUERY(window.QueryFindSpace{
Width: width,
Height: height,
Width: width,
Height: height,
ScreenWidth: screenWidth,
ScreenHeight: screenHeight,
})
case "screen:list":
result, handled, err = s.Core().QUERY(screen.QueryAll{})
@ -862,6 +875,8 @@ func (s *Service) handleWSMessage(msg WSMessage) (any, bool, error) {
result, handled, err = s.Core().PERFORM(systray.TaskSetTrayMenu{Items: items})
case "tray:info":
result, handled, err = s.GetTrayInfo(), true, nil
case "event:info":
result, handled, err = s.GetEventInfo(), true, nil
case "theme:get":
result, handled, err = s.GetTheme(), true, nil
case "theme:system":
@ -1964,6 +1979,14 @@ func (s *Service) GetEventManager() *WSEventManager {
return s.events
}
// GetEventInfo returns a summary of the live WebSocket event server state.
func (s *Service) GetEventInfo() EventServerInfo {
if s.events == nil {
return EventServerInfo{}
}
return s.events.Info()
}
// --- Menu (handlers stay in display, structure delegated via IPC) ---
func (s *Service) buildMenu() {

View file

@ -1040,6 +1040,18 @@ func TestHandleWSMessage_Extended_Good(t *testing.T) {
assert.True(t, handled)
})
t.Run("webview errors", func(t *testing.T) {
result, handled, err := svc.handleWSMessage(WSMessage{
Action: "webview:errors",
Data: map[string]any{"window": "editor", "limit": float64(10)},
})
require.NoError(t, err)
assert.True(t, handled)
errors, ok := result.([]webview.ExceptionInfo)
require.True(t, ok)
assert.Len(t, errors, 0)
})
t.Run("tray message", func(t *testing.T) {
_, handled, err := svc.handleWSMessage(WSMessage{
Action: "tray:show-message",
@ -1084,4 +1096,14 @@ func TestHandleWSMessage_Extended_Good(t *testing.T) {
assert.True(t, handled)
assert.Equal(t, "OK", result)
})
t.Run("event info", func(t *testing.T) {
result, handled, err := svc.handleWSMessage(WSMessage{Action: "event:info"})
require.NoError(t, err)
assert.True(t, handled)
info, ok := result.(EventServerInfo)
require.True(t, ok)
assert.Equal(t, 0, info.ConnectedClients)
assert.Equal(t, 0, info.Subscriptions)
})
}

View file

@ -57,6 +57,13 @@ type Subscription struct {
EventTypes []EventType `json:"eventTypes"`
}
// EventServerInfo summarises the live WebSocket event server state.
type EventServerInfo struct {
ConnectedClients int `json:"connectedClients"`
Subscriptions int `json:"subscriptions"`
BufferedEvents int `json:"bufferedEvents"`
}
// WSEventManager manages WebSocket connections and event subscriptions.
type WSEventManager struct {
upgrader websocket.Upgrader
@ -307,6 +314,23 @@ func (em *WSEventManager) ConnectedClients() int {
return len(em.clients)
}
// Info returns a snapshot of the WebSocket event server state.
func (em *WSEventManager) Info() EventServerInfo {
em.mu.RLock()
defer em.mu.RUnlock()
info := EventServerInfo{
ConnectedClients: len(em.clients),
BufferedEvents: len(em.eventBuffer),
}
for _, state := range em.clients {
state.mu.RLock()
info.Subscriptions += len(state.subscriptions)
state.mu.RUnlock()
}
return info
}
// Close shuts down the event manager.
func (em *WSEventManager) Close() {
em.mu.Lock()

View file

@ -40,8 +40,10 @@ type QueryWindowBounds struct{ Name string }
// QueryFindSpace returns a suggested free placement for a new window.
type QueryFindSpace struct {
Width int
Height int
Width int
Height int
ScreenWidth int
ScreenHeight int
}
// QueryLayoutSuggestion returns a layout recommendation for the current screen.

View file

@ -86,10 +86,16 @@ func (s *Service) handleQuery(c *core.Core, q core.Query) (any, bool, error) {
}
return &l, true, nil
case QueryFindSpace:
screenW, screenH := s.primaryScreenSize()
screenW, screenH := q.ScreenWidth, q.ScreenHeight
if screenW <= 0 || screenH <= 0 {
screenW, screenH = s.primaryScreenSize()
}
return s.manager.FindSpace(screenW, screenH, q.Width, q.Height), true, nil
case QueryLayoutSuggestion:
screenW, screenH := s.primaryScreenSize()
screenW, screenH := q.ScreenWidth, q.ScreenHeight
if screenW <= 0 || screenH <= 0 {
screenW, screenH = s.primaryScreenSize()
}
return s.manager.SuggestLayout(screenW, screenH, q.WindowCount), true, nil
default:
return nil, false, nil