component.DummyMenuItem: Force early replacement

This commit is contained in:
Tom Wiesing 2023-02-03 15:12:52 +01:00
parent 2466238388
commit a7309d5268
No known key found for this signature in database
7 changed files with 75 additions and 27 deletions

View file

@ -34,7 +34,12 @@ type GrantWithURL struct {
URL template.URL URL template.URL
} }
var (
totpActionItem = component.DummyMenuItem()
)
func (panel *UserPanel) routeUser(ctx context.Context) http.Handler { func (panel *UserPanel) routeUser(ctx context.Context) http.Handler {
tpl := userTemplate.Prepare( tpl := userTemplate.Prepare(
panel.Dependencies.Templating, panel.Dependencies.Templating,
templating.Crumbs( templating.Crumbs(
@ -42,7 +47,7 @@ func (panel *UserPanel) routeUser(ctx context.Context) http.Handler {
), ),
templating.Actions( templating.Actions(
component.MenuItem{Title: "Change Password", Path: "/user/password/"}, component.MenuItem{Title: "Change Password", Path: "/user/password/"},
component.DummyMenuItem, totpActionItem,
component.MenuItem{Title: "SSH Keys", Path: "/user/ssh/"}, component.MenuItem{Title: "SSH Keys", Path: "/user/ssh/"},
), ),
) )
@ -68,7 +73,7 @@ func (panel *UserPanel) routeUser(ctx context.Context) http.Handler {
} }
} }
funcs = []templating.FlagFunc{ funcs = []templating.FlagFunc{
templating.ReplaceAction(1, totpAction), templating.ReplaceAction(totpActionItem, totpAction),
templating.Title(uc.AuthUser.User.User), templating.Title(uc.AuthUser.User.User),
} }

View file

