This commit is contained in:
2026-02-13 21:15:00 +01:00
parent bcc7877c41
commit fd29e602e8
4 changed files with 134 additions and 124 deletions
+27 -9
View File
@@ -59,6 +59,10 @@ func (s *Server) loadTemplates() {
switch state {
case stacks.StateRunning:
return "green"
case stacks.StateStarting:
return "orange"
case stacks.StateUnhealthy:
return "yellow"
case stacks.StateStopped, stacks.StateExited:
return "red"
case stacks.StateRestarting:
@@ -71,6 +75,10 @@ func (s *Server) loadTemplates() {
switch state {
case stacks.StateRunning:
return "Fut"
case stacks.StateStarting:
return "Indulás..."
case stacks.StateUnhealthy:
return "Nem egészséges"
case stacks.StateStopped, stacks.StateExited:
return "Leállítva"
case stacks.StateRestarting:
@@ -87,6 +95,10 @@ func (s *Server) loadTemplates() {
switch state {
case stacks.StateRunning:
return "●"
case stacks.StateStarting:
return "◐"
case stacks.StateUnhealthy:
return "◑"
case stacks.StateStopped, stacks.StateExited:
return "○"
case stacks.StateRestarting:
@@ -98,6 +110,16 @@ func (s *Server) loadTemplates() {
"stateStr": func(state stacks.ContainerState) string {
return string(state)
},
// isOperational returns true for any state where the stack has containers
// and is not stopped/exited — used by templates for showing action buttons
"isOperational": func(state stacks.ContainerState) bool {
switch state {
case stacks.StateRunning, stacks.StateStarting, stacks.StateUnhealthy, stacks.StateRestarting:
return true
default:
return false
}
},
"logoURL": func(slug string) string {
return s.cfg.AppLogoURL(slug)
},
@@ -134,7 +156,6 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Cache-Control", "public, max-age=3600")
fmt.Fprint(w, cssContent)
case strings.HasPrefix(path, "/static/assets/"):
// Serve baked-in app assets (logos, screenshots)
s.serveAsset(w, r, strings.TrimPrefix(path, "/static/assets/"))
case strings.HasPrefix(path, "/apps/"):
slug := strings.TrimPrefix(path, "/apps/")
@@ -287,6 +308,10 @@ func (s *Server) dashboardHandler(w http.ResponseWriter, _ *http.Request) {
running++
case stacks.StateStopped, stacks.StateExited:
stopped++
case stacks.StateStarting, stacks.StateUnhealthy, stacks.StateRestarting:
// Count starting/unhealthy/restarting as "running" for the dashboard stat
// (they have containers, they're just not fully healthy yet)
running++
}
}
@@ -347,11 +372,9 @@ func (s *Server) deployHandler(w http.ResponseWriter, _ *http.Request, name stri
}
// serveAsset serves baked-in app assets (logos, screenshots) from /usr/share/felhom/assets/
// These are copied into the container at build time.
const assetsDir = "/usr/share/felhom/assets"
func (s *Server) serveAsset(w http.ResponseWriter, r *http.Request, filename string) {
// Sanitize: prevent directory traversal
filename = filepath.Base(filename)
path := filepath.Join(assetsDir, filename)
@@ -364,14 +387,9 @@ func (s *Server) serveAsset(w http.ResponseWriter, r *http.Request, filename str
http.ServeFile(w, r, path)
}
// appDetailHandler serves a local app detail page (description, screenshots, FAQ).
// TODO: Phase 1.5 — for now, redirect to the stacks page.
// Future: render a dedicated app page template with baked-in content.
func (s *Server) appDetailHandler(w http.ResponseWriter, r *http.Request, slug string) {
// Find the stack by slug
for _, stack := range s.stackMgr.GetStacks() {
if stack.Meta.Slug == slug {
// For now, redirect to deploy page (if not deployed) or stacks page
if !stack.Deployed {
http.Redirect(w, r, "/stacks/"+stack.Name+"/deploy", http.StatusFound)
} else {
@@ -402,4 +420,4 @@ func (s *Server) render(w http.ResponseWriter, name string, data interface{}) {
s.logger.Printf("[ERROR] Template error (%s): %v", name, err)
http.Error(w, "Internal error", http.StatusInternalServerError)
}
}
}