135 lines
2.9 KiB
Go
135 lines
2.9 KiB
Go
package templates
|
|
|
|
import (
|
|
"encoding/json"
|
|
"fmt"
|
|
"sort"
|
|
"sync"
|
|
)
|
|
|
|
// Registry holds all available templates (system + user overrides).
|
|
type Registry struct {
|
|
mu sync.RWMutex
|
|
templates map[string]*Template
|
|
}
|
|
|
|
func NewRegistry() *Registry {
|
|
return &Registry{templates: make(map[string]*Template)}
|
|
}
|
|
|
|
// LoadSystem reads system templates from embedded JSON.
|
|
func (r *Registry) LoadSystem() error {
|
|
data, err := systemTemplatesFS.ReadFile("system_templates.json")
|
|
if err != nil {
|
|
return err
|
|
}
|
|
var sysTemplates []Template
|
|
if err := json.Unmarshal(data, &sysTemplates); err != nil {
|
|
return err
|
|
}
|
|
r.mu.Lock()
|
|
defer r.mu.Unlock()
|
|
for _, t := range sysTemplates {
|
|
cp := t
|
|
r.templates[t.ID] = &cp
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// Get returns a template by ID.
|
|
func (r *Registry) Get(id string) (*Template, bool) {
|
|
r.mu.RLock()
|
|
defer r.mu.RUnlock()
|
|
t, ok := r.templates[id]
|
|
return t, ok
|
|
}
|
|
|
|
// Enabled returns all enabled templates sorted by type+id.
|
|
func (r *Registry) Enabled() []*Template {
|
|
r.mu.RLock()
|
|
defer r.mu.RUnlock()
|
|
var result []*Template
|
|
for _, t := range r.templates {
|
|
if t.Enabled {
|
|
result = append(result, t)
|
|
}
|
|
}
|
|
sort.Slice(result, func(i, j int) bool {
|
|
if result[i].Type != result[j].Type {
|
|
return result[i].Type < result[j].Type
|
|
}
|
|
return result[i].ID < result[j].ID
|
|
})
|
|
return result
|
|
}
|
|
|
|
// All returns all registered templates sorted by type+id.
|
|
func (r *Registry) All() []*Template {
|
|
r.mu.RLock()
|
|
defer r.mu.RUnlock()
|
|
return sortedCopy(r.templates)
|
|
}
|
|
|
|
func sortedCopy(templates map[string]*Template) []*Template {
|
|
result := make([]*Template, 0, len(templates))
|
|
for _, t := range templates {
|
|
result = append(result, t)
|
|
}
|
|
sort.Slice(result, func(i, j int) bool {
|
|
if result[i].Type != result[j].Type {
|
|
return result[i].Type < result[j].Type
|
|
}
|
|
return result[i].ID < result[j].ID
|
|
})
|
|
return result
|
|
}
|
|
|
|
// EnabledForParent returns templates that are allowed for a given parent type.
|
|
func (r *Registry) EnabledForParent(parentType string) []*Template {
|
|
r.mu.RLock()
|
|
defer r.mu.RUnlock()
|
|
var result []*Template
|
|
for _, t := range r.templates {
|
|
if !t.Enabled {
|
|
continue
|
|
}
|
|
for _, allowed := range t.AllowedParentTypes {
|
|
if allowed == "*" || allowed == parentType {
|
|
result = append(result, t)
|
|
break
|
|
}
|
|
}
|
|
}
|
|
sort.Slice(result, func(i, j int) bool {
|
|
if result[i].Type != result[j].Type {
|
|
return result[i].Type < result[j].Type
|
|
}
|
|
return result[i].ID < result[j].ID
|
|
})
|
|
return result
|
|
}
|
|
|
|
// Enable enables a template by ID.
|
|
func (r *Registry) Enable(id string) error {
|
|
r.mu.Lock()
|
|
defer r.mu.Unlock()
|
|
t, ok := r.templates[id]
|
|
if !ok {
|
|
return fmt.Errorf("template %q not found", id)
|
|
}
|
|
t.Enabled = true
|
|
return nil
|
|
}
|
|
|
|
// Disable disables a template by ID.
|
|
func (r *Registry) Disable(id string) error {
|
|
r.mu.Lock()
|
|
defer r.mu.Unlock()
|
|
t, ok := r.templates[id]
|
|
if !ok {
|
|
return fmt.Errorf("template %q not found", id)
|
|
}
|
|
t.Enabled = false
|
|
return nil
|
|
}
|