@ -3,6 +3,7 @@ package component
import ( import (
"html/template" "html/template"
"net/http" "net/http"
"sync/atomic"
) )
// Menuable is a component that provides a menu // Menuable is a component that provides a menu
@ -16,13 +17,35 @@ type MenuItem struct {
Path template.URL Path template.URL
Active bool Active bool
Priority MenuPriority // menu priority Priority MenuPriority
replaceID uint64 // internal id used to replace an item
} }
// DummyMenuItem is a dummy menu item var dummyCounter uint64
// It should be replaced before being displayed to the user
var DummyMenuItem = MenuItem{ // DummyMenuItem creates a new Dummy Menu Item to be replaced
Title: "* to be replaced *", func DummyMenuItem() MenuItem {
return MenuItem{
replaceID: atomic.AddUint64(&dummyCounter, 1),
}
}
// ReplaceWith replaces this MenuItem with a different MenuItem.
// This method returns true if an appropriate DummyMenuItem exists.
func (mi MenuItem) ReplaceWith(new MenuItem, items []MenuItem) bool {
if mi.replaceID == 0 {
// never replace non-dummy items
return false
}
for i, item := range items {
if mi.replaceID == item.replaceID {
items[i] = new
return true
}
}
return false
} }
func MenuItemSort(a, b MenuItem) bool { func MenuItemSort(a, b MenuItem) bool {

View file

@ -47,14 +47,19 @@ func (admin *Admin) components(ctx context.Context) http.Handler {
}) })
} }
var (
instanceCrumb = component.DummyMenuItem()
ingredientsCrumb = component.DummyMenuItem()
)
func (admin *Admin) ingredients(ctx context.Context) http.Handler { func (admin *Admin) ingredients(ctx context.Context) http.Handler {
tpl := analTemplate.Prepare( tpl := analTemplate.Prepare(
admin.Dependencies.Templating, admin.Dependencies.Templating,
templating.Crumbs( templating.Crumbs(
component.MenuItem{Title: "Admin", Path: "/admin/"}, component.MenuItem{Title: "Admin", Path: "/admin/"},
component.MenuItem{Title: "Instances", Path: "/admin/instance/"}, component.MenuItem{Title: "Instances", Path: "/admin/instance/"},
component.DummyMenuItem, instanceCrumb,
component.DummyMenuItem, ingredientsCrumb,
), ),
) )
@ -70,8 +75,8 @@ func (admin *Admin) ingredients(ctx context.Context) http.Handler {
return ac, nil, err return ac, nil, err
} }
funcs = []templating.FlagFunc{ funcs = []templating.FlagFunc{
templating.ReplaceCrumb(2, component.MenuItem{Title: "Instance", Path: template.URL("/admin/instance/" + slug)}), templating.ReplaceCrumb(instanceCrumb, component.MenuItem{Title: "Instance", Path: template.URL("/admin/instance/" + slug)}),
templating.ReplaceCrumb(3, component.MenuItem{Title: "Ingredients", Path: template.URL("/admin/instance/" + slug + "/ingredients/")}), templating.ReplaceCrumb(ingredientsCrumb, component.MenuItem{Title: "Ingredients", Path: template.URL("/admin/instance/" + slug + "/ingredients/")}),
templating.Title(instance.Name() + " - Ingredients"), templating.Title(instance.Name() + " - Ingredients"),
} }

View file

@ -41,14 +41,19 @@ type grantsContext struct {
Drupals []string // unusued drupal usernames Drupals []string // unusued drupal usernames
} }
var (
instancePageCrumb = component.DummyMenuItem()
grantsPageCrumb = component.DummyMenuItem()
)
func (admin *Admin) grants(ctx context.Context) http.Handler { func (admin *Admin) grants(ctx context.Context) http.Handler {
tpl := grantsTemplate.Prepare( tpl := grantsTemplate.Prepare(
admin.Dependencies.Templating, admin.Dependencies.Templating,
templating.Crumbs( templating.Crumbs(
component.MenuItem{Title: "Admin", Path: "/admin/"}, component.MenuItem{Title: "Admin", Path: "/admin/"},
component.MenuItem{Title: "Instances", Path: "/admin/instance/"}, component.MenuItem{Title: "Instances", Path: "/admin/instance/"},
component.DummyMenuItem, instancePageCrumb,
component.DummyMenuItem, grantsPageCrumb,
), ),
) )
@ -137,8 +142,8 @@ func (gc *grantsContext) use(r *http.Request, slug string, admin *Admin) (funcs
// replace the functions // replace the functions
funcs = []templating.FlagFunc{ funcs = []templating.FlagFunc{
templating.ReplaceCrumb(2, component.MenuItem{Title: "Instance", Path: template.URL("/admin/instance/" + slug)}), templating.ReplaceCrumb(instancePageCrumb, component.MenuItem{Title: "Instance", Path: template.URL("/admin/instance/" + slug)}),
templating.ReplaceCrumb(3, component.MenuItem{Title: "Grants", Path: template.URL("/admin/instance/" + slug + "/grants/")}), templating.ReplaceCrumb(grantsPageCrumb, component.MenuItem{Title: "Grants", Path: template.URL("/admin/instance/" + slug + "/grants/")}),
templating.Title(gc.Instance.Slug + " - Grants"), templating.Title(gc.Instance.Slug + " - Grants"),
} }
return funcs, nil return funcs, nil

View file

@ -31,17 +31,23 @@ type instanceContext struct {
Info status.WissKI Info status.WissKI
} }
var (
instancesPageCrumb = component.DummyMenuItem()
grantsAction = component.DummyMenuItem()
ingredientsAction = component.DummyMenuItem()
)
func (admin *Admin) instance(ctx context.Context) http.Handler { func (admin *Admin) instance(ctx context.Context) http.Handler {
tpl := instanceTemplate.Prepare( tpl := instanceTemplate.Prepare(
admin.Dependencies.Templating, admin.Dependencies.Templating,
templating.Crumbs( templating.Crumbs(
component.MenuItem{Title: "Admin", Path: "/admin/"}, component.MenuItem{Title: "Admin", Path: "/admin/"},
component.MenuItem{Title: "Instances", Path: "/admin/instance/"}, component.MenuItem{Title: "Instances", Path: "/admin/instance/"},
component.DummyMenuItem, instancesPageCrumb,
), ),
templating.Actions( templating.Actions(
component.DummyMenuItem, grantsAction,
component.DummyMenuItem, ingredientsAction,
), ),
) )
@ -65,9 +71,9 @@ func (admin *Admin) instance(ctx context.Context) http.Handler {
} }
funcs = []templating.FlagFunc{ funcs = []templating.FlagFunc{
templating.ReplaceCrumb(2, component.MenuItem{Title: "Instance", Path: template.URL("/admin/instance/" + slug)}), templating.ReplaceCrumb(instancesPageCrumb, component.MenuItem{Title: "Instance", Path: template.URL("/admin/instance/" + slug)}),
templating.ReplaceAction(0, component.MenuItem{Title: "Grants", Path: template.URL("/admin/grants/" + slug)}), templating.ReplaceAction(grantsAction, component.MenuItem{Title: "Grants", Path: template.URL("/admin/grants/" + slug)}),
templating.ReplaceAction(1, component.MenuItem{Title: "Ingredients", Path: template.URL("/admin/ingredients/" + slug), Priority: component.SmallButton}), templating.ReplaceAction(ingredientsAction, component.MenuItem{Title: "Ingredients", Path: template.URL("/admin/ingredients/" + slug), Priority: component.SmallButton}),
templating.Title(instance.Slug), templating.Title(instance.Slug),
} }

View file

@ -203,7 +203,6 @@ const (
) )
func (ctx *tContext[C]) doMain(err error) (template.HTML, error) { func (ctx *tContext[C]) doMain(err error) (template.HTML, error) {
zerolog.Ctx(ctx.ctx).Info().Msg("doMain")
if err != nil { if err != nil {
zerolog.Ctx(ctx.ctx).Err(err).Msg("error lazy loading template") zerolog.Ctx(ctx.ctx).Err(err).Msg("error lazy loading template")
return errUnknown, nil return errUnknown, nil
@ -220,7 +219,6 @@ func (ctx *tContext[C]) doMain(err error) (template.HTML, error) {
} }
func (ctx *tContext[C]) AfterBody() (template.HTML, error) { func (ctx *tContext[C]) AfterBody() (template.HTML, error) {
zerolog.Ctx(ctx.ctx).Info().Msg("AfterBody()")
// everything was done already // everything was done already
if !ctx.cWaiting { if !ctx.cWaiting {
return "", nil return "", nil

View file

@ -1,12 +1,14 @@
package templating package templating
import ( import (
"fmt"
"html/template" "html/template"
"net/http" "net/http"
"time" "time"
"github.com/FAU-CDI/wisski-distillery/internal/dis/component" "github.com/FAU-CDI/wisski-distillery/internal/dis/component"
"github.com/FAU-CDI/wisski-distillery/internal/dis/component/server/assets" "github.com/FAU-CDI/wisski-distillery/internal/dis/component/server/assets"
"github.com/rs/zerolog"
"github.com/tkw1536/goprogram/lib/reflectx" "github.com/tkw1536/goprogram/lib/reflectx"
"golang.org/x/exp/slices" "golang.org/x/exp/slices"
) )
@ -77,17 +79,21 @@ func Actions(actions ...component.MenuItem) FlagFunc {
} }
// ReplaceAction replaces a specific action // ReplaceAction replaces a specific action
func ReplaceAction(index int, action component.MenuItem) FlagFunc { func ReplaceAction(old component.MenuItem, action component.MenuItem) FlagFunc {
return func(flags Flags, r *http.Request) Flags { return func(flags Flags, r *http.Request) Flags {
flags.Actions[index] = action if !old.ReplaceWith(action, flags.Actions) {
zerolog.Ctx(r.Context()).Warn().Str("action", fmt.Sprint(action)).Str("actions", fmt.Sprint(flags.Actions)).Msg("did not replace menu item")
}
return flags return flags
} }
} }
// ReplaceCrumb replaces a specific crum // ReplaceCrumb replaces a specific crum
func ReplaceCrumb(index int, action component.MenuItem) FlagFunc { func ReplaceCrumb(old component.MenuItem, action component.MenuItem) FlagFunc {
return func(flags Flags, r *http.Request) Flags { return func(flags Flags, r *http.Request) Flags {
flags.Crumbs[index] = action if !old.ReplaceWith(action, flags.Crumbs) {
zerolog.Ctx(r.Context()).Warn().Str("action", fmt.Sprint(action)).Str("actions", fmt.Sprint(flags.Actions)).Msg("did not replace menu item")
}
return flags return flags
} }
} }