feat(web-ui): redesign dashboard and live sessions
This commit is contained in:
+32
-17
@@ -10,6 +10,7 @@ import (
|
|||||||
"net/url"
|
"net/url"
|
||||||
"os"
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
|
"sync"
|
||||||
|
|
||||||
"github.com/gorilla/websocket"
|
"github.com/gorilla/websocket"
|
||||||
)
|
)
|
||||||
@@ -58,24 +59,38 @@ func main() {
|
|||||||
}
|
}
|
||||||
defer uiConn.Close()
|
defer uiConn.Close()
|
||||||
|
|
||||||
// Bidirectional copy
|
var uiMu, upstreamMu sync.Mutex
|
||||||
|
|
||||||
|
// upstream → UI
|
||||||
done := make(chan struct{})
|
done := make(chan struct{})
|
||||||
go func() {
|
go func() {
|
||||||
|
defer close(done)
|
||||||
for {
|
for {
|
||||||
_, msg, err := conn.ReadMessage()
|
_, msg, err := conn.ReadMessage()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
break
|
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 {
|
for {
|
||||||
_, msg, err := uiConn.ReadMessage()
|
_, msg, err := uiConn.ReadMessage()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
conn.WriteMessage(websocket.TextMessage, msg)
|
upstreamMu.Lock()
|
||||||
|
err = conn.WriteMessage(websocket.TextMessage, msg)
|
||||||
|
upstreamMu.Unlock()
|
||||||
|
if err != nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
}
|
}
|
||||||
<-done
|
<-done
|
||||||
})
|
})
|
||||||
@@ -89,23 +104,23 @@ func main() {
|
|||||||
fileServer.ServeHTTP(w, r)
|
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) {
|
mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
|
||||||
// Serve index.html for SPA routes
|
// If the path contains a dot, it's likely a missing static asset
|
||||||
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") {
|
if strings.Contains(r.URL.Path, ".") {
|
||||||
f, err := staticFiles.Open("static/index.html")
|
http.NotFound(w, r)
|
||||||
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)
|
|
||||||
return
|
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)
|
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>
|
<h1><a href="/">agentmon<span class="logo-dot"></span></a></h1>
|
||||||
</div>
|
</div>
|
||||||
<nav><a href="/">Dashboard</a><a href="/sessions">Sessions</a><a href="/agents">Agents</a><a href="/infrastructure">Infra</a></nav>
|
<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>
|
</header>
|
||||||
<main id="app">
|
<main id="app">
|
||||||
<p>Loading...</p>
|
<p>Loading...</p>
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user