152 lines
5.2 KiB
Go
152 lines
5.2 KiB
Go
package ui
|
|
|
|
import (
|
|
"fmt"
|
|
"log"
|
|
"os"
|
|
"path/filepath"
|
|
"regexp"
|
|
"strings"
|
|
|
|
"git.ourworld.tf/herocode/heroagent/pkg/servers/ui/routes" // Import the routes package
|
|
"github.com/gofiber/fiber/v2"
|
|
jetadapter "github.com/gofiber/template/jet/v2" // Aliased for clarity
|
|
)
|
|
|
|
// AppConfig holds the configuration for the UI application.
|
|
type AppConfig struct {
|
|
// Any specific configurations can be added here later
|
|
}
|
|
|
|
// NewApp creates and configures a new Fiber application for the UI.
|
|
func NewApp(config AppConfig) *fiber.App {
|
|
// Initialize Jet template engine
|
|
// Using OSFileSystemLoader to load templates from the filesystem.
|
|
// The path is relative to where the application is run.
|
|
// Get current working directory and construct absolute path to views
|
|
cwd, err := os.Getwd()
|
|
if err != nil {
|
|
panic("Failed to get current working directory: " + err.Error())
|
|
}
|
|
viewsPath := filepath.Join(cwd, "pkg", "servers", "ui", "views")
|
|
|
|
// Validate that the views directory and key template files exist
|
|
if _, err := os.Stat(viewsPath); os.IsNotExist(err) {
|
|
panic("Views directory does not exist: " + viewsPath)
|
|
}
|
|
|
|
// Check for key template files
|
|
baseLayoutPath := filepath.Join(viewsPath, "layouts", "base.jet")
|
|
dashboardPath := filepath.Join(viewsPath, "pages", "dashboard.jet")
|
|
navbarPath := filepath.Join(viewsPath, "components", "navbar.jet")
|
|
sidebarPath := filepath.Join(viewsPath, "components", "sidebar.jet")
|
|
|
|
requiredFiles := []string{baseLayoutPath, dashboardPath, navbarPath, sidebarPath}
|
|
for _, filePath := range requiredFiles {
|
|
if _, err := os.Stat(filePath); os.IsNotExist(err) {
|
|
panic("Required template file does not exist: " + filePath)
|
|
}
|
|
}
|
|
|
|
// Log the views path for debugging
|
|
println("Views directory found at:", viewsPath)
|
|
println("All required template files exist")
|
|
|
|
// Create Fiber Jet adapter
|
|
engine := jetadapter.New(viewsPath, ".jet")
|
|
|
|
// Enable template reloading for development
|
|
engine.Reload(true)
|
|
|
|
// No custom functions for now
|
|
|
|
// Create a new Fiber app with the configured Jet engine and enhanced error handling
|
|
app := fiber.New(fiber.Config{
|
|
Views: engine,
|
|
ErrorHandler: func(c *fiber.Ctx, err error) error {
|
|
// Log the detailed error
|
|
log.Printf("ERROR: %v", err)
|
|
|
|
// Check if it's a template rendering error
|
|
if err.Error() != "" && (c.Route().Path != "" && c.Method() == "GET") {
|
|
// Extract template name and line number from error message
|
|
errorMsg := err.Error()
|
|
templateInfo := "Unknown template"
|
|
lineInfo := "Unknown line"
|
|
variableInfo := "Unknown variable"
|
|
|
|
// Try to extract template name and line number
|
|
if strings.Contains(errorMsg, "Jet Runtime Error") {
|
|
// Extract template and line number
|
|
templateLineRegex := regexp.MustCompile(`"([^"]+)":(\d+)`)
|
|
templateMatches := templateLineRegex.FindStringSubmatch(errorMsg)
|
|
if len(templateMatches) >= 3 {
|
|
templateInfo = templateMatches[1]
|
|
lineInfo = templateMatches[2]
|
|
}
|
|
|
|
// Extract variable name
|
|
varRegex := regexp.MustCompile(`there is no field or method '([^']+)'`)
|
|
varMatches := varRegex.FindStringSubmatch(errorMsg)
|
|
if len(varMatches) >= 2 {
|
|
variableInfo = varMatches[1]
|
|
}
|
|
|
|
// Log more detailed information
|
|
log.Printf("Template Error Details - Template: %s, Line: %s, Variable: %s",
|
|
templateInfo, lineInfo, variableInfo)
|
|
}
|
|
|
|
// Create a more detailed error page
|
|
errorHTML := fmt.Sprintf(`
|
|
<html>
|
|
<head>
|
|
<title>Template Error</title>
|
|
<style>
|
|
body { font-family: Arial, sans-serif; margin: 20px; }
|
|
.error-box { background-color: #f8d7da; border: 1px solid #f5c6cb; padding: 15px; border-radius: 5px; }
|
|
.error-details { background-color: #f8f9fa; border: 1px solid #dee2e6; padding: 15px; border-radius: 5px; margin-top: 20px; }
|
|
.code-context { background-color: #f0f0f0; padding: 10px; border-radius: 5px; font-family: monospace; }
|
|
pre { white-space: pre-wrap; }
|
|
.highlight { background-color: #ffeb3b; font-weight: bold; }
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<h1>Template Error</h1>
|
|
<div class="error-box">
|
|
<h3>Error Details:</h3>
|
|
<p><strong>Template:</strong> %s</p>
|
|
<p><strong>Line:</strong> %s</p>
|
|
<p><strong>Missing Variable:</strong> <span class="highlight">%s</span></p>
|
|
<pre>%s</pre>
|
|
</div>
|
|
<div class="error-details">
|
|
<h3>Debugging Tips:</h3>
|
|
<p>1. Check if the variable <span class="highlight">%s</span> is passed to the template</p>
|
|
<p>2. Visit <a href="/debug">/debug</a> to see available template variables</p>
|
|
<p>3. Check for typos in variable names</p>
|
|
<p>4. Ensure the variable is of the expected type</p>
|
|
<p>5. Check the controller that renders this template to ensure all required data is provided</p>
|
|
</div>
|
|
</body>
|
|
</html>
|
|
`, templateInfo, lineInfo, variableInfo, errorMsg, variableInfo)
|
|
|
|
return c.Status(fiber.StatusInternalServerError).Type("html").SendString(errorHTML)
|
|
}
|
|
|
|
// For other errors, use the default error handler
|
|
return fiber.DefaultErrorHandler(c, err)
|
|
},
|
|
})
|
|
|
|
// Setup static file serving
|
|
// Files in ./pkg/servers/ui/static will be accessible via /static URL path
|
|
app.Static("/static", "./pkg/servers/ui/static")
|
|
|
|
// Setup routes
|
|
routes.SetupRoutes(app)
|
|
|
|
return app
|
|
}
|