diff --git a/pkg/web/components/issue.templ b/pkg/web/components/issue.templ
new file mode 100644
index 0000000..b8bcc23
--- /dev/null
+++ b/pkg/web/components/issue.templ
@@ -0,0 +1,109 @@
+package components
+
+import (
+ "github.com/LazyBachelor/LazyPM/internal/models"
+ "github.com/LazyBachelor/LazyPM/pkg/web/components/base"
+)
+
+type IssueFormProps struct {
+ Action string
+ Title string
+ Description string
+ Status string
+ Priority int
+ IssueType string
+ Class string
+ Attrs templ.Attributes
+}
+
+templ IssueForm(props IssueFormProps) {
+
+}
+
+type IssueTableProps struct {
+ Issues []*models.Issue
+}
+
+templ IssueTable(props IssueTableProps) {
+ @base.Table(
+ []templ.Component{
+ base.PlainText("ID"),
+ base.PlainText("Title"),
+ base.PlainText("Status"),
+ base.PlainText("Type"),
+ base.PlainText("Priority"),
+ },
+ []templ.Component{
+ IssueRows(props.Issues),
+ },
+ templ.Attributes{},
+ )
+}
+
+templ IssueRows(issues []*models.Issue) {
+ for _, issue := range issues {
+
+ | { issue.ID } |
+ { issue.Title } |
+ { issue.Status } |
+ { issue.IssueType } |
+ { issue.Priority } |
+
+ }
+}
diff --git a/pkg/web/components/issue_templ.go b/pkg/web/components/issue_templ.go
new file mode 100644
index 0000000..0a4e123
--- /dev/null
+++ b/pkg/web/components/issue_templ.go
@@ -0,0 +1,298 @@
+// Code generated by templ - DO NOT EDIT.
+
+// templ: version: v0.3.977
+package components
+
+//lint:file-ignore SA4006 This context is only used if a nested component is present.
+
+import "github.com/a-h/templ"
+import templruntime "github.com/a-h/templ/runtime"
+
+import (
+ "github.com/LazyBachelor/LazyPM/internal/models"
+ "github.com/LazyBachelor/LazyPM/pkg/web/components/base"
+)
+
+type IssueFormProps struct {
+ Action string
+ Title string
+ Description string
+ Status string
+ Priority int
+ IssueType string
+ Class string
+ Attrs templ.Attributes
+}
+
+func IssueForm(props IssueFormProps) templ.Component {
+ return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
+ templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
+ if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil {
+ return templ_7745c5c3_CtxErr
+ }
+ templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W)
+ if !templ_7745c5c3_IsBuffer {
+ defer func() {
+ templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer)
+ if templ_7745c5c3_Err == nil {
+ templ_7745c5c3_Err = templ_7745c5c3_BufErr
+ }
+ }()
+ }
+ ctx = templ.InitializeContext(ctx)
+ templ_7745c5c3_Var1 := templ.GetChildren(ctx)
+ if templ_7745c5c3_Var1 == nil {
+ templ_7745c5c3_Var1 = templ.NopComponent
+ }
+ ctx = templ.ClearChildren(ctx)
+ var templ_7745c5c3_Var2 = []any{"w-full max-w-xs mx-auto ", props.Class}
+ templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var2...)
+ if templ_7745c5c3_Err != nil {
+ return templ_7745c5c3_Err
+ }
+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 1, "")
+ if templ_7745c5c3_Err != nil {
+ return templ_7745c5c3_Err
+ }
+ return nil
+ })
+}
+
+type IssueTableProps struct {
+ Issues []*models.Issue
+}
+
+func IssueTable(props IssueTableProps) templ.Component {
+ return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
+ templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
+ if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil {
+ return templ_7745c5c3_CtxErr
+ }
+ templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W)
+ if !templ_7745c5c3_IsBuffer {
+ defer func() {
+ templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer)
+ if templ_7745c5c3_Err == nil {
+ templ_7745c5c3_Err = templ_7745c5c3_BufErr
+ }
+ }()
+ }
+ ctx = templ.InitializeContext(ctx)
+ templ_7745c5c3_Var5 := templ.GetChildren(ctx)
+ if templ_7745c5c3_Var5 == nil {
+ templ_7745c5c3_Var5 = templ.NopComponent
+ }
+ ctx = templ.ClearChildren(ctx)
+ templ_7745c5c3_Err = base.Table(
+ []templ.Component{
+ base.PlainText("ID"),
+ base.PlainText("Title"),
+ base.PlainText("Status"),
+ base.PlainText("Type"),
+ base.PlainText("Priority"),
+ },
+ []templ.Component{
+ IssueRows(props.Issues),
+ },
+ templ.Attributes{},
+ ).Render(ctx, templ_7745c5c3_Buffer)
+ if templ_7745c5c3_Err != nil {
+ return templ_7745c5c3_Err
+ }
+ return nil
+ })
+}
+
+func IssueRows(issues []*models.Issue) templ.Component {
+ return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
+ templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
+ if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil {
+ return templ_7745c5c3_CtxErr
+ }
+ templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W)
+ if !templ_7745c5c3_IsBuffer {
+ defer func() {
+ templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer)
+ if templ_7745c5c3_Err == nil {
+ templ_7745c5c3_Err = templ_7745c5c3_BufErr
+ }
+ }()
+ }
+ ctx = templ.InitializeContext(ctx)
+ templ_7745c5c3_Var6 := templ.GetChildren(ctx)
+ if templ_7745c5c3_Var6 == nil {
+ templ_7745c5c3_Var6 = templ.NopComponent
+ }
+ ctx = templ.ClearChildren(ctx)
+ for _, issue := range issues {
+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 6, "| ")
+ if templ_7745c5c3_Err != nil {
+ return templ_7745c5c3_Err
+ }
+ var templ_7745c5c3_Var7 string
+ templ_7745c5c3_Var7, templ_7745c5c3_Err = templ.JoinStringErrs(issue.ID)
+ if templ_7745c5c3_Err != nil {
+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `pkg/web/components/issue.templ`, Line: 102, Col: 42}
+ }
+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var7))
+ if templ_7745c5c3_Err != nil {
+ return templ_7745c5c3_Err
+ }
+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 7, " | ")
+ if templ_7745c5c3_Err != nil {
+ return templ_7745c5c3_Err
+ }
+ var templ_7745c5c3_Var8 string
+ templ_7745c5c3_Var8, templ_7745c5c3_Err = templ.JoinStringErrs(issue.Title)
+ if templ_7745c5c3_Err != nil {
+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `pkg/web/components/issue.templ`, Line: 103, Col: 45}
+ }
+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var8))
+ if templ_7745c5c3_Err != nil {
+ return templ_7745c5c3_Err
+ }
+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 8, " | ")
+ if templ_7745c5c3_Err != nil {
+ return templ_7745c5c3_Err
+ }
+ var templ_7745c5c3_Var9 string
+ templ_7745c5c3_Var9, templ_7745c5c3_Err = templ.JoinStringErrs(issue.Status)
+ if templ_7745c5c3_Err != nil {
+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `pkg/web/components/issue.templ`, Line: 104, Col: 46}
+ }
+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var9))
+ if templ_7745c5c3_Err != nil {
+ return templ_7745c5c3_Err
+ }
+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 9, " | ")
+ if templ_7745c5c3_Err != nil {
+ return templ_7745c5c3_Err
+ }
+ var templ_7745c5c3_Var10 string
+ templ_7745c5c3_Var10, templ_7745c5c3_Err = templ.JoinStringErrs(issue.IssueType)
+ if templ_7745c5c3_Err != nil {
+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `pkg/web/components/issue.templ`, Line: 105, Col: 49}
+ }
+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var10))
+ if templ_7745c5c3_Err != nil {
+ return templ_7745c5c3_Err
+ }
+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 10, " | ")
+ if templ_7745c5c3_Err != nil {
+ return templ_7745c5c3_Err
+ }
+ var templ_7745c5c3_Var11 string
+ templ_7745c5c3_Var11, templ_7745c5c3_Err = templ.JoinStringErrs(issue.Priority)
+ if templ_7745c5c3_Err != nil {
+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `pkg/web/components/issue.templ`, Line: 106, Col: 48}
+ }
+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var11))
+ if templ_7745c5c3_Err != nil {
+ return templ_7745c5c3_Err
+ }
+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 11, " |
")
+ if templ_7745c5c3_Err != nil {
+ return templ_7745c5c3_Err
+ }
+ }
+ return nil
+ })
+}
+
+var _ = templruntime.GeneratedTemplate
diff --git a/pkg/web/components/issuelist.templ b/pkg/web/components/issuelist.templ
deleted file mode 100644
index cc97491..0000000
--- a/pkg/web/components/issuelist.templ
+++ /dev/null
@@ -1,19 +0,0 @@
-package components
-
-import "github.com/LazyBachelor/LazyPM/internal/models"
-
-type IssueListProps struct {
- Issues []*models.Issue
-}
-
-templ IssueList(props IssueListProps) {
-
- for _, issue := range props.Issues {
- @IssueListItem(issue)
- }
-
-}
-
-templ IssueListItem(issue *models.Issue) {
- Issue ID: { issue.ID }, Title: { issue.Title }
-}
diff --git a/pkg/web/components/issuelist_templ.go b/pkg/web/components/issuelist_templ.go
deleted file mode 100644
index 860dc69..0000000
--- a/pkg/web/components/issuelist_templ.go
+++ /dev/null
@@ -1,111 +0,0 @@
-// Code generated by templ - DO NOT EDIT.
-
-// templ: version: v0.3.977
-package components
-
-//lint:file-ignore SA4006 This context is only used if a nested component is present.
-
-import "github.com/a-h/templ"
-import templruntime "github.com/a-h/templ/runtime"
-
-import "github.com/LazyBachelor/LazyPM/internal/models"
-
-type IssueListProps struct {
- Issues []*models.Issue
-}
-
-func IssueList(props IssueListProps) templ.Component {
- return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
- templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
- if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil {
- return templ_7745c5c3_CtxErr
- }
- templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W)
- if !templ_7745c5c3_IsBuffer {
- defer func() {
- templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer)
- if templ_7745c5c3_Err == nil {
- templ_7745c5c3_Err = templ_7745c5c3_BufErr
- }
- }()
- }
- ctx = templ.InitializeContext(ctx)
- templ_7745c5c3_Var1 := templ.GetChildren(ctx)
- if templ_7745c5c3_Var1 == nil {
- templ_7745c5c3_Var1 = templ.NopComponent
- }
- ctx = templ.ClearChildren(ctx)
- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 1, "")
- if templ_7745c5c3_Err != nil {
- return templ_7745c5c3_Err
- }
- for _, issue := range props.Issues {
- templ_7745c5c3_Err = IssueListItem(issue).Render(ctx, templ_7745c5c3_Buffer)
- if templ_7745c5c3_Err != nil {
- return templ_7745c5c3_Err
- }
- }
- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 2, "
")
- if templ_7745c5c3_Err != nil {
- return templ_7745c5c3_Err
- }
- return nil
- })
-}
-
-func IssueListItem(issue *models.Issue) templ.Component {
- return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
- templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
- if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil {
- return templ_7745c5c3_CtxErr
- }
- templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W)
- if !templ_7745c5c3_IsBuffer {
- defer func() {
- templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer)
- if templ_7745c5c3_Err == nil {
- templ_7745c5c3_Err = templ_7745c5c3_BufErr
- }
- }()
- }
- ctx = templ.InitializeContext(ctx)
- templ_7745c5c3_Var2 := templ.GetChildren(ctx)
- if templ_7745c5c3_Var2 == nil {
- templ_7745c5c3_Var2 = templ.NopComponent
- }
- ctx = templ.ClearChildren(ctx)
- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 3, "Issue ID: ")
- if templ_7745c5c3_Err != nil {
- return templ_7745c5c3_Err
- }
- var templ_7745c5c3_Var3 string
- templ_7745c5c3_Var3, templ_7745c5c3_Err = templ.JoinStringErrs(issue.ID)
- if templ_7745c5c3_Err != nil {
- return templ.Error{Err: templ_7745c5c3_Err, FileName: `pkg/web/components/issuelist.templ`, Line: 18, Col: 25}
- }
- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var3))
- if templ_7745c5c3_Err != nil {
- return templ_7745c5c3_Err
- }
- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 4, ", Title: ")
- if templ_7745c5c3_Err != nil {
- return templ_7745c5c3_Err
- }
- var templ_7745c5c3_Var4 string
- templ_7745c5c3_Var4, templ_7745c5c3_Err = templ.JoinStringErrs(issue.Title)
- if templ_7745c5c3_Err != nil {
- return templ.Error{Err: templ_7745c5c3_Err, FileName: `pkg/web/components/issuelist.templ`, Line: 18, Col: 49}
- }
- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var4))
- if templ_7745c5c3_Err != nil {
- return templ_7745c5c3_Err
- }
- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 5, "")
- if templ_7745c5c3_Err != nil {
- return templ_7745c5c3_Err
- }
- return nil
- })
-}
-
-var _ = templruntime.GeneratedTemplate
diff --git a/pkg/web/handler/issues.go b/pkg/web/handler/issues.go
index 6beff6a..bbe2fe0 100644
--- a/pkg/web/handler/issues.go
+++ b/pkg/web/handler/issues.go
@@ -2,6 +2,7 @@ package handler
import (
"encoding/json"
+ "fmt"
"net/http"
"github.com/LazyBachelor/LazyPM/internal/models"
@@ -22,25 +23,30 @@ func CreateIssue(svc *service.Services) http.HandlerFunc {
return
}
- var issue models.Issue
-
- err := json.NewDecoder(r.Body).Decode(&issue)
- if err != nil {
- http.Error(w, "Invalid request payload", http.StatusBadRequest)
+ // 1. Parse Form instead of JSON
+ if err := r.ParseForm(); err != nil {
+ http.Error(w, "Failed to parse form", http.StatusBadRequest)
return
}
- defer r.Body.Close()
+ // 2. Map form values to your struct manually
+ // (Or use a library like 'gorilla/schema')
+ issue := models.Issue{
+ Title: r.FormValue("title"),
+ Description: r.FormValue("description"),
+ Status: models.Status(r.FormValue("status")),
+ IssueType: models.IssueType(r.FormValue("issue_type")),
+ }
- err = svc.Beads.CreateIssue(r.Context(), &issue, "")
+ err := svc.Beads.CreateIssue(r.Context(), &issue, "")
if err != nil {
- http.Error(w, "Failed to create issue: "+err.Error(), http.StatusBadRequest)
+ http.Error(w, "Failed to create issue: "+err.Error(), http.StatusInternalServerError)
return
}
- w.Header().Set("Content-Type", "application/json")
- w.WriteHeader(http.StatusCreated)
- json.NewEncoder(w).Encode(issue)
+ // 3. HTMX usually expects HTML back, not JSON
+ w.Header().Set("Content-Type", "text/html")
+ fmt.Fprintf(w, "Created issue: %s
", issue.Title)
}
}
diff --git a/pkg/web/handler/pages.go b/pkg/web/handler/pages.go
index 0eea015..82c6c63 100644
--- a/pkg/web/handler/pages.go
+++ b/pkg/web/handler/pages.go
@@ -31,12 +31,10 @@ func IndexHandler(svc *service.Services) http.HandlerFunc {
}
props := routes.IndexProps{
- Issues: issues,
- IssueList: components.IssueListProps{
+ IssueTable: components.IssueTableProps{
Issues: issues,
},
}
-
routes.Index(props).Render(r.Context(), w)
}
}
diff --git a/pkg/web/routes/index.templ b/pkg/web/routes/index.templ
index 73423e2..8a3c463 100644
--- a/pkg/web/routes/index.templ
+++ b/pkg/web/routes/index.templ
@@ -1,19 +1,28 @@
package routes
import (
- "github.com/LazyBachelor/LazyPM/internal/models"
"github.com/LazyBachelor/LazyPM/pkg/web/components"
)
type IndexProps struct {
- Issues []*models.Issue
- IssueList components.IssueListProps
+ IssueTable components.IssueTableProps
}
templ Index(props IndexProps) {
@BaseLayout() {
- Welcome to the Beads Test Application
- Here are current issues:
- @components.IssueList(props.IssueList)
+
+
Create New Issue
+ @components.IssueForm(
+ components.IssueFormProps{
+ Action: "/create-issue",
+ Class: "mb-4",
+ Title: "",
+ Description: "",
+ Status: "open",
+ Priority: 0,
+ IssueType: "task",
+ })
+
+ @components.IssueTable(props.IssueTable)
}
}
diff --git a/pkg/web/routes/index_templ.go b/pkg/web/routes/index_templ.go
index 0600679..7f014ff 100644
--- a/pkg/web/routes/index_templ.go
+++ b/pkg/web/routes/index_templ.go
@@ -9,13 +9,11 @@ import "github.com/a-h/templ"
import templruntime "github.com/a-h/templ/runtime"
import (
- "github.com/LazyBachelor/LazyPM/internal/models"
"github.com/LazyBachelor/LazyPM/pkg/web/components"
)
type IndexProps struct {
- Issues []*models.Issue
- IssueList components.IssueListProps
+ IssueTable components.IssueTableProps
}
func Index(props IndexProps) templ.Component {
@@ -51,11 +49,28 @@ func Index(props IndexProps) templ.Component {
}()
}
ctx = templ.InitializeContext(ctx)
- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 1, "Welcome to the Beads Test Application
Here are current issues:
")
+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 1, "Create New Issue
")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
- templ_7745c5c3_Err = components.IssueList(props.IssueList).Render(ctx, templ_7745c5c3_Buffer)
+ templ_7745c5c3_Err = components.IssueForm(
+ components.IssueFormProps{
+ Action: "/create-issue",
+ Class: "mb-4",
+ Title: "",
+ Description: "",
+ Status: "open",
+ Priority: 0,
+ IssueType: "task",
+ }).Render(ctx, templ_7745c5c3_Buffer)
+ if templ_7745c5c3_Err != nil {
+ return templ_7745c5c3_Err
+ }
+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 2, "")
+ if templ_7745c5c3_Err != nil {
+ return templ_7745c5c3_Err
+ }
+ templ_7745c5c3_Err = components.IssueTable(props.IssueTable).Render(ctx, templ_7745c5c3_Buffer)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}