Adds a new Stacks feature: upload/edit docker-compose YAML, deploy as atomic units, browse revisions, roll back, and stream logs. Backend in internal/stack + internal/api/stacks.go, persistent storage in internal/store/stacks.go. Stacks pages (list, new, detail) use a modern Forge aesthetic — Instrument Serif display type, JetBrains Mono for meta/code, indigo ember accents, dot-grid hero, registration marks on hover, terminal panel for logs. Palette is sourced from the app's existing design tokens so the feature remains consistent with the rest of Tinyforge. Fonts self-hosted via @fontsource/instrument-serif and @fontsource/jetbrains-mono to satisfy the strict CSP.
This commit is contained in:
@@ -0,0 +1,38 @@
|
||||
package stack
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// parsePsOutput handles both formats emitted by `docker compose ps --format json`:
|
||||
// newer versions emit NDJSON (one object per line); older versions emit a single JSON array.
|
||||
func parsePsOutput(out string) []Service {
|
||||
out = strings.TrimSpace(out)
|
||||
if out == "" {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Array form.
|
||||
if strings.HasPrefix(out, "[") {
|
||||
var arr []Service
|
||||
if err := json.Unmarshal([]byte(out), &arr); err == nil {
|
||||
return arr
|
||||
}
|
||||
}
|
||||
|
||||
// NDJSON form: one object per line.
|
||||
var services []Service
|
||||
for _, line := range strings.Split(out, "\n") {
|
||||
line = strings.TrimSpace(line)
|
||||
if line == "" || !strings.HasPrefix(line, "{") {
|
||||
continue
|
||||
}
|
||||
var svc Service
|
||||
if err := json.Unmarshal([]byte(line), &svc); err != nil {
|
||||
continue
|
||||
}
|
||||
services = append(services, svc)
|
||||
}
|
||||
return services
|
||||
}
|
||||
Reference in New Issue
Block a user