Signed-off-by: dusk y.bera003.06@protonmail.com
+3
-3
appview/db/issues.go
+3
-3
appview/db/issues.go
···
98
98
whereClause = " where " + strings.Join(conditions, " and ")
99
99
}
100
100
101
-
pLower := FilterGte("row_num", page.Offset+1)
102
-
pUpper := FilterLte("row_num", page.Offset+page.Limit)
101
+
pLower := FilterGte("row_num", page.Count*page.No+1)
102
+
pUpper := FilterLte("row_num", page.Count*(page.No+1))
103
103
104
104
args = append(args, pLower.Arg()...)
105
105
args = append(args, pUpper.Arg()...)
···
244
244
}
245
245
246
246
func GetIssues(e Execer, filters ...filter) ([]models.Issue, error) {
247
-
return GetIssuesPaginated(e, pagination.FirstPage(), filters...)
247
+
return GetIssuesPaginated(e, pagination.Page{No: 0, Count: 30}, filters...)
248
248
}
249
249
250
250
func GetIssue(e Execer, repoAt syntax.ATURI, issueId int) (*models.Issue, error) {
+3
-3
appview/db/notifications.go
+3
-3
appview/db/notifications.go
···
68
68
limit ? offset ?
69
69
`, whereClause)
70
70
71
-
args = append(args, page.Limit, page.Offset)
71
+
args = append(args, page.Count, page.Count*page.No+1)
72
72
73
73
rows, err := e.QueryContext(context.Background(), query, args...)
74
74
if err != nil {
···
142
142
limit ? offset ?
143
143
`, whereClause)
144
144
145
-
args = append(args, page.Limit, page.Offset)
145
+
args = append(args, page.Count, page.Count*page.No+1)
146
146
147
147
rows, err := e.QueryContext(context.Background(), query, args...)
148
148
if err != nil {
···
247
247
248
248
// GetNotifications retrieves notifications with filters
249
249
func GetNotifications(e Execer, filters ...filter) ([]*models.Notification, error) {
250
-
return GetNotificationsPaginated(e, pagination.FirstPage(), filters...)
250
+
return GetNotificationsPaginated(e, pagination.Page{No: 0, Count: 30}, filters...)
251
251
}
252
252
253
253
func CountNotifications(e Execer, filters ...filter) (int64, error) {
+19
-8
appview/issues/issues.go
+19
-8
appview/issues/issues.go
···
769
769
isOpen = true
770
770
}
771
771
772
-
page, ok := r.Context().Value("page").(pagination.Page)
773
-
if !ok {
774
-
log.Println("failed to get page")
775
-
page = pagination.FirstPage()
776
-
}
777
-
778
772
user := rp.oauth.GetUser(r)
779
773
f, err := rp.repoResolver.Resolve(r)
780
774
if err != nil {
···
782
776
return
783
777
}
784
778
779
+
issueCounts, err := db.GetIssueCount(rp.db, f.RepoAt())
780
+
if err != nil {
781
+
log.Println("failed to get issue count", err)
782
+
rp.pages.Notice(w, "issues", "Failed to load issues. Try again later.")
783
+
return
784
+
}
785
+
page, ok := r.Context().Value("page").(pagination.Page)
786
+
if !ok {
787
+
log.Println("failed to get page")
788
+
page = pagination.Page{No: 0, Count: 10}
789
+
}
790
+
issueCount := issueCounts.Closed
791
+
if isOpen {
792
+
issueCount = issueCounts.Open
793
+
}
794
+
paginate := pagination.NewFromPage(page, issueCount)
795
+
785
796
openVal := 0
786
797
if isOpen {
787
798
openVal = 1
788
799
}
789
800
issues, err := db.GetIssuesPaginated(
790
801
rp.db,
791
-
page,
802
+
paginate.CurrentPage(),
792
803
db.FilterEq("repo_at", f.RepoAt()),
793
804
db.FilterEq("open", openVal),
794
805
)
···
820
831
Issues: issues,
821
832
LabelDefs: defs,
822
833
FilteringByOpen: isOpen,
823
-
Page: page,
834
+
Pagination: paginate,
824
835
})
825
836
}
826
837
+1
-1
appview/issues/router.go
+1
-1
appview/issues/router.go
+24
-22
appview/middleware/middleware.go
+24
-22
appview/middleware/middleware.go
···
81
81
}
82
82
}
83
83
84
-
func Paginate(next http.Handler) http.Handler {
85
-
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
86
-
page := pagination.FirstPage()
84
+
func Paginate(paginationCount int) func(next http.Handler) http.Handler {
85
+
return func(next http.Handler) http.Handler {
86
+
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
87
+
page := pagination.Page{No: 0, Count: paginationCount}
87
88
88
-
offsetVal := r.URL.Query().Get("offset")
89
-
if offsetVal != "" {
90
-
offset, err := strconv.Atoi(offsetVal)
91
-
if err != nil {
92
-
log.Println("invalid offset")
93
-
} else {
94
-
page.Offset = offset
89
+
pageNoVal := r.URL.Query().Get("page")
90
+
if pageNoVal != "" {
91
+
pageNo, err := strconv.Atoi(pageNoVal)
92
+
if err != nil {
93
+
log.Println("invalid page no")
94
+
} else if pageNo > 0 {
95
+
page.No = pageNo - 1
96
+
}
95
97
}
96
-
}
97
98
98
-
limitVal := r.URL.Query().Get("limit")
99
-
if limitVal != "" {
100
-
limit, err := strconv.Atoi(limitVal)
101
-
if err != nil {
102
-
log.Println("invalid limit")
103
-
} else {
104
-
page.Limit = limit
99
+
pageCountVal := r.URL.Query().Get("count")
100
+
if pageCountVal != "" {
101
+
pageCount, err := strconv.Atoi(pageCountVal)
102
+
if err != nil {
103
+
log.Println("invalid page count")
104
+
} else {
105
+
page.Count = pageCount
106
+
}
105
107
}
106
-
}
107
108
108
-
ctx := context.WithValue(r.Context(), "page", page)
109
-
next.ServeHTTP(w, r.WithContext(ctx))
110
-
})
109
+
ctx := context.WithValue(r.Context(), "page", page)
110
+
next.ServeHTTP(w, r.WithContext(ctx))
111
+
})
112
+
}
111
113
}
112
114
113
115
func (mw Middleware) knotRoleMiddleware(group string) middlewareFunc {
+4
-3
appview/notifications/notifications.go
+4
-3
appview/notifications/notifications.go
···
34
34
35
35
r.Group(func(r chi.Router) {
36
36
r.Use(middleware.AuthMiddleware(n.oauth))
37
-
r.With(middleware.Paginate).Get("/", n.notificationsPage)
37
+
r.With(middleware.Paginate(30)).Get("/", n.notificationsPage)
38
38
r.Post("/{id}/read", n.markRead)
39
39
r.Post("/read-all", n.markAllRead)
40
40
r.Delete("/{id}", n.deleteNotification)
···
49
49
page, ok := r.Context().Value("page").(pagination.Page)
50
50
if !ok {
51
51
log.Println("failed to get page")
52
-
page = pagination.FirstPage()
52
+
page = pagination.Page{No: 0, Count: 30}
53
53
}
54
54
55
55
total, err := db.CountNotifications(
···
61
61
n.pages.Error500(w)
62
62
return
63
63
}
64
+
paginate := pagination.NewFromPage(page, int(total))
64
65
65
66
notifications, err := db.GetNotificationsWithEntities(
66
67
n.db,
···
84
85
LoggedInUser: user,
85
86
Notifications: notifications,
86
87
UnreadCount: unreadCount,
87
-
Page: page,
88
+
Pagination: paginate,
88
89
Total: total,
89
90
})
90
91
}
+3
-3
appview/pages/pages.go
+3
-3
appview/pages/pages.go
···
320
320
RepoGroups []*models.RepoGroup
321
321
LabelDefs map[string]*models.LabelDefinition
322
322
GfiLabel *models.LabelDefinition
323
-
Page pagination.Page
323
+
Pagination pagination.Pagination
324
324
}
325
325
326
326
func (p *Pages) GoodFirstIssues(w io.Writer, params GoodFirstIssuesParams) error {
···
341
341
LoggedInUser *oauth.User
342
342
Notifications []*models.NotificationWithEntity
343
343
UnreadCount int
344
-
Page pagination.Page
344
+
Pagination pagination.Pagination
345
345
Total int64
346
346
}
347
347
···
968
968
Active string
969
969
Issues []models.Issue
970
970
LabelDefs map[string]*models.LabelDefinition
971
-
Page pagination.Page
971
+
Pagination pagination.Pagination
972
972
FilteringByOpen bool
973
973
}
974
974
+7
-7
appview/pages/templates/goodfirstissues/index.html
+7
-7
appview/pages/templates/goodfirstissues/index.html
···
130
130
</div>
131
131
{{ end }}
132
132
133
-
{{ if or (gt .Page.Offset 0) (eq (len .RepoGroups) .Page.Limit) }}
133
+
{{ if or .Pagination.HasPreviousPage .Pagination.HasNextPage }}
134
134
<div class="flex justify-center mt-8">
135
135
<div class="flex gap-2">
136
-
{{ if gt .Page.Offset 0 }}
137
-
{{ $prev := .Page.Previous }}
136
+
{{ if .Pagination.HasPreviousPage }}
137
+
{{ $prev := .Pagination.PreviousPage }}
138
138
<a
139
139
class="btn flex items-center gap-2 no-underline hover:no-underline dark:text-white dark:hover:bg-gray-700"
140
140
hx-boost="true"
141
-
href="/goodfirstissues?offset={{ $prev.Offset }}&limit={{ $prev.Limit }}"
141
+
href="/goodfirstissues?page={{ add $prev.No 1 }}&count={{ $prev.Count }}"
142
142
>
143
143
{{ i "chevron-left" "w-4 h-4" }}
144
144
previous
···
147
147
<div></div>
148
148
{{ end }}
149
149
150
-
{{ if eq (len .RepoGroups) .Page.Limit }}
151
-
{{ $next := .Page.Next }}
150
+
{{ if .Pagination.HasNextPage }}
151
+
{{ $next := .Pagination.NextPage }}
152
152
<a
153
153
class="btn flex items-center gap-2 no-underline hover:no-underline dark:text-white dark:hover:bg-gray-700"
154
154
hx-boost="true"
155
-
href="/goodfirstissues?offset={{ $next.Offset }}&limit={{ $next.Limit }}"
155
+
href="/goodfirstissues?page={{ add $next.No 1 }}&count={{ $next.Count }}"
156
156
>
157
157
next
158
158
{{ i "chevron-right" "w-4 h-4" }}
+6
-7
appview/pages/templates/notifications/list.html
+6
-7
appview/pages/templates/notifications/list.html
···
35
35
36
36
{{ define "pagination" }}
37
37
<div class="flex justify-end mt-4 gap-2">
38
-
{{ if gt .Page.Offset 0 }}
39
-
{{ $prev := .Page.Previous }}
38
+
{{ if .Pagination.HasPreviousPage }}
39
+
{{ $prev := .Pagination.PreviousPage }}
40
40
<a
41
41
class="btn flex items-center gap-2 no-underline hover:no-underline dark:text-white dark:hover:bg-gray-700"
42
42
hx-boost="true"
43
-
href = "/notifications?offset={{ $prev.Offset }}&limit={{ $prev.Limit }}"
43
+
href = "/notifications?page={{ add $prev.No 1 }}&count={{ $prev.Count }}"
44
44
>
45
45
{{ i "chevron-left" "w-4 h-4" }}
46
46
previous
···
49
49
<div></div>
50
50
{{ end }}
51
51
52
-
{{ $next := .Page.Next }}
53
-
{{ if lt $next.Offset .Total }}
54
-
{{ $next := .Page.Next }}
52
+
{{ if .Pagination.HasNextPage }}
53
+
{{ $next := .Pagination.NextPage }}
55
54
<a
56
55
class="btn flex items-center gap-2 no-underline hover:no-underline dark:text-white dark:hover:bg-gray-700"
57
56
hx-boost="true"
58
-
href = "/notifications?offset={{ $next.Offset }}&limit={{ $next.Limit }}"
57
+
href = "/notifications?page={{ add $next.No 1 }}&count={{ $next.Count }}"
59
58
>
60
59
next
61
60
{{ i "chevron-right" "w-4 h-4" }}
+6
-6
appview/pages/templates/repo/issues/issues.html
+6
-6
appview/pages/templates/repo/issues/issues.html
···
50
50
{{ $currentState = "open" }}
51
51
{{ end }}
52
52
53
-
{{ if gt .Page.Offset 0 }}
54
-
{{ $prev := .Page.Previous }}
53
+
{{ if .Pagination.HasPreviousPage }}
54
+
{{ $prev := .Pagination.PreviousPage }}
55
55
<a
56
56
class="btn flex items-center gap-2 no-underline hover:no-underline dark:text-white dark:hover:bg-gray-700"
57
57
hx-boost="true"
58
-
href = "/{{ $.RepoInfo.FullName }}/issues?state={{ $currentState }}&offset={{ $prev.Offset }}&limit={{ $prev.Limit }}"
58
+
href = "/{{ $.RepoInfo.FullName }}/issues?state={{ $currentState }}&page={{ add $prev.No 1 }}&count={{ $prev.Count }}"
59
59
>
60
60
{{ i "chevron-left" "w-4 h-4" }}
61
61
previous
···
64
64
<div></div>
65
65
{{ end }}
66
66
67
-
{{ if eq (len .Issues) .Page.Limit }}
68
-
{{ $next := .Page.Next }}
67
+
{{ if .Pagination.HasNextPage }}
68
+
{{ $next := .Pagination.NextPage }}
69
69
<a
70
70
class="btn flex items-center gap-2 no-underline hover:no-underline dark:text-white dark:hover:bg-gray-700"
71
71
hx-boost="true"
72
-
href = "/{{ $.RepoInfo.FullName }}/issues?state={{ $currentState }}&offset={{ $next.Offset }}&limit={{ $next.Limit }}"
72
+
href = "/{{ $.RepoInfo.FullName }}/issues?state={{ $currentState }}&page={{ add $next.No 1 }}&count={{ $next.Count }}"
73
73
>
74
74
next
75
75
{{ i "chevron-right" "w-4 h-4" }}
+61
-13
appview/pagination/page.go
+61
-13
appview/pagination/page.go
···
1
1
package pagination
2
2
3
-
type Page struct {
3
+
type Pagination struct {
4
4
Offset int // where to start from
5
-
Limit int // number of items in a page
5
+
Limit int // number of items on a single page
6
+
Total int // total number of items
7
+
}
8
+
9
+
type Page struct {
10
+
No int // page number
11
+
Count int // number of items on this page
12
+
}
13
+
14
+
func New(offset, limit, total int) Pagination {
15
+
return Pagination{
16
+
Offset: offset,
17
+
Limit: limit,
18
+
Total: total,
19
+
}
6
20
}
7
21
8
-
func FirstPage() Page {
22
+
func NewFromPage(page Page, total int) Pagination {
23
+
return New(page.No*page.Count, page.Count, total)
24
+
}
25
+
26
+
func (p Pagination) FirstPage() Page {
9
27
return Page{
10
-
Offset: 0,
11
-
Limit: 30,
28
+
No: 0,
29
+
Count: p.Limit,
12
30
}
13
31
}
14
32
15
-
func (p Page) Previous() Page {
33
+
func (p Pagination) CurrentPage() Page {
34
+
return Page{
35
+
No: p.Offset / p.Limit,
36
+
Count: p.Limit,
37
+
}
38
+
}
39
+
40
+
func (p Pagination) LastPage() Page {
41
+
return Page{
42
+
No: (p.Total - 1) / p.Limit,
43
+
Count: p.Limit,
44
+
}
45
+
}
46
+
47
+
func (p Pagination) PreviousPage() Page {
16
48
if p.Offset-p.Limit < 0 {
17
-
return FirstPage()
49
+
return p.FirstPage()
18
50
} else {
19
51
return Page{
20
-
Offset: p.Offset - p.Limit,
21
-
Limit: p.Limit,
52
+
No: (p.Offset - p.Limit) / p.Limit,
53
+
Count: p.Limit,
22
54
}
23
55
}
24
56
}
25
57
26
-
func (p Page) Next() Page {
27
-
return Page{
28
-
Offset: p.Offset + p.Limit,
29
-
Limit: p.Limit,
58
+
func (p Pagination) NextPage() Page {
59
+
if p.Offset+p.Limit >= p.Total {
60
+
return p.LastPage()
61
+
} else {
62
+
return Page{
63
+
No: (p.Offset + p.Limit) / p.Limit,
64
+
Count: p.Limit,
65
+
}
30
66
}
31
67
}
68
+
69
+
func (p Pagination) HasPreviousPage() bool {
70
+
return p.CurrentPage().No > 0
71
+
}
72
+
73
+
func (p Pagination) HasNextPage() bool {
74
+
return p.CurrentPage().No+1 < p.TotalPageCount()
75
+
}
76
+
77
+
func (p Pagination) TotalPageCount() int {
78
+
return (p.Total + p.Limit - 1) / p.Limit
79
+
}
+1
-1
appview/repo/feed.go
+1
-1
appview/repo/feed.go
+9
-6
appview/state/gfi.go
+9
-6
appview/state/gfi.go
···
20
20
21
21
page, ok := r.Context().Value("page").(pagination.Page)
22
22
if !ok {
23
-
page = pagination.FirstPage()
23
+
page = pagination.Page{No: 0, Count: 30}
24
24
}
25
25
26
26
goodFirstIssueLabel := fmt.Sprintf("at://%s/%s/%s", consts.TangledDid, tangled.LabelDefinitionNSID, "good-first-issue")
···
37
37
LoggedInUser: user,
38
38
RepoGroups: []*models.RepoGroup{},
39
39
LabelDefs: make(map[string]*models.LabelDefinition),
40
-
Page: page,
40
+
Pagination: pagination.NewFromPage(page, 0),
41
41
})
42
42
return
43
43
}
···
50
50
allIssues, err := db.GetIssuesPaginated(
51
51
s.db,
52
52
pagination.Page{
53
-
Limit: 500,
53
+
No: 0,
54
+
Count: 500,
54
55
},
55
56
db.FilterIn("repo_at", repoUris),
56
57
db.FilterEq("open", 1),
···
98
99
return sortedGroups[i].Repo.Name < sortedGroups[j].Repo.Name
99
100
})
100
101
101
-
groupStart := page.Offset
102
-
groupEnd := page.Offset + page.Limit
102
+
pagination := pagination.NewFromPage(page, len(sortedGroups))
103
+
104
+
groupStart := page.Count * page.No
105
+
groupEnd := page.Count * (page.No + 1)
103
106
if groupStart > len(sortedGroups) {
104
107
groupStart = len(sortedGroups)
105
108
}
···
145
148
LoggedInUser: user,
146
149
RepoGroups: paginatedGroups,
147
150
LabelDefs: labelDefsMap,
148
-
Page: page,
151
+
Pagination: pagination,
149
152
GfiLabel: labelDefsMap[goodFirstIssueLabel],
150
153
})
151
154
}