Make admin menu links dynamic.

This commit is contained in:
mikestefanello 2025-04-19 10:22:40 -04:00
parent 8219b96df7
commit 36bc20b90f
6 changed files with 42 additions and 15 deletions

View file

@ -132,10 +132,11 @@ func (h *Handler) PasswordTokenDelete(ctx echo.Context, id int) error {
} }
func (h *Handler) PasswordTokenList(ctx echo.Context) (*EntityList, error) { func (h *Handler) PasswordTokenList(ctx echo.Context) (*EntityList, error) {
page, offset := h.getPageAndOffset(ctx)
res, err := h.client.PasswordToken. res, err := h.client.PasswordToken.
Query(). Query().
Limit(h.Config.ItemsPerPage + 1). Limit(h.Config.ItemsPerPage + 1).
Offset(h.getOffset(ctx)). Offset(offset).
Order(passwordtoken.ByID(sql.OrderDesc())). Order(passwordtoken.ByID(sql.OrderDesc())).
All(ctx.Request().Context()) All(ctx.Request().Context())
@ -149,6 +150,7 @@ func (h *Handler) PasswordTokenList(ctx echo.Context) (*EntityList, error) {
"Created at", "Created at",
}, },
Entities: make([]EntityValues, 0, len(res)), Entities: make([]EntityValues, 0, len(res)),
Page: page,
HasNextPage: len(res) > h.Config.ItemsPerPage, HasNextPage: len(res) > h.Config.ItemsPerPage,
} }
@ -225,10 +227,11 @@ func (h *Handler) UserDelete(ctx echo.Context, id int) error {
} }
func (h *Handler) UserList(ctx echo.Context) (*EntityList, error) { func (h *Handler) UserList(ctx echo.Context) (*EntityList, error) {
page, offset := h.getPageAndOffset(ctx)
res, err := h.client.User. res, err := h.client.User.
Query(). Query().
Limit(h.Config.ItemsPerPage + 1). Limit(h.Config.ItemsPerPage + 1).
Offset(h.getOffset(ctx)). Offset(offset).
Order(user.ByID(sql.OrderDesc())). Order(user.ByID(sql.OrderDesc())).
All(ctx.Request().Context()) All(ctx.Request().Context())
@ -244,6 +247,7 @@ func (h *Handler) UserList(ctx echo.Context) (*EntityList, error) {
"Created at", "Created at",
}, },
Entities: make([]EntityValues, 0, len(res)), Entities: make([]EntityValues, 0, len(res)),
Page: page,
HasNextPage: len(res) > h.Config.ItemsPerPage, HasNextPage: len(res) > h.Config.ItemsPerPage,
} }
@ -275,13 +279,13 @@ func (h *Handler) UserGet(ctx echo.Context, id int) (url.Values, error) {
return v, err return v, err
} }
func (h *Handler) getOffset(ctx echo.Context) int { func (h *Handler) getPageAndOffset(ctx echo.Context) (int, int) {
if page, err := strconv.Atoi(ctx.QueryParam(h.Config.PageQueryKey)); err == nil { if page, err := strconv.Atoi(ctx.QueryParam(h.Config.PageQueryKey)); err == nil {
if page > 1 { if page > 1 {
return (page - 1) * h.Config.ItemsPerPage return page, (page - 1) * h.Config.ItemsPerPage
} }
} }
return 0 return 1, 0
} }
func (h *Handler) bind(ctx echo.Context, entity any) error { func (h *Handler) bind(ctx echo.Context, entity any) error {

View file

@ -156,10 +156,11 @@
} }
func (h *Handler) {{ $n.Name }}List(ctx echo.Context) (*EntityList, error) { func (h *Handler) {{ $n.Name }}List(ctx echo.Context) (*EntityList, error) {
page, offset := h.getPageAndOffset(ctx)
res, err := h.client.{{ $n.Name }}. res, err := h.client.{{ $n.Name }}.
Query(). Query().
Limit(h.Config.ItemsPerPage+1). Limit(h.Config.ItemsPerPage+1).
Offset(h.getOffset(ctx)). Offset(offset).
Order({{ $n.Package }}.ByID(sql.OrderDesc())). Order({{ $n.Package }}.ByID(sql.OrderDesc())).
All(ctx.Request().Context()) All(ctx.Request().Context())
@ -176,6 +177,7 @@
{{- end }} {{- end }}
}, },
Entities: make([]EntityValues, 0, len(res)), Entities: make([]EntityValues, 0, len(res)),
Page: page,
HasNextPage: len(res) > h.Config.ItemsPerPage, HasNextPage: len(res) > h.Config.ItemsPerPage,
} }
@ -223,13 +225,13 @@
} }
{{ end }} {{ end }}
func (h *Handler) getOffset(ctx echo.Context) int { func (h *Handler) getPageAndOffset(ctx echo.Context) (int, int) {
if page, err := strconv.Atoi(ctx.QueryParam(h.Config.PageQueryKey)); err == nil { if page, err := strconv.Atoi(ctx.QueryParam(h.Config.PageQueryKey)); err == nil {
if page > 1 { if page > 1 {
return (page-1) * h.Config.ItemsPerPage return page, (page-1) * h.Config.ItemsPerPage
} }
} }
return 0 return 1, 0
} }
func (h *Handler) bind(ctx echo.Context, entity any) error { func (h *Handler) bind(ctx echo.Context, entity any) error {

View file

@ -5,7 +5,7 @@
// Code generated by ent, DO NOT EDIT. // Code generated by ent, DO NOT EDIT.
package admin package admin
{{ range $n := $.Nodes }} {{- range $n := $.Nodes }}
type {{ $n.Name }} struct { type {{ $n.Name }} struct {
{{- range $f := $n.Fields }} {{- range $f := $n.Fields }}
{{ fieldName $f.Name }} {{ if (fieldIsPointer $f) }}*{{ end }}{{ $f.Type }} `form:"{{ $f.Name }}"` {{ fieldName $f.Name }} {{ if (fieldIsPointer $f) }}*{{ end }}{{ $f.Type }} `form:"{{ $f.Name }}"`
@ -16,6 +16,7 @@
type EntityList struct { type EntityList struct {
Columns []string Columns []string
Entities []EntityValues Entities []EntityValues
Page int
HasNextPage bool HasNextPage bool
} }
@ -30,4 +31,12 @@
TimeFormat string TimeFormat string
} }
func GetEntityTypeNames() []string {
return []string{
{{- range $n := $.Nodes }}
"{{ $n.Name }}",
{{- end }}
}
}
{{ end }} {{ end }}

View file

@ -20,6 +20,7 @@ type User struct {
type EntityList struct { type EntityList struct {
Columns []string Columns []string
Entities []EntityValues Entities []EntityValues
Page int
HasNextPage bool HasNextPage bool
} }
@ -33,3 +34,10 @@ type HandlerConfig struct {
PageQueryKey string PageQueryKey string
TimeFormat string TimeFormat string
} }
func GetEntityTypeNames() []string {
return []string{
"PasswordToken",
"User",
}
}

View file

@ -49,7 +49,6 @@ func (h *Admin) Routes(g *echo.Group) {
// TODO admin user status middleware // TODO admin user status middleware
entities := g.Group("/admin/content") entities := g.Group("/admin/content")
// TODO: can we generate something we can loop instead?
for _, n := range h.graph.Nodes { for _, n := range h.graph.Nodes {
ng := entities.Group(fmt.Sprintf("/%s", strings.ToLower(n.Name))) ng := entities.Group(fmt.Sprintf("/%s", strings.ToLower(n.Name)))
ng.GET("", h.EntityList(n)). ng.GET("", h.EntityList(n)).
@ -71,7 +70,6 @@ func (h *Admin) Routes(g *echo.Group) {
} }
} }
// TODO, maybe this can be used outside of admin stuff as well?
func (h *Admin) middlewareEntityLoad(n *gen.Type) echo.MiddlewareFunc { func (h *Admin) middlewareEntityLoad(n *gen.Type) echo.MiddlewareFunc {
return func(next echo.HandlerFunc) echo.HandlerFunc { return func(next echo.HandlerFunc) echo.HandlerFunc {
return func(ctx echo.Context) error { return func(ctx echo.Context) error {

View file

@ -1,6 +1,7 @@
package layouts package layouts
import ( import (
"github.com/mikestefanello/pagoda/ent/admin"
"github.com/mikestefanello/pagoda/pkg/routenames" "github.com/mikestefanello/pagoda/pkg/routenames"
"github.com/mikestefanello/pagoda/pkg/ui" "github.com/mikestefanello/pagoda/pkg/ui"
. "github.com/mikestefanello/pagoda/pkg/ui/components" . "github.com/mikestefanello/pagoda/pkg/ui/components"
@ -42,17 +43,22 @@ func Admin(r *ui.Request, content Node) Node {
} }
func adminMenu(r *ui.Request) Node { func adminMenu(r *ui.Request) Node {
entityTypeNames := admin.GetEntityTypeNames()
entityTypeLinks := make(Group, len(entityTypeNames))
for _, n := range entityTypeNames {
entityTypeLinks = append(entityTypeLinks, MenuLink(r, n, routenames.AdminEntityList(n)))
}
return Aside( return Aside(
Class("menu"), Class("menu"),
HxBoost(), HxBoost(),
P( P(
Class("menu-label"), Class("menu-label"),
Text("Content"), Text("Entities"),
), ),
Ul( Ul(
Class("menu-list"), Class("menu-list"),
MenuLink(r, "User", routenames.AdminEntityList("User")), entityTypeLinks,
MenuLink(r, "PasswordToken", routenames.AdminEntityList("PasswordToken")),
), ),
P( P(
Class("menu-label"), Class("menu-label"),