feat: update auto render
This commit is contained in:
247
internal/template/config_loader.go
Normal file
247
internal/template/config_loader.go
Normal file
@@ -0,0 +1,247 @@
|
||||
package template
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log/slog"
|
||||
|
||||
"github.com/spf13/viper"
|
||||
)
|
||||
|
||||
// ConfigLoader loads template configuration from YAML files
|
||||
type ConfigLoader struct {
|
||||
configPath string
|
||||
logger *slog.Logger
|
||||
}
|
||||
|
||||
// NewConfigLoader creates a new template config loader
|
||||
func NewConfigLoader(configPath string) *ConfigLoader {
|
||||
return &ConfigLoader{
|
||||
configPath: configPath,
|
||||
logger: slog.With("component", "template_config"),
|
||||
}
|
||||
}
|
||||
|
||||
// TemplateConfigFile represents the structure of template configuration file
|
||||
type TemplateConfigFile struct {
|
||||
Templates map[string]struct {
|
||||
Name string `yaml:"name"`
|
||||
Type string `yaml:"type"`
|
||||
Description string `yaml:"description"`
|
||||
Fields map[string]string `yaml:"fields"`
|
||||
Config map[string]interface{} `yaml:"config"`
|
||||
} `yaml:"templates"`
|
||||
TemplateTypes map[string]struct {
|
||||
Layout string `yaml:"layout"`
|
||||
Fields map[string]string `yaml:"fields"`
|
||||
Options map[string]interface{} `yaml:"options"`
|
||||
} `yaml:"template_types"`
|
||||
}
|
||||
|
||||
|
||||
|
||||
// LoadTemplateConfig loads template configuration from YAML files
|
||||
func (cl *ConfigLoader) LoadTemplateConfig() (*TemplateConfigFile, error) {
|
||||
viper.SetConfigName("templates")
|
||||
viper.SetConfigType("yaml")
|
||||
|
||||
// Add search paths
|
||||
viper.AddConfigPath(cl.configPath)
|
||||
viper.AddConfigPath("./config/templates")
|
||||
viper.AddConfigPath("./web/templates")
|
||||
viper.AddConfigPath("/etc/database-render/templates")
|
||||
|
||||
// Set default values
|
||||
viper.SetDefault("templates", map[string]interface{}{})
|
||||
viper.SetDefault("template_types", map[string]interface{}{
|
||||
"list": map[string]interface{}{
|
||||
"layout": "table",
|
||||
"fields": map[string]string{
|
||||
"default": "raw",
|
||||
"time": "time",
|
||||
"tag": "tag",
|
||||
},
|
||||
"options": map[string]interface{}{
|
||||
"striped": true,
|
||||
"hover": true,
|
||||
},
|
||||
},
|
||||
"card": map[string]interface{}{
|
||||
"layout": "grid",
|
||||
"fields": map[string]string{
|
||||
"default": "raw",
|
||||
"time": "relative",
|
||||
"tag": "badge",
|
||||
},
|
||||
"options": map[string]interface{}{
|
||||
"columns": "3",
|
||||
"spacing": "md",
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
// Read configuration
|
||||
if err := viper.ReadInConfig(); err != nil {
|
||||
if _, ok := err.(viper.ConfigFileNotFoundError); ok {
|
||||
cl.logger.Warn("template config file not found, using defaults")
|
||||
return cl.createDefaultConfig(), nil
|
||||
}
|
||||
return nil, fmt.Errorf("failed to read template config: %w", err)
|
||||
}
|
||||
|
||||
var config TemplateConfigFile
|
||||
if err := viper.Unmarshal(&config); err != nil {
|
||||
return nil, fmt.Errorf("failed to unmarshal template config: %w", err)
|
||||
}
|
||||
|
||||
cl.logger.Info("template configuration loaded successfully",
|
||||
"config_file", viper.ConfigFileUsed(),
|
||||
"templates_count", len(config.Templates),
|
||||
"types_count", len(config.TemplateTypes))
|
||||
|
||||
return &config, nil
|
||||
}
|
||||
|
||||
// createDefaultConfig creates default template configuration
|
||||
func (cl *ConfigLoader) createDefaultConfig() *TemplateConfigFile {
|
||||
return &TemplateConfigFile{
|
||||
Templates: map[string]struct {
|
||||
Name string `yaml:"name"`
|
||||
Type string `yaml:"type"`
|
||||
Description string `yaml:"description"`
|
||||
Fields map[string]string `yaml:"fields"`
|
||||
Config map[string]interface{} `yaml:"config"`
|
||||
}{
|
||||
"articles": {
|
||||
Name: "文章列表",
|
||||
Type: "list",
|
||||
Description: "技术文章列表视图",
|
||||
Fields: map[string]string{
|
||||
"title": "string",
|
||||
"content": "markdown",
|
||||
"category": "category",
|
||||
"tags": "tag",
|
||||
"created_at": "time",
|
||||
},
|
||||
Config: map[string]interface{}{
|
||||
"page_size": 15,
|
||||
"show_pagination": true,
|
||||
},
|
||||
},
|
||||
"logs": {
|
||||
Name: "系统日志",
|
||||
Type: "table",
|
||||
Description: "系统日志表格视图",
|
||||
Fields: map[string]string{
|
||||
"level": "tag",
|
||||
"message": "string",
|
||||
"timestamp": "time",
|
||||
},
|
||||
Config: map[string]interface{}{
|
||||
"page_size": 50,
|
||||
"show_filter": true,
|
||||
},
|
||||
},
|
||||
},
|
||||
TemplateTypes: map[string]struct {
|
||||
Layout string `yaml:"layout"`
|
||||
Fields map[string]string `yaml:"fields"`
|
||||
Options map[string]interface{} `yaml:"options"`
|
||||
}{
|
||||
"list": {
|
||||
Layout: "table",
|
||||
Fields: map[string]string{
|
||||
"default": "raw",
|
||||
"time": "time",
|
||||
"tag": "tag",
|
||||
},
|
||||
Options: map[string]interface{}{
|
||||
"striped": true,
|
||||
"hover": true,
|
||||
},
|
||||
},
|
||||
"card": {
|
||||
Layout: "grid",
|
||||
Fields: map[string]string{
|
||||
"default": "raw",
|
||||
"time": "relative",
|
||||
"tag": "badge",
|
||||
},
|
||||
Options: map[string]interface{}{
|
||||
"columns": "3",
|
||||
"spacing": "md",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// ValidateTemplateConfig validates template configuration
|
||||
func (cl *ConfigLoader) ValidateTemplateConfig(config *TemplateConfigFile) error {
|
||||
for name, template := range config.Templates {
|
||||
if template.Name == "" {
|
||||
return fmt.Errorf("template %s: name cannot be empty", name)
|
||||
}
|
||||
if template.Type == "" {
|
||||
return fmt.Errorf("template %s: type cannot be empty", name)
|
||||
}
|
||||
}
|
||||
|
||||
for name, templateType := range config.TemplateTypes {
|
||||
if templateType.Layout == "" {
|
||||
return fmt.Errorf("template type %s: layout cannot be empty", name)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetTemplateConfig returns template configuration for a specific table
|
||||
func (cl *ConfigLoader) GetTemplateConfig(tableName string) (interface{}, bool) {
|
||||
config, err := cl.LoadTemplateConfig()
|
||||
if err != nil {
|
||||
cl.logger.Error("failed to load template config", "error", err)
|
||||
return nil, false
|
||||
}
|
||||
|
||||
template, exists := config.Templates[tableName]
|
||||
return template, exists
|
||||
}
|
||||
|
||||
// GetTemplateType returns template type configuration
|
||||
func (cl *ConfigLoader) GetTemplateType(typeName string) (interface{}, bool) {
|
||||
config, err := cl.LoadTemplateConfig()
|
||||
if err != nil {
|
||||
cl.logger.Error("failed to load template config", "error", err)
|
||||
return nil, false
|
||||
}
|
||||
|
||||
typeConfig, exists := config.TemplateTypes[typeName]
|
||||
return typeConfig, exists
|
||||
}
|
||||
|
||||
// GetAvailableTemplates returns all available templates
|
||||
func (cl *ConfigLoader) GetAvailableTemplates() map[string]string {
|
||||
config, err := cl.LoadTemplateConfig()
|
||||
if err != nil {
|
||||
cl.logger.Error("failed to load template config", "error", err)
|
||||
return map[string]string{"list": "默认列表"}
|
||||
}
|
||||
|
||||
result := make(map[string]string)
|
||||
for key, template := range config.Templates {
|
||||
result[key] = template.Description
|
||||
}
|
||||
|
||||
// Add built-in templates if not overridden
|
||||
if _, exists := result["list"]; !exists {
|
||||
result["list"] = "列表视图"
|
||||
}
|
||||
if _, exists := result["card"]; !exists {
|
||||
result["card"] = "卡片视图"
|
||||
}
|
||||
if _, exists := result["timeline"]; !exists {
|
||||
result["timeline"] = "时间轴视图"
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
Reference in New Issue
Block a user