v0.3.0: structural refactor — go:embed templates, server split, domain rename
- Migrate all 7 HTML templates + CSS from Go string constants to individual go:embed files in internal/web/templates/ (templates.go: 2150→35 lines) - Split server.go into auth.go, handlers.go, funcmap.go (server.go: 540→120 lines) - Rename controller subdomain from dashboard.* to felhom.* in Traefik labels - Update documentation (CLAUDE.md, README.md, CONTEXT.md) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,173 @@
|
||||
package web
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
"gitea.dooplex.hu/admin/felhom-controller/internal/stacks"
|
||||
"gitea.dooplex.hu/admin/felhom-controller/internal/system"
|
||||
)
|
||||
|
||||
func (s *Server) baseData(page, title string) map[string]interface{} {
|
||||
return map[string]interface{}{
|
||||
"Page": page,
|
||||
"Title": title,
|
||||
"CustomerName": s.cfg.Customer.Name,
|
||||
"Domain": s.cfg.Customer.Domain,
|
||||
"Version": s.version,
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Server) dashboardHandler(w http.ResponseWriter, _ *http.Request) {
|
||||
stackList := s.stackMgr.GetStacks()
|
||||
|
||||
running, stopped := 0, 0
|
||||
for _, st := range stackList {
|
||||
switch st.State {
|
||||
case stacks.StateRunning:
|
||||
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++
|
||||
}
|
||||
}
|
||||
|
||||
sysInfo := system.GetInfo(s.cfg.Paths.HDDPath)
|
||||
|
||||
data := s.baseData("dashboard", "Vezérlőpult")
|
||||
data["Stacks"] = stackList
|
||||
data["RunningCount"] = running
|
||||
data["StoppedCount"] = stopped
|
||||
data["TotalCount"] = len(stackList)
|
||||
data["SystemInfo"] = sysInfo
|
||||
|
||||
s.render(w, "dashboard", data)
|
||||
}
|
||||
|
||||
func (s *Server) stacksHandler(w http.ResponseWriter, _ *http.Request) {
|
||||
data := s.baseData("stacks", "Alkalmazások")
|
||||
data["Stacks"] = s.stackMgr.GetStacks()
|
||||
s.render(w, "stacks", data)
|
||||
}
|
||||
|
||||
func (s *Server) logsHandler(w http.ResponseWriter, r *http.Request, name string) {
|
||||
stack, ok := s.stackMgr.GetStack(name)
|
||||
if !ok {
|
||||
http.NotFound(w, r)
|
||||
return
|
||||
}
|
||||
|
||||
logs, err := s.stackMgr.GetLogs(name, 200)
|
||||
if err != nil {
|
||||
logs = fmt.Sprintf("Hiba a naplók lekérésekor: %v", err)
|
||||
}
|
||||
|
||||
// Raw mode: return plain text for AJAX polling
|
||||
if r.URL.Query().Get("raw") == "1" {
|
||||
w.Header().Set("Content-Type", "text/plain; charset=utf-8")
|
||||
fmt.Fprint(w, logs)
|
||||
return
|
||||
}
|
||||
|
||||
data := s.baseData("logs", stack.Meta.DisplayName+" — Naplók")
|
||||
data["Stack"] = stack
|
||||
data["Logs"] = logs
|
||||
s.render(w, "logs", data)
|
||||
}
|
||||
|
||||
func (s *Server) deployHandler(w http.ResponseWriter, _ *http.Request, name string) {
|
||||
meta, appCfg, err := s.stackMgr.GetDeployFields(name)
|
||||
if err != nil {
|
||||
http.NotFound(w, nil)
|
||||
return
|
||||
}
|
||||
|
||||
stack, _ := s.stackMgr.GetStack(name)
|
||||
alreadyDeployed := appCfg != nil && appCfg.Deployed
|
||||
|
||||
data := s.baseData("deploy", meta.DisplayName+" — Telepítés")
|
||||
data["Stack"] = stack
|
||||
data["Meta"] = meta
|
||||
data["AppConfig"] = appCfg
|
||||
data["AlreadyDeployed"] = alreadyDeployed
|
||||
data["LogoURL"] = s.cfg.AppLogoURL(meta.Slug)
|
||||
data["LogoPNGURL"] = s.cfg.AppLogoPNGURL(meta.Slug)
|
||||
data["AppPageURL"] = s.cfg.AppPageURL(meta.Slug)
|
||||
data["UserFields"] = meta.UserFacingFields()
|
||||
data["AutoFields"] = meta.AutoGeneratedFields()
|
||||
|
||||
// Memory info for deploy page (only for non-deployed apps)
|
||||
if !alreadyDeployed {
|
||||
memInfo := map[string]interface{}{"Available": false}
|
||||
totalMB, memErr := system.GetTotalMemoryMB()
|
||||
if memErr == nil {
|
||||
reservedMB := s.cfg.System.ReservedMemoryMB
|
||||
usableMB := totalMB - reservedMB
|
||||
committedReqMB, committedLimitMB := s.stackMgr.CommittedMemory()
|
||||
newReqMB := stacks.ParseMemoryMB(meta.Resources.MemRequest)
|
||||
newLimitMB := stacks.ParseMemoryMB(meta.Resources.MemLimit)
|
||||
afterReqMB := committedReqMB + newReqMB
|
||||
afterLimitMB := committedLimitMB + newLimitMB
|
||||
percent := 0
|
||||
if usableMB > 0 {
|
||||
percent = afterReqMB * 100 / usableMB
|
||||
}
|
||||
|
||||
committedPercent := 0
|
||||
if usableMB > 0 {
|
||||
committedPercent = committedReqMB * 100 / usableMB
|
||||
}
|
||||
|
||||
memInfo["Available"] = true
|
||||
memInfo["TotalMB"] = totalMB
|
||||
memInfo["ReservedMB"] = reservedMB
|
||||
memInfo["UsableMB"] = usableMB
|
||||
memInfo["CommittedMB"] = committedReqMB
|
||||
memInfo["NewRequestMB"] = newReqMB
|
||||
memInfo["AfterMB"] = afterReqMB
|
||||
memInfo["Percent"] = percent
|
||||
memInfo["CommittedPercent"] = committedPercent
|
||||
memInfo["Blocked"] = newReqMB > 0 && afterReqMB > usableMB
|
||||
memInfo["OvercommitWarn"] = newLimitMB > 0 && afterLimitMB > totalMB
|
||||
}
|
||||
data["MemoryInfo"] = memInfo
|
||||
}
|
||||
|
||||
s.render(w, "deploy", data)
|
||||
}
|
||||
|
||||
func (s *Server) appDetailHandler(w http.ResponseWriter, _ *http.Request, slug string) {
|
||||
var found *stacks.Stack
|
||||
for _, stack := range s.stackMgr.GetStacks() {
|
||||
if stack.Meta.Slug == slug {
|
||||
found = &stack
|
||||
break
|
||||
}
|
||||
}
|
||||
if found == nil {
|
||||
http.NotFound(w, nil)
|
||||
return
|
||||
}
|
||||
|
||||
// Load current optional config values from app.yaml
|
||||
currentValues := make(map[string]string)
|
||||
if appCfg := s.stackMgr.LoadAppConfigByName(found.Name); appCfg != nil {
|
||||
for k, v := range appCfg.Env {
|
||||
currentValues[k] = v
|
||||
}
|
||||
}
|
||||
|
||||
data := s.baseData("stacks", found.Meta.DisplayName)
|
||||
data["Stack"] = found
|
||||
data["Meta"] = found.Meta
|
||||
data["AppInfo"] = found.Meta.AppInfo
|
||||
data["OptionalConfig"] = found.Meta.OptionalConfig
|
||||
data["CurrentValues"] = currentValues
|
||||
data["HasAppInfo"] = found.Meta.HasAppInfo()
|
||||
data["HasOptionalConfig"] = found.Meta.HasOptionalConfig()
|
||||
|
||||
s.render(w, "app_info", data)
|
||||
}
|
||||
Reference in New Issue
Block a user