This repository has been archived on 2026-04-03. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
core/server/pages/pages_surfaces.go
Jeffrey Smith 57c981d52d Clean up dead Go code in handlers, pages, and stores
- Remove "chat" from surface disable guard (only admin needs it)
- Remove "chat" from IsSurfaceEnabled always-on check
- Remove unused fmt.Sprintf references in team stores
- Update stale comments referencing personas and chat surfaces

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-27 13:06:07 +00:00

166 lines
5.0 KiB
Go

package pages
import (
"context"
"log"
"net/http"
"github.com/gin-gonic/gin"
)
// SeedSurfaces writes core surface manifests to the registry table.
// Called once at startup. Does NOT overwrite the enabled flag — admin
// toggles survive restarts.
func (e *Engine) SeedSurfaces() {
if e.stores.Packages == nil {
log.Printf("[pages] Surface registry not available — skipping seed")
return
}
ctx := context.Background()
for _, s := range e.surfaces {
manifest := map[string]any{
"route": s.Route,
"alt_routes": s.AltRoutes,
"template": s.Template,
"components": s.Components,
"data_requires": s.DataRequires,
"auth": s.Auth,
"layout": s.Layout,
}
if err := e.stores.Packages.Seed(ctx, s.ID, s.Title, s.Source, manifest); err != nil {
log.Printf("[pages] Failed to seed surface %q: %v", s.ID, err)
}
}
log.Printf("[pages] Seeded %d core surfaces into registry", len(e.surfaces))
// v0.31.0: Clean up old "editor" core surface row.
// Editor is now an installable package — the old seed row would show a
// broken nav link until the package .pkg is uploaded via admin UI.
if sr, err := e.stores.Packages.Get(ctx, "editor"); err == nil && sr != nil && sr.Source == "extension" {
if sr.Type == "" || sr.Type == "surface" {
if delErr := e.stores.Packages.Delete(ctx, "editor"); delErr != nil {
log.Printf("[pages] Failed to clean up old editor surface: %v", delErr)
} else {
log.Printf("[pages] Cleaned up old editor core surface — install editor .pkg via admin UI")
}
}
}
}
// IsSurfaceEnabled checks if a surface is enabled in the registry.
// Admin is always enabled (system-critical).
// Returns true if the surface is not found (fail-open for backward compat).
func (e *Engine) IsSurfaceEnabled(surfaceID string) bool {
if surfaceID == "admin" {
return true
}
if e.stores.Packages == nil {
return true // No registry = all surfaces enabled (backward compat)
}
ctx := context.Background()
sr, err := e.stores.Packages.Get(ctx, surfaceID)
if err != nil || sr == nil {
return true // Not in registry = assume enabled (backward compat)
}
return sr.Enabled
}
// EnabledSurfaceIDs returns a list of enabled surface IDs for nav rendering.
func (e *Engine) EnabledSurfaceIDs() []string {
if e.stores.Packages == nil {
// No registry — return all core surface IDs
var all []string
for _, s := range e.surfaces {
all = append(all, s.ID)
}
return all
}
ctx := context.Background()
ids, err := e.stores.Packages.ListEnabled(ctx)
if err != nil {
log.Printf("[pages] Failed to load enabled surfaces: %v", err)
// Fallback: return all core surface IDs
var all []string
for _, s := range e.surfaces {
all = append(all, s.ID)
}
return all
}
return ids
}
// DefaultSurfaceRedirect returns a handler for GET / that redirects to the
// configured default surface, falling back to the first enabled extension
// surface, then /admin.
func (e *Engine) DefaultSurfaceRedirect() gin.HandlerFunc {
return func(c *gin.Context) {
target := e.resolveDefaultSurface(c.Request.Context())
c.Redirect(http.StatusTemporaryRedirect, e.cfg.BasePath+target)
}
}
// resolveDefaultSurface returns the path to redirect to (without BasePath).
// Priority: configured default_surface → first enabled extension surface → /admin.
func (e *Engine) resolveDefaultSurface(ctx context.Context) string {
if e.stores.GlobalConfig == nil || e.stores.Packages == nil {
return "/admin"
}
// 1. Check configured default_surface
if raw, err := e.stores.GlobalConfig.Get(ctx, "default_surface"); err == nil && raw != nil {
if id, ok := raw["id"].(string); ok && id != "" {
if path := e.surfacePath(ctx, id); path != "" {
return path
}
// Configured surface is missing or disabled — fall through
}
}
// 2. First enabled extension surface
surfaces, err := e.stores.Packages.ListEnabledByType(ctx, "surface")
if err == nil {
for _, s := range surfaces {
if s.Source == "core" {
continue
}
if s.Enabled {
return "/s/" + s.ID
}
}
}
// 3. Fallback
return "/admin"
}
// surfacePath returns the URL path for a surface ID, or "" if the surface
// doesn't exist or is disabled.
func (e *Engine) surfacePath(ctx context.Context, id string) string {
pkg, err := e.stores.Packages.Get(ctx, id)
if err != nil || pkg == nil || !pkg.Enabled {
return ""
}
// Core surfaces live at /{id}, extension surfaces at /s/{slug}
if pkg.Source == "core" {
// Look up the core surface's base route
if sm := e.GetSurface(id); sm != nil {
// Use the first alt route (without params) or strip params from Route
if len(sm.AltRoutes) > 0 {
return sm.AltRoutes[0]
}
}
return "/" + id
}
return "/s/" + id
}
// disabledRedirect returns a handler that redirects to /admin.
// Uses /admin (not /) to avoid a redirect loop when the default surface
// is the one being disabled.
func (e *Engine) disabledRedirect() gin.HandlerFunc {
return func(c *gin.Context) {
c.Redirect(http.StatusTemporaryRedirect, e.cfg.BasePath+"/admin")
}
}