all repos — searchix @ d3336c09a291673ab82e259741bd232baf1bbc07

Search engine for NixOS, nix-darwin, home-manager and NUR users

refactor: extract more pagination logic into module

Alan Pearce
commit

d3336c09a291673ab82e259741bd232baf1bbc07

parent

523d5f2e715f21dd1211c39bc1231d637588902f

M internal/components/data.gointernal/components/data.go
@@ -1,9 +1,13 @@
package components import ( + "net/url" + "strconv" + "alin.ovh/searchix/frontend" "alin.ovh/searchix/internal/config" search "alin.ovh/searchix/internal/index" + "alin.ovh/searchix/internal/pagination" ) type TemplateData struct {
@@ -14,13 +18,53 @@ ExtraHeadHTML string
Code int Message string Assets *frontend.AssetCollection + SearchNav SearchNav } type ResultData struct { TemplateData Query string Results *search.Result - Prev string - Next string - All string +} + +type SearchNav struct { + URL url.URL + + Prev string + Next string + All string + + pagination *pagination.Pagination +} + +func NewSearchNav(u url.URL) SearchNav { + return SearchNav{URL: u} +} + +func (u SearchNav) WithPagination(page *pagination.Pagination) SearchNav { + u.pagination = page + + q := u.URL.Query() + urlBase := u.URL.Path + + if page.Next != 0 { + q.Set("page", strconv.Itoa(page.Next)) + u.Next = urlBase + "?" + q.Encode() + } + + if page.Prev != 0 { + if page.Prev == 1 { + q.Del("page") + } else { + q.Set("page", strconv.Itoa(page.Prev)) + } + u.Prev = urlBase + "?" + q.Encode() + } + + if page.CanShowAll { + q.Set("page", "0") + u.All = urlBase + "?" + q.Encode() + } + + return u }
M internal/components/results.gointernal/components/results.go
@@ -8,11 +8,11 @@ . "alin.ovh/gomponents/html"
) func Results(r ResultData) g.Node { - if r.Query == "" { + if r.Results == nil { return Br() } - if r.Results == nil || r.Results.Total == 0 { + if r.Results.Total == 0 { return Span(Role("status"), g.Text("Nothing found")) }
@@ -34,11 +34,11 @@ Footer(
g.Attr("aria-label", "pagination"), Nav( ID("pagination"), - g.If(r.Prev != "", - A(Class("button"), Href(r.Prev), Rel("prev"), g.Text("Prev")), + g.If(r.SearchNav.Prev != "", + A(Class("button"), Href(r.SearchNav.Prev), Rel("prev"), g.Text("Prev")), ), - g.If(r.Next != "", - A(Class("button"), Href(r.Next), Rel("next"), g.Text("Next")), + g.If(r.SearchNav.Next != "", + A(Class("button"), Href(r.SearchNav.Next), Rel("next"), g.Text("Next")), ), ), Span(
@@ -46,8 +46,8 @@ Role("status"),
g.Textf("%d results", r.Results.Total), ), g.Text(" "), - g.If(r.Next != r.Prev && r.Results.Total < config.MaxResultsShowAll, - A(Href(r.All), g.Text("Show All")), + g.If(r.SearchNav.All != "", + A(Href(r.SearchNav.All), g.Text("Show All")), ), ), })
M internal/pagination/pagination.gointernal/pagination/pagination.go
@@ -1,5 +1,7 @@
package pagination +import "alin.ovh/searchix/internal/config" + type Pagination struct { total uint64
@@ -10,7 +12,8 @@ Current,
Prev, Next int - Needed bool + Needed bool + CanShowAll bool } func New(page int, pageSize int) *Pagination {
@@ -18,14 +21,18 @@ return &Pagination{
Current: page, From: (page - 1) * pageSize, Size: pageSize, + Needed: page > 1, } } func (p *Pagination) SetResults(total uint64) { p.total = total - p.Needed = p.total > uint64(p.Size) + p.Needed = p.Needed || (total > uint64(p.Size)) + p.CanShowAll = p.Needed && total < config.MaxResultsShowAll + if p.Current > 1 { + p.Prev = p.Current - 1 + } if uint64(p.Current*p.Size) <= p.total { p.Next = p.Current + 1 - p.Prev = p.Current - 1 } }
M internal/server/mux.gointernal/server/mux.go
@@ -8,7 +8,6 @@ "fmt"
"maps" "math" "net/http" - "net/url" "path" "slices" "strconv"
@@ -86,9 +85,7 @@ createSearchHandler := func(importerType config.ImporterType) func(http.ResponseWriter, *http.Request) {
return func(w http.ResponseWriter, r *http.Request) { var err error var source *config.Source - var urlBase string if importerType != config.All { - urlBase = "search" source = cfg.Importer.Sources[r.PathValue("source")] if source == nil || importerType != source.Importer { errorHandler(w, r, http.StatusText(http.StatusNotFound), http.StatusNotFound)
@@ -143,6 +140,7 @@ if pageSize == config.MaxResultsShowAll &&
results.Total > config.MaxResultsShowAll { errorHandler(w, r, "Too many results, use pagination", http.StatusBadRequest) } + page.SetResults(results.Total) tdata := components.ResultData{ TemplateData: components.TemplateData{
@@ -151,36 +149,10 @@ Source: source,
Sources: sources, Assets: assets, Query: qs, + SearchNav: components.NewSearchNav(*r.URL).WithPagination(page), }, Query: qs, Results: results, - } - - page.SetResults(results.Total) - if page.Needed { - q, err := url.ParseQuery(r.URL.RawQuery) - if err != nil { - errorHandler(w, r, "Query string error", http.StatusBadRequest) - - return - } - - if page.Next != 0 { - q.Set("page", strconv.Itoa(page.Next)) - tdata.Next = urlBase + "?" + q.Encode() - } - - if page.Prev != 0 { - if page.Prev == 1 { - q.Del("page") - } else { - q.Set("page", strconv.Itoa(page.Prev)) - } - tdata.Prev = urlBase + "?" + q.Encode() - } - - q.Set("page", "0") - tdata.All = urlBase + "?" + q.Encode() } w.Header().Add("Cache-Control", "max-age=300")