feat(web-ui): redesign dashboard and live sessions
This commit is contained in:
+32
-17
@@ -10,6 +10,7 @@ import (
|
||||
"net/url"
|
||||
"os"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"github.com/gorilla/websocket"
|
||||
)
|
||||
@@ -58,24 +59,38 @@ func main() {
|
||||
}
|
||||
defer uiConn.Close()
|
||||
|
||||
// Bidirectional copy
|
||||
var uiMu, upstreamMu sync.Mutex
|
||||
|
||||
// upstream → UI
|
||||
done := make(chan struct{})
|
||||
go func() {
|
||||
defer close(done)
|
||||
for {
|
||||
_, msg, err := conn.ReadMessage()
|
||||
if err != nil {
|
||||
break
|
||||
}
|
||||
uiConn.WriteMessage(websocket.TextMessage, msg)
|
||||
uiMu.Lock()
|
||||
err = uiConn.WriteMessage(websocket.TextMessage, msg)
|
||||
uiMu.Unlock()
|
||||
if err != nil {
|
||||
break
|
||||
}
|
||||
}
|
||||
close(done)
|
||||
}()
|
||||
|
||||
// UI → upstream
|
||||
for {
|
||||
_, msg, err := uiConn.ReadMessage()
|
||||
if err != nil {
|
||||
break
|
||||
}
|
||||
conn.WriteMessage(websocket.TextMessage, msg)
|
||||
upstreamMu.Lock()
|
||||
err = conn.WriteMessage(websocket.TextMessage, msg)
|
||||
upstreamMu.Unlock()
|
||||
if err != nil {
|
||||
break
|
||||
}
|
||||
}
|
||||
<-done
|
||||
})
|
||||
@@ -89,23 +104,23 @@ func main() {
|
||||
fileServer.ServeHTTP(w, r)
|
||||
})
|
||||
|
||||
// SPA catch-all: serve index.html for all other routes
|
||||
// SPA catch-all: serve index.html for routes without file extensions
|
||||
mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
|
||||
// Serve index.html for SPA routes
|
||||
if r.URL.Path == "/" || strings.HasPrefix(r.URL.Path, "/sessions") || strings.HasPrefix(r.URL.Path, "/runs") || strings.HasPrefix(r.URL.Path, "/infrastructure") || strings.HasPrefix(r.URL.Path, "/agents") {
|
||||
f, err := staticFiles.Open("static/index.html")
|
||||
if err != nil {
|
||||
http.Error(w, "index.html not found", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
w.Header().Set("Content-Type", "text/html; charset=utf-8")
|
||||
_, _ = io.Copy(w, f)
|
||||
// If the path contains a dot, it's likely a missing static asset
|
||||
if strings.Contains(r.URL.Path, ".") {
|
||||
http.NotFound(w, r)
|
||||
return
|
||||
}
|
||||
|
||||
http.NotFound(w, r)
|
||||
f, err := staticFiles.Open("static/index.html")
|
||||
if err != nil {
|
||||
http.Error(w, "index.html not found", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
w.Header().Set("Content-Type", "text/html; charset=utf-8")
|
||||
_, _ = io.Copy(w, f)
|
||||
})
|
||||
|
||||
log.Printf("web-ui listening on %s", addr)
|
||||
|
||||
+1350
-242
File diff suppressed because it is too large
Load Diff
@@ -17,7 +17,10 @@
|
||||
<h1><a href="/">agentmon<span class="logo-dot"></span></a></h1>
|
||||
</div>
|
||||
<nav><a href="/">Dashboard</a><a href="/sessions">Sessions</a><a href="/agents">Agents</a><a href="/infrastructure">Infra</a></nav>
|
||||
<button class="theme-toggle" id="theme-toggle" aria-label="Toggle theme"></button>
|
||||
<div class="header-right">
|
||||
<span class="ws-dot" id="ws-dot" title="Disconnected"></span>
|
||||
<button class="theme-toggle" id="theme-toggle" aria-label="Toggle theme"></button>
|
||||
</div>
|
||||
</header>
|
||||
<main id="app">
|
||||
<p>Loading...</p>
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user