Monorepo for Tangled tangled.org

appview: add reusable pagination template #953

closed opened by moshyfawn.dev targeting master from moshyfawn.dev/core: feat/pulls-pagination

Extract pagination UI into a shared template for reuse across pages. Refactored issues listing to use it with no behavior change

Labels

None yet.

assignee
Participants 2
AT URI
at://did:plc:sshwio5obbx4zjfrn3fhsen6/sh.tangled.repo.pull/3mchh4ehpm622
+133 -105
Diff #0
+2
appview/pages/pages.go
··· 1069 1069 Stacks map[string]models.Stack 1070 1070 Pipelines map[string]models.Pipeline 1071 1071 LabelDefs map[string]*models.LabelDefinition 1072 + Page pagination.Page 1073 + PullCount int 1072 1074 } 1073 1075 1074 1076 func (p *Pages) RepoPulls(w io.Writer, params RepoPullsParams) error {
+95
appview/pages/templates/fragments/pagination.html
··· 1 + {{ define "fragments/pagination" }} 2 + {{/* Params: Page (pagination.Page), TotalCount (int), BasePath (string), QueryParams (string) */}} 3 + {{ $page := .Page }} 4 + {{ $totalCount := .TotalCount }} 5 + {{ $basePath := .BasePath }} 6 + {{ $queryParams := .QueryParams }} 7 + 8 + {{ $prev := $page.Previous.Offset }} 9 + {{ $next := $page.Next.Offset }} 10 + {{ $lastPage := sub $totalCount (mod $totalCount $page.Limit) }} 11 + 12 + <div class="flex justify-center items-center mt-4 gap-2"> 13 + <a 14 + class=" 15 + btn flex items-center gap-2 no-underline hover:no-underline 16 + dark:text-white dark:hover:bg-gray-700 17 + {{ if le $page.Offset 0 }} 18 + cursor-not-allowed opacity-50 19 + {{ end }} 20 + " 21 + {{ if gt $page.Offset 0 }} 22 + hx-boost="true" 23 + href="{{ $basePath }}?{{ $queryParams }}&offset={{ $prev }}&limit={{ $page.Limit }}" 24 + {{ end }} 25 + > 26 + {{ i "chevron-left" "w-4 h-4" }} 27 + previous 28 + </a> 29 + 30 + {{ if gt $page.Offset 0 }} 31 + <a 32 + hx-boost="true" 33 + href="{{ $basePath }}?{{ $queryParams }}&offset=0&limit={{ $page.Limit }}" 34 + > 35 + 1 36 + </a> 37 + {{ end }} 38 + 39 + {{ if gt $prev $page.Limit }} 40 + <span>...</span> 41 + {{ end }} 42 + 43 + {{ if gt $prev 0 }} 44 + <a 45 + hx-boost="true" 46 + href="{{ $basePath }}?{{ $queryParams }}&offset={{ $prev }}&limit={{ $page.Limit }}" 47 + > 48 + {{ add (div $prev $page.Limit) 1 }} 49 + </a> 50 + {{ end }} 51 + 52 + <span class="font-bold"> 53 + {{ add (div $page.Offset $page.Limit) 1 }} 54 + </span> 55 + 56 + {{ if lt $next $lastPage }} 57 + <a 58 + hx-boost="true" 59 + href="{{ $basePath }}?{{ $queryParams }}&offset={{ $next }}&limit={{ $page.Limit }}" 60 + > 61 + {{ add (div $next $page.Limit) 1 }} 62 + </a> 63 + {{ end }} 64 + 65 + {{ if lt $next (sub $totalCount (mul 2 $page.Limit)) }} 66 + <span>...</span> 67 + {{ end }} 68 + 69 + {{ if lt $page.Offset $lastPage }} 70 + <a 71 + hx-boost="true" 72 + href="{{ $basePath }}?{{ $queryParams }}&offset={{ $lastPage }}&limit={{ $page.Limit }}" 73 + > 74 + {{ add (div $lastPage $page.Limit) 1 }} 75 + </a> 76 + {{ end }} 77 + 78 + <a 79 + class=" 80 + btn flex items-center gap-2 no-underline hover:no-underline 81 + dark:text-white dark:hover:bg-gray-700 82 + {{ if lt $next $totalCount | not }} 83 + cursor-not-allowed opacity-50 84 + {{ end }} 85 + " 86 + {{ if lt $next $totalCount }} 87 + hx-boost="true" 88 + href="{{ $basePath }}?{{ $queryParams }}&offset={{ $next }}&limit={{ $page.Limit }}" 89 + {{ end }} 90 + > 91 + next 92 + {{ i "chevron-right" "w-4 h-4" }} 93 + </a> 94 + </div> 95 + {{ end }}
+10 -103
appview/pages/templates/repo/issues/issues.html
··· 71 71 <div class="mt-2"> 72 72 {{ template "repo/issues/fragments/issueListing" (dict "Issues" .Issues "RepoPrefix" .RepoInfo.FullName "LabelDefs" .LabelDefs) }} 73 73 </div> 74 - {{if gt .IssueCount .Page.Limit }} 75 - {{ block "pagination" . }} {{ end }} 76 - {{ end }} 77 - {{ end }} 78 - 79 - {{ define "pagination" }} 80 - <div class="flex justify-center items-center mt-4 gap-2"> 81 - {{ $currentState := "closed" }} 82 - {{ if .FilteringByOpen }} 83 - {{ $currentState = "open" }} 84 - {{ end }} 85 - 86 - {{ $prev := .Page.Previous.Offset }} 87 - {{ $next := .Page.Next.Offset }} 88 - {{ $lastPage := sub .IssueCount (mod .IssueCount .Page.Limit) }} 89 - 90 - <a 91 - class=" 92 - btn flex items-center gap-2 no-underline hover:no-underline 93 - dark:text-white dark:hover:bg-gray-700 94 - {{ if le .Page.Offset 0 }} 95 - cursor-not-allowed opacity-50 96 - {{ end }} 97 - " 98 - {{ if gt .Page.Offset 0 }} 99 - hx-boost="true" 100 - href = "/{{ $.RepoInfo.FullName }}/issues?state={{ $currentState }}&q={{ .FilterQuery }}&offset={{ $prev }}&limit={{ .Page.Limit }}" 74 + {{if gt .IssueCount .Page.Limit }} 75 + {{ $state := "closed" }} 76 + {{ if .FilteringByOpen }} 77 + {{ $state = "open" }} 101 78 {{ end }} 102 - > 103 - {{ i "chevron-left" "w-4 h-4" }} 104 - previous 105 - </a> 106 - 107 - <!-- dont show first page if current page is first page --> 108 - {{ if gt .Page.Offset 0 }} 109 - <a 110 - hx-boost="true" 111 - href = "/{{ $.RepoInfo.FullName }}/issues?state={{ $currentState }}&q={{ .FilterQuery }}&offset=0&limit={{ .Page.Limit }}" 112 - > 113 - 1 114 - </a> 115 - {{ end }} 116 - 117 - <!-- if previous page is not first or second page (prev > limit) --> 118 - {{ if gt $prev .Page.Limit }} 119 - <span>...</span> 79 + {{ template "fragments/pagination" (dict 80 + "Page" .Page 81 + "TotalCount" .IssueCount 82 + "BasePath" (printf "/%s/issues" .RepoInfo.FullName) 83 + "QueryParams" (printf "state=%s&q=%s" $state .FilterQuery) 84 + ) }} 120 85 {{ end }} 121 - 122 - <!-- if previous page is not the first page --> 123 - {{ if gt $prev 0 }} 124 - <a 125 - hx-boost="true" 126 - href = "/{{ $.RepoInfo.FullName }}/issues?state={{ $currentState }}&q={{ .FilterQuery }}&offset={{ $prev }}&limit={{ .Page.Limit }}" 127 - > 128 - {{ add (div $prev .Page.Limit) 1 }} 129 - </a> 130 - {{ end }} 131 - 132 - <!-- current page. this is always visible --> 133 - <span class="font-bold"> 134 - {{ add (div .Page.Offset .Page.Limit) 1 }} 135 - </span> 136 - 137 - <!-- if next page is not last page --> 138 - {{ if lt $next $lastPage }} 139 - <a 140 - hx-boost="true" 141 - href = "/{{ $.RepoInfo.FullName }}/issues?state={{ $currentState }}&q={{ .FilterQuery }}&offset={{ $next }}&limit={{ .Page.Limit }}" 142 - > 143 - {{ add (div $next .Page.Limit) 1 }} 144 - </a> 145 - {{ end }} 146 - 147 - <!-- if next page is not second last or last page (next < issues - 2 * limit) --> 148 - {{ if lt ($next) (sub .IssueCount (mul (2) .Page.Limit)) }} 149 - <span>...</span> 150 - {{ end }} 151 - 152 - <!-- if its not the last page --> 153 - {{ if lt .Page.Offset $lastPage }} 154 - <a 155 - hx-boost="true" 156 - href = "/{{ $.RepoInfo.FullName }}/issues?state={{ $currentState }}&q={{ .FilterQuery }}&offset={{ $lastPage }}&limit={{ .Page.Limit }}" 157 - > 158 - {{ add (div $lastPage .Page.Limit) 1 }} 159 - </a> 160 - {{ end }} 161 - 162 - <a 163 - class=" 164 - btn flex items-center gap-2 no-underline hover:no-underline 165 - dark:text-white dark:hover:bg-gray-700 166 - {{ if ne (len .Issues) .Page.Limit }} 167 - cursor-not-allowed opacity-50 168 - {{ end }} 169 - " 170 - {{ if eq (len .Issues) .Page.Limit }} 171 - hx-boost="true" 172 - href="/{{ $.RepoInfo.FullName }}/issues?state={{ $currentState }}&q={{ .FilterQuery }}&offset={{ $next }}&limit={{ .Page.Limit }}" 173 - {{ end }} 174 - > 175 - next 176 - {{ i "chevron-right" "w-4 h-4" }} 177 - </a> 178 - </div> 179 86 {{ end }}
+8
appview/pages/templates/repo/pulls/pulls.html
··· 170 170 </div> 171 171 {{ end }} 172 172 </div> 173 + {{if gt .PullCount .Page.Limit }} 174 + {{ template "fragments/pagination" (dict 175 + "Page" .Page 176 + "TotalCount" .PullCount 177 + "BasePath" (printf "/%s/pulls" .RepoInfo.FullName) 178 + "QueryParams" (printf "state=%s&q=%s" .FilteringBy.String .FilterQuery) 179 + ) }} 180 + {{ end }} 173 181 {{ end }} 174 182 175 183 {{ define "stackedPullList" }}
+17 -1
appview/pulls/pulls.go
··· 26 26 "tangled.org/core/appview/pages" 27 27 "tangled.org/core/appview/pages/markup" 28 28 "tangled.org/core/appview/pages/repoinfo" 29 + "tangled.org/core/appview/pagination" 29 30 "tangled.org/core/appview/reporesolver" 30 31 "tangled.org/core/appview/validator" 31 32 "tangled.org/core/appview/xrpcclient" ··· 563 564 state = models.PullMerged 564 565 } 565 566 567 + page := pagination.FromContext(r.Context()) 568 + 566 569 f, err := s.repoResolver.Resolve(r) 567 570 if err != nil { 568 571 log.Println("failed to get repo and knot", err) 569 572 return 570 573 } 571 574 575 + var totalPulls int 576 + switch state { 577 + case models.PullOpen: 578 + totalPulls = f.RepoStats.PullCount.Open 579 + case models.PullMerged: 580 + totalPulls = f.RepoStats.PullCount.Merged 581 + case models.PullClosed: 582 + totalPulls = f.RepoStats.PullCount.Closed 583 + } 584 + 572 585 keyword := params.Get("q") 573 586 574 587 var ids []int64 ··· 576 589 Keyword: keyword, 577 590 RepoAt: f.RepoAt().String(), 578 591 State: state, 579 - // Page: page, 592 + Page: page, 580 593 } 581 594 l.Debug("searching with", "searchOpts", searchOpts) 582 595 if keyword != "" { ··· 586 599 return 587 600 } 588 601 ids = res.Hits 602 + totalPulls = int(res.Total) 589 603 l.Debug("searched pulls with indexer", "count", len(ids)) 590 604 } else { 591 605 ids, err = db.GetPullIDs(s.db, searchOpts) ··· 688 702 FilterQuery: keyword, 689 703 Stacks: stacks, 690 704 Pipelines: m, 705 + Page: page, 706 + PullCount: totalPulls, 691 707 }) 692 708 } 693 709
+1 -1
appview/pulls/router.go
··· 9 9 10 10 func (s *Pulls) Router(mw *middleware.Middleware) http.Handler { 11 11 r := chi.NewRouter() 12 - r.Get("/", s.RepoPulls) 12 + r.With(middleware.Paginate).Get("/", s.RepoPulls) 13 13 r.With(middleware.AuthMiddleware(s.oauth)).Route("/new", func(r chi.Router) { 14 14 r.Get("/", s.NewPull) 15 15 r.Get("/patch-upload", s.PatchUploadFragment)

History

1 round 3 comments
sign up or login to add to the discussion
moshyfawn.dev submitted #0
2 commits
expand
appview: add reusable pagination template
appview/pulls: add pagination to pull requests listing
expand 3 comments

Can't update the desc: forgot it only extracts the first commit message.

This PR adds offset-based pagination to the pulls page using the refactored issues pagination template. This is relevant for both https://tangled.org/tangled.org/core/pulls/951 and the fact that right now going to pulls to look through some merged PRs pulls the entire set of merged PRs data which is a DB operation that's on a longer running side.

Thank you for the contribution! This generally seems good, but PR list pagination is inverted due to db.GetPageIDs() bug. So I opened a new PR with the fix amended. I'll leave you as the author of the commit.

closed without merging