Files
latticelm/internal/admin/static.go
Anibal Angulo 7025ec746c
Some checks failed
CI / Test (pull_request) Failing after 1m33s
CI / Lint (pull_request) Failing after 13s
CI / Build (pull_request) Has been skipped
CI / Security Scan (pull_request) Failing after 4m47s
CI / Build and Push Docker Image (pull_request) Has been skipped
Add admin UI
2026-03-05 23:09:27 +00:00

63 lines
1.5 KiB
Go

package admin
import (
"embed"
"io"
"io/fs"
"net/http"
"path"
"strings"
)
//go:embed all:dist
var frontendAssets embed.FS
// serveSPA serves the frontend SPA with fallback to index.html for client-side routing.
func (s *AdminServer) serveSPA() http.Handler {
// Get the dist subdirectory from embedded files
distFS, err := fs.Sub(frontendAssets, "dist")
if err != nil {
s.logger.Error("failed to access frontend assets", "error", err)
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
http.Error(w, "Admin UI not available", http.StatusNotFound)
})
}
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
// Path comes in without /admin prefix due to StripPrefix
urlPath := r.URL.Path
if urlPath == "" || urlPath == "/" {
urlPath = "index.html"
} else {
// Remove leading slash
urlPath = strings.TrimPrefix(urlPath, "/")
}
// Clean the path
cleanPath := path.Clean(urlPath)
// Try to open the file
file, err := distFS.Open(cleanPath)
if err != nil {
// File not found, serve index.html for SPA routing
cleanPath = "index.html"
file, err = distFS.Open(cleanPath)
if err != nil {
http.Error(w, "Not found", http.StatusNotFound)
return
}
}
defer file.Close()
// Get file info for content type detection
info, err := file.Stat()
if err != nil {
http.Error(w, "Internal error", http.StatusInternalServerError)
return
}
// Serve the file
http.ServeContent(w, r, cleanPath, info.ModTime(), file.(io.ReadSeeker))
})
}