KAOS/code/internal/server/render.go
djuka 10c510d9ef T19: Dugme Pusti na task karticama sa pokretanjem u čistoj sesiji
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-20 12:59:41 +00:00

184 lines
4.5 KiB
Go

package server
import (
"bytes"
"html/template"
"strings"
"github.com/dal/kaos/internal/supervisor"
"github.com/dal/kaos/web"
)
// taskCardData wraps a task with UI display info.
type taskCardData struct {
supervisor.Task
CanRun bool
}
// columnData holds data for rendering a single kanban column.
type columnData struct {
Name string
Label string
Icon string
Count int
Tasks []taskCardData
}
// dashboardData holds data for the full dashboard page.
type dashboardData struct {
Columns []columnData
}
// taskDetailData holds data for the task detail panel.
type taskDetailData struct {
Task supervisor.Task
Content string
HasReport bool
}
// statusIcons maps folder names to emoji icons.
var statusIcons = map[string]string{
"backlog": "📦",
"ready": "📋",
"active": "🔄",
"review": "👀",
"done": "✅",
}
// columnOrder defines the display order of columns.
var columnOrder = []string{"backlog", "ready", "active", "review", "done"}
// templateFuncs provides custom functions for templates.
var templateFuncs = template.FuncMap{
"joinDeps": func(deps []string) string {
return strings.Join(deps, ", ")
},
}
// templates holds the parsed template set.
var templates *template.Template
func init() {
templates = template.Must(
template.New("").Funcs(templateFuncs).ParseFS(
web.TemplatesFS,
"templates/layout.html",
"templates/dashboard.html",
"templates/docs-list.html",
"templates/docs-view.html",
"templates/console.html",
"templates/partials/column.html",
"templates/partials/task-card.html",
"templates/partials/task-detail.html",
"templates/partials/search-results.html",
),
)
}
// renderDashboard generates the full dashboard HTML page.
func renderDashboard(columns map[string][]supervisor.Task) string {
// Build set of done task IDs for dependency checking
doneSet := make(map[string]bool)
for _, t := range columns["done"] {
doneSet[t.ID] = true
}
data := dashboardData{}
for _, col := range columnOrder {
tasks := columns[col]
cards := make([]taskCardData, len(tasks))
for i, t := range tasks {
cards[i] = taskCardData{
Task: t,
CanRun: canRunTask(t, doneSet),
}
}
data.Columns = append(data.Columns, columnData{
Name: col,
Label: strings.ToUpper(col),
Icon: statusIcons[col],
Count: len(tasks),
Tasks: cards,
})
}
var buf bytes.Buffer
if err := templates.ExecuteTemplate(&buf, "layout.html", data); err != nil {
return "Greška pri renderovanju: " + err.Error()
}
return buf.String()
}
// canRunTask determines if a task can be run via the "Pusti" button.
func canRunTask(t supervisor.Task, doneSet map[string]bool) bool {
switch t.Status {
case "ready":
return true
case "backlog":
// Only if all dependencies are done
for _, dep := range t.DependsOn {
if !doneSet[dep] {
return false
}
}
return true
case "review":
// Only if Description contains non-empty answers
// (simplified: review tasks with content can be re-run)
return true
default:
return false
}
}
// renderDocsList generates the docs listing HTML page.
func renderDocsList(data docsListData) string {
var buf bytes.Buffer
if err := templates.ExecuteTemplate(&buf, "docs-list", data); err != nil {
return "Greška pri renderovanju: " + err.Error()
}
return buf.String()
}
// renderDocsView generates the docs view HTML page.
func renderDocsView(data docsViewData) string {
var buf bytes.Buffer
if err := templates.ExecuteTemplate(&buf, "docs-view", data); err != nil {
return "Greška pri renderovanju: " + err.Error()
}
return buf.String()
}
// renderConsolePage generates the console HTML page.
func renderConsolePage() string {
var buf bytes.Buffer
if err := templates.ExecuteTemplate(&buf, "console", nil); err != nil {
return "Greška pri renderovanju: " + err.Error()
}
return buf.String()
}
// renderSearchResults generates the search results HTML fragment.
func renderSearchResults(data searchResultsData) string {
var buf bytes.Buffer
if err := templates.ExecuteTemplate(&buf, "search-results", data); err != nil {
return "Greška pri renderovanju: " + err.Error()
}
return buf.String()
}
// renderTaskDetail generates HTML fragment for task detail panel.
func renderTaskDetail(t supervisor.Task, content string, hasReport bool) string {
data := taskDetailData{
Task: t,
Content: content,
HasReport: hasReport,
}
var buf bytes.Buffer
if err := templates.ExecuteTemplate(&buf, "task-detail", data); err != nil {
return "Greška pri renderovanju: " + err.Error()
}
return buf.String()
}