catalog: the lifecycle implementation itself (fixes the previous commit)

The previous commit landed only the new test/badge files: a 'git stash' used
to compare REUSE.md ref-check output silently dropped the staged index, so
every modification to an existing file was left behind and that commit does
not build. This adds the metadata field, the predicates, the fail-closed
deploy gate, the catalog filter, the funcmap entries, the template edits and
the docs that those tests exercise.
This commit is contained in:
2026-07-21 16:20:24 +02:00
parent ea0d3f1764
commit 5fdd2039fd
11 changed files with 213 additions and 5 deletions
+22 -1
View File
@@ -211,9 +211,30 @@ func (s *Server) dashboardHandler(w http.ResponseWriter, r *http.Request) {
s.executeTemplate(w, r, "dashboard", data)
}
// visibleCatalogStacks drops templates that are no longer OFFERED for new installs (lifecycle
// `hidden` or `abandoned`) AND are not deployed on this box.
//
// The `Deployed || Protected` half is the load-bearing part: a customer already running an app must
// keep seeing and managing it, whatever the catalog now says about offering it to new customers.
// Withdrawing an app must never take a working app away from someone — that is precisely the failure
// the short-lived `retired/` directory move would have caused, and why lifecycle is a metadata field
// rather than a deletion.
//
// Filtered here, in the handler, rather than in the template: the template already carries five
// conditional badges per card, and a visibility rule buried among them is a rule nobody can test.
func visibleCatalogStacks(in []stacks.Stack) []stacks.Stack {
out := make([]stacks.Stack, 0, len(in))
for _, st := range in {
if st.Deployed || st.Protected || st.Meta.CanInstall() {
out = append(out, st)
}
}
return out
}
func (s *Server) stacksHandler(w http.ResponseWriter, r *http.Request) {
data := s.baseData("stacks", "Alkalmazások")
allStacks := s.stackMgr.GetStacks()
allStacks := visibleCatalogStacks(s.stackMgr.GetStacks())
data["Stacks"] = allStacks
data["MissingStorage"] = s.missingStorageMap(allStacks)
nw, ns := s.networkStorageWarnings(allStacks) // NAS unreachable (recoverable) / guest-side stub (defect)