appview: implement pagination for pipelines index #521

closed
opened by ptr.pet targeting master from [deleted fork]: pipeline-paginated
+2 -2
appview/db/artifact.go
··· 37 37 return err 38 38 } 39 39 40 - func GetArtifact(e Execer, filters ...filter) ([]models.Artifact, error) { 40 + func GetArtifact(e Execer, filters ...Filter) ([]models.Artifact, error) { 41 41 var artifacts []models.Artifact 42 42 43 43 var conditions []string ··· 110 110 return artifacts, nil 111 111 } 112 112 113 - func DeleteArtifact(e Execer, filters ...filter) error { 113 + func DeleteArtifact(e Execer, filters ...Filter) error { 114 114 var conditions []string 115 115 var args []any 116 116 for _, filter := range filters {
+1 -1
appview/db/collaborators.go
··· 15 15 return err 16 16 } 17 17 18 - func DeleteCollaborator(e Execer, filters ...filter) error { 18 + func DeleteCollaborator(e Execer, filters ...Filter) error { 19 19 var conditions []string 20 20 var args []any 21 21 for _, filter := range filters {
+16 -16
appview/db/db.go
··· 1144 1144 return d.DB.Close() 1145 1145 } 1146 1146 1147 - type filter struct { 1147 + type Filter struct { 1148 1148 key string 1149 1149 arg any 1150 1150 cmp string 1151 1151 } 1152 1152 1153 - func newFilter(key, cmp string, arg any) filter { 1154 - return filter{ 1153 + func newFilter(key, cmp string, arg any) Filter { 1154 + return Filter{ 1155 1155 key: key, 1156 1156 arg: arg, 1157 1157 cmp: cmp, 1158 1158 } 1159 1159 } 1160 1160 1161 - func FilterEq(key string, arg any) filter { return newFilter(key, "=", arg) } 1162 - func FilterNotEq(key string, arg any) filter { return newFilter(key, "<>", arg) } 1163 - func FilterGte(key string, arg any) filter { return newFilter(key, ">=", arg) } 1164 - func FilterLte(key string, arg any) filter { return newFilter(key, "<=", arg) } 1165 - func FilterIs(key string, arg any) filter { return newFilter(key, "is", arg) } 1166 - func FilterIsNot(key string, arg any) filter { return newFilter(key, "is not", arg) } 1167 - func FilterIn(key string, arg any) filter { return newFilter(key, "in", arg) } 1168 - func FilterLike(key string, arg any) filter { return newFilter(key, "like", arg) } 1169 - func FilterNotLike(key string, arg any) filter { return newFilter(key, "not like", arg) } 1170 - func FilterContains(key string, arg any) filter { 1161 + func FilterEq(key string, arg any) Filter { return newFilter(key, "=", arg) } 1162 + func FilterNotEq(key string, arg any) Filter { return newFilter(key, "<>", arg) } 1163 + func FilterGte(key string, arg any) Filter { return newFilter(key, ">=", arg) } 1164 + func FilterLte(key string, arg any) Filter { return newFilter(key, "<=", arg) } 1165 + func FilterIs(key string, arg any) Filter { return newFilter(key, "is", arg) } 1166 + func FilterIsNot(key string, arg any) Filter { return newFilter(key, "is not", arg) } 1167 + func FilterIn(key string, arg any) Filter { return newFilter(key, "in", arg) } 1168 + func FilterLike(key string, arg any) Filter { return newFilter(key, "like", arg) } 1169 + func FilterNotLike(key string, arg any) Filter { return newFilter(key, "not like", arg) } 1170 + func FilterContains(key string, arg any) Filter { 1171 1171 return newFilter(key, "like", fmt.Sprintf("%%%v%%", arg)) 1172 1172 } 1173 - func FilterBetween(key string, arg1, arg2 any) filter { 1173 + func FilterBetween(key string, arg1, arg2 any) Filter { 1174 1174 return newFilter(key, "between", []any{arg1, arg2}) 1175 1175 } 1176 1176 1177 - func (f filter) Condition() string { 1177 + func (f Filter) Condition() string { 1178 1178 rv := reflect.ValueOf(f.arg) 1179 1179 kind := rv.Kind() 1180 1180 ··· 1200 1200 return fmt.Sprintf("%s %s ?", f.key, f.cmp) 1201 1201 } 1202 1202 1203 - func (f filter) Arg() []any { 1203 + func (f Filter) Arg() []any { 1204 1204 rv := reflect.ValueOf(f.arg) 1205 1205 kind := rv.Kind() 1206 1206 if (kind == reflect.Slice && rv.Type().Elem().Kind() != reflect.Uint8) || kind == reflect.Array {
+1 -1
appview/db/follow.go
··· 134 134 return result, nil 135 135 } 136 136 137 - func GetFollows(e Execer, limit int, filters ...filter) ([]models.Follow, error) { 137 + func GetFollows(e Execer, limit int, filters ...Filter) ([]models.Follow, error) { 138 138 var follows []models.Follow 139 139 140 140 var conditions []string
+7 -7
appview/db/issues.go
··· 82 82 return err 83 83 } 84 84 85 - func GetIssuesPaginated(e Execer, page pagination.Page, filters ...filter) ([]models.Issue, error) { 85 + func GetIssuesPaginated(e Execer, page pagination.Page, filters ...Filter) ([]models.Issue, error) { 86 86 issueMap := make(map[string]*models.Issue) // at-uri -> issue 87 87 88 88 var conditions []string ··· 243 243 return issues, nil 244 244 } 245 245 246 - func GetIssues(e Execer, filters ...filter) ([]models.Issue, error) { 246 + func GetIssues(e Execer, filters ...Filter) ([]models.Issue, error) { 247 247 return GetIssuesPaginated(e, pagination.Page{No: 0, Count: 30}, filters...) 248 248 } 249 249 ··· 310 310 return id, nil 311 311 } 312 312 313 - func DeleteIssueComments(e Execer, filters ...filter) error { 313 + func DeleteIssueComments(e Execer, filters ...Filter) error { 314 314 var conditions []string 315 315 var args []any 316 316 for _, filter := range filters { ··· 329 329 return err 330 330 } 331 331 332 - func GetIssueComments(e Execer, filters ...filter) ([]models.IssueComment, error) { 332 + func GetIssueComments(e Execer, filters ...Filter) ([]models.IssueComment, error) { 333 333 var comments []models.IssueComment 334 334 335 335 var conditions []string ··· 419 419 return comments, nil 420 420 } 421 421 422 - func DeleteIssues(e Execer, filters ...filter) error { 422 + func DeleteIssues(e Execer, filters ...Filter) error { 423 423 var conditions []string 424 424 var args []any 425 425 for _, filter := range filters { ··· 437 437 return err 438 438 } 439 439 440 - func CloseIssues(e Execer, filters ...filter) error { 440 + func CloseIssues(e Execer, filters ...Filter) error { 441 441 var conditions []string 442 442 var args []any 443 443 for _, filter := range filters { ··· 455 455 return err 456 456 } 457 457 458 - func ReopenIssues(e Execer, filters ...filter) error { 458 + func ReopenIssues(e Execer, filters ...Filter) error { 459 459 var conditions []string 460 460 var args []any 461 461 for _, filter := range filters {
+7 -7
appview/db/label.go
··· 59 59 return id, nil 60 60 } 61 61 62 - func DeleteLabelDefinition(e Execer, filters ...filter) error { 62 + func DeleteLabelDefinition(e Execer, filters ...Filter) error { 63 63 var conditions []string 64 64 var args []any 65 65 for _, filter := range filters { ··· 75 75 return err 76 76 } 77 77 78 - func GetLabelDefinitions(e Execer, filters ...filter) ([]models.LabelDefinition, error) { 78 + func GetLabelDefinitions(e Execer, filters ...Filter) ([]models.LabelDefinition, error) { 79 79 var labelDefinitions []models.LabelDefinition 80 80 var conditions []string 81 81 var args []any ··· 92 92 93 93 query := fmt.Sprintf( 94 94 ` 95 - select 95 + select 96 96 id, 97 97 did, 98 98 rkey, ··· 167 167 } 168 168 169 169 // helper to get exactly one label def 170 - func GetLabelDefinition(e Execer, filters ...filter) (*models.LabelDefinition, error) { 170 + func GetLabelDefinition(e Execer, filters ...Filter) (*models.LabelDefinition, error) { 171 171 labels, err := GetLabelDefinitions(e, filters...) 172 172 if err != nil { 173 173 return nil, err ··· 227 227 return id, nil 228 228 } 229 229 230 - func GetLabelOps(e Execer, filters ...filter) ([]models.LabelOp, error) { 230 + func GetLabelOps(e Execer, filters ...Filter) ([]models.LabelOp, error) { 231 231 var labelOps []models.LabelOp 232 232 var conditions []string 233 233 var args []any ··· 302 302 } 303 303 304 304 // get labels for a given list of subject URIs 305 - func GetLabels(e Execer, filters ...filter) (map[syntax.ATURI]models.LabelState, error) { 305 + func GetLabels(e Execer, filters ...Filter) (map[syntax.ATURI]models.LabelState, error) { 306 306 ops, err := GetLabelOps(e, filters...) 307 307 if err != nil { 308 308 return nil, err ··· 338 338 return results, nil 339 339 } 340 340 341 - func NewLabelApplicationCtx(e Execer, filters ...filter) (*models.LabelApplicationCtx, error) { 341 + func NewLabelApplicationCtx(e Execer, filters ...Filter) (*models.LabelApplicationCtx, error) { 342 342 labels, err := GetLabelDefinitions(e, filters...) 343 343 if err != nil { 344 344 return nil, err
+2 -2
appview/db/language.go
··· 9 9 "tangled.org/core/appview/models" 10 10 ) 11 11 12 - func GetRepoLanguages(e Execer, filters ...filter) ([]models.RepoLanguage, error) { 12 + func GetRepoLanguages(e Execer, filters ...Filter) ([]models.RepoLanguage, error) { 13 13 var conditions []string 14 14 var args []any 15 15 for _, filter := range filters { ··· 85 85 return nil 86 86 } 87 87 88 - func DeleteRepoLanguages(e Execer, filters ...filter) error { 88 + func DeleteRepoLanguages(e Execer, filters ...Filter) error { 89 89 var conditions []string 90 90 var args []any 91 91 for _, filter := range filters {
+4 -4
appview/db/notifications.go
··· 43 43 } 44 44 45 45 // GetNotificationsPaginated retrieves notifications with filters and pagination 46 - func GetNotificationsPaginated(e Execer, page pagination.Page, filters ...filter) ([]*models.Notification, error) { 46 + func GetNotificationsPaginated(e Execer, page pagination.Page, filters ...Filter) ([]*models.Notification, error) { 47 47 var conditions []string 48 48 var args []any 49 49 ··· 109 109 } 110 110 111 111 // GetNotificationsWithEntities retrieves notifications with their related entities 112 - func GetNotificationsWithEntities(e Execer, page pagination.Page, filters ...filter) ([]*models.NotificationWithEntity, error) { 112 + func GetNotificationsWithEntities(e Execer, page pagination.Page, filters ...Filter) ([]*models.NotificationWithEntity, error) { 113 113 var conditions []string 114 114 var args []any 115 115 ··· 246 246 } 247 247 248 248 // GetNotifications retrieves notifications with filters 249 - func GetNotifications(e Execer, filters ...filter) ([]*models.Notification, error) { 249 + func GetNotifications(e Execer, filters ...Filter) ([]*models.Notification, error) { 250 250 return GetNotificationsPaginated(e, pagination.Page{No: 0, Count: 30}, filters...) 251 251 } 252 252 253 - func CountNotifications(e Execer, filters ...filter) (int64, error) { 253 + func CountNotifications(e Execer, filters ...Filter) (int64, error) { 254 254 var conditions []string 255 255 var args []any 256 256 for _, filter := range filters {
+62 -14
appview/db/pipeline.go
··· 9 9 "tangled.org/core/appview/models" 10 10 ) 11 11 12 - func GetPipelines(e Execer, filters ...filter) ([]models.Pipeline, error) { 12 + func GetPipelines(e Execer, filters ...Filter) ([]models.Pipeline, error) { 13 13 var pipelines []models.Pipeline 14 14 15 15 var conditions []string ··· 168 168 169 169 // this is a mega query, but the most useful one: 170 170 // get N pipelines, for each one get the latest status of its N workflows 171 - func GetPipelineStatuses(e Execer, filters ...filter) ([]models.Pipeline, error) { 171 + func GetPipelineStatuses(e Execer, filters ...Filter) ([]models.Pipeline, error) { 172 172 var conditions []string 173 173 var args []any 174 174 for _, filter := range filters { ··· 183 183 } 184 184 185 185 query := fmt.Sprintf(` 186 + with ranked_pipelines as ( 187 + select 188 + p.id, 189 + p.knot, 190 + p.rkey, 191 + p.repo_owner, 192 + p.repo_name, 193 + p.sha, 194 + p.created, 195 + t.id, 196 + t.kind, 197 + t.push_ref, 198 + t.push_new_sha, 199 + t.push_old_sha, 200 + t.pr_source_branch, 201 + t.pr_target_branch, 202 + t.pr_source_sha, 203 + t.pr_action, 204 + row_number() over (order by p.created desc) as row_num 205 + from 206 + pipelines p 207 + join 208 + triggers t ON p.trigger_id = t.id 209 + ) 186 210 select 187 211 p.id, 188 212 p.knot, ··· 191 215 p.repo_name, 192 216 p.sha, 193 217 p.created, 194 - t.id, 195 - t.kind, 196 - t.push_ref, 197 - t.push_new_sha, 198 - t.push_old_sha, 199 - t.pr_source_branch, 200 - t.pr_target_branch, 201 - t.pr_source_sha, 202 - t.pr_action 218 + p.id, 219 + p.kind, 220 + p.push_ref, 221 + p.push_new_sha, 222 + p.push_old_sha, 223 + p.pr_source_branch, 224 + p.pr_target_branch, 225 + p.pr_source_sha, 226 + p.pr_action 203 227 from 204 - pipelines p 205 - join 206 - triggers t ON p.trigger_id = t.id 228 + ranked_pipelines p 207 229 %s 208 230 `, whereClause) 209 231 ··· 363 385 364 386 return all, nil 365 387 } 388 + 389 + // get pipeline counts, implement with filters 390 + func GetPipelineCount(e Execer, filters ...Filter) (int, error) { 391 + var conditions []string 392 + var args []any 393 + for _, filter := range filters { 394 + conditions = append(conditions, filter.Condition()) 395 + args = append(args, filter.Arg()...) 396 + } 397 + 398 + whereClause := "" 399 + if conditions != nil { 400 + whereClause = " where " + strings.Join(conditions, " and ") 401 + } 402 + 403 + query := fmt.Sprintf(`select count(*) as count from pipelines %s`, whereClause) 404 + 405 + row := e.QueryRow(query, args...) 406 + 407 + var count int 408 + if err := row.Scan(&count); err != nil { 409 + return 0, err 410 + } 411 + 412 + return count, nil 413 + }
+1 -1
appview/db/profile.go
··· 197 197 return tx.Commit() 198 198 } 199 199 200 - func GetProfiles(e Execer, filters ...filter) (map[string]*models.Profile, error) { 200 + func GetProfiles(e Execer, filters ...Filter) (map[string]*models.Profile, error) { 201 201 var conditions []string 202 202 var args []any 203 203 for _, filter := range filters {
+6 -6
appview/db/pulls.go
··· 110 110 return pullId - 1, err 111 111 } 112 112 113 - func GetPullsWithLimit(e Execer, limit int, filters ...filter) ([]*models.Pull, error) { 113 + func GetPullsWithLimit(e Execer, limit int, filters ...Filter) ([]*models.Pull, error) { 114 114 pulls := make(map[syntax.ATURI]*models.Pull) 115 115 116 116 var conditions []string ··· 277 277 return orderedByPullId, nil 278 278 } 279 279 280 - func GetPulls(e Execer, filters ...filter) ([]*models.Pull, error) { 280 + func GetPulls(e Execer, filters ...Filter) ([]*models.Pull, error) { 281 281 return GetPullsWithLimit(e, 0, filters...) 282 282 } 283 283 ··· 294 294 } 295 295 296 296 // mapping from pull -> pull submissions 297 - func GetPullSubmissions(e Execer, filters ...filter) (map[syntax.ATURI][]*models.PullSubmission, error) { 297 + func GetPullSubmissions(e Execer, filters ...Filter) (map[syntax.ATURI][]*models.PullSubmission, error) { 298 298 var conditions []string 299 299 var args []any 300 300 for _, filter := range filters { ··· 391 391 return m, nil 392 392 } 393 393 394 - func GetPullComments(e Execer, filters ...filter) ([]models.PullComment, error) { 394 + func GetPullComments(e Execer, filters ...Filter) ([]models.PullComment, error) { 395 395 var conditions []string 396 396 var args []any 397 397 for _, filter := range filters { ··· 600 600 return err 601 601 } 602 602 603 - func SetPullParentChangeId(e Execer, parentChangeId string, filters ...filter) error { 603 + func SetPullParentChangeId(e Execer, parentChangeId string, filters ...Filter) error { 604 604 var conditions []string 605 605 var args []any 606 606 ··· 624 624 625 625 // Only used when stacking to update contents in the event of a rebase (the interdiff should be empty). 626 626 // otherwise submissions are immutable 627 - func UpdatePull(e Execer, newPatch, sourceRev string, filters ...filter) error { 627 + func UpdatePull(e Execer, newPatch, sourceRev string, filters ...Filter) error { 628 628 var conditions []string 629 629 var args []any 630 630
+1 -1
appview/db/punchcard.go
··· 20 20 return err 21 21 } 22 22 23 - func MakePunchcard(e Execer, filters ...filter) (*models.Punchcard, error) { 23 + func MakePunchcard(e Execer, filters ...Filter) (*models.Punchcard, error) { 24 24 punchcard := &models.Punchcard{} 25 25 now := time.Now() 26 26 startOfYear := time.Date(now.Year(), 1, 1, 0, 0, 0, 0, time.UTC)
+3 -3
appview/db/registration.go
··· 9 9 "tangled.org/core/appview/models" 10 10 ) 11 11 12 - func GetRegistrations(e Execer, filters ...filter) ([]models.Registration, error) { 12 + func GetRegistrations(e Execer, filters ...Filter) ([]models.Registration, error) { 13 13 var registrations []models.Registration 14 14 15 15 var conditions []string ··· 69 69 return registrations, nil 70 70 } 71 71 72 - func MarkRegistered(e Execer, filters ...filter) error { 72 + func MarkRegistered(e Execer, filters ...Filter) error { 73 73 var conditions []string 74 74 var args []any 75 75 for _, filter := range filters { ··· 94 94 return err 95 95 } 96 96 97 - func DeleteKnot(e Execer, filters ...filter) error { 97 + func DeleteKnot(e Execer, filters ...Filter) error { 98 98 var conditions []string 99 99 var args []any 100 100 for _, filter := range filters {
+5 -5
appview/db/repos.go
··· 41 41 return p 42 42 } 43 43 44 - func GetRepos(e Execer, limit int, filters ...filter) ([]models.Repo, error) { 44 + func GetRepos(e Execer, limit int, filters ...Filter) ([]models.Repo, error) { 45 45 repoMap := make(map[syntax.ATURI]*models.Repo) 46 46 47 47 var conditions []string ··· 312 312 } 313 313 314 314 // helper to get exactly one repo 315 - func GetRepo(e Execer, filters ...filter) (*models.Repo, error) { 315 + func GetRepo(e Execer, filters ...Filter) (*models.Repo, error) { 316 316 repos, err := GetRepos(e, 0, filters...) 317 317 if err != nil { 318 318 return nil, err ··· 329 329 return &repos[0], nil 330 330 } 331 331 332 - func CountRepos(e Execer, filters ...filter) (int64, error) { 332 + func CountRepos(e Execer, filters ...Filter) (int64, error) { 333 333 var conditions []string 334 334 var args []any 335 335 for _, filter := range filters { ··· 521 521 return err 522 522 } 523 523 524 - func UnsubscribeLabel(e Execer, filters ...filter) error { 524 + func UnsubscribeLabel(e Execer, filters ...Filter) error { 525 525 var conditions []string 526 526 var args []any 527 527 for _, filter := range filters { ··· 539 539 return err 540 540 } 541 541 542 - func GetRepoLabels(e Execer, filters ...filter) ([]models.RepoLabel, error) { 542 + func GetRepoLabels(e Execer, filters ...Filter) ([]models.RepoLabel, error) { 543 543 var conditions []string 544 544 var args []any 545 545 for _, filter := range filters {
+5 -5
appview/db/spindle.go
··· 9 9 "tangled.org/core/appview/models" 10 10 ) 11 11 12 - func GetSpindles(e Execer, filters ...filter) ([]models.Spindle, error) { 12 + func GetSpindles(e Execer, filters ...Filter) ([]models.Spindle, error) { 13 13 var spindles []models.Spindle 14 14 15 15 var conditions []string ··· 91 91 return err 92 92 } 93 93 94 - func VerifySpindle(e Execer, filters ...filter) (int64, error) { 94 + func VerifySpindle(e Execer, filters ...Filter) (int64, error) { 95 95 var conditions []string 96 96 var args []any 97 97 for _, filter := range filters { ··· 114 114 return res.RowsAffected() 115 115 } 116 116 117 - func DeleteSpindle(e Execer, filters ...filter) error { 117 + func DeleteSpindle(e Execer, filters ...Filter) error { 118 118 var conditions []string 119 119 var args []any 120 120 for _, filter := range filters { ··· 144 144 return err 145 145 } 146 146 147 - func RemoveSpindleMember(e Execer, filters ...filter) error { 147 + func RemoveSpindleMember(e Execer, filters ...Filter) error { 148 148 var conditions []string 149 149 var args []any 150 150 for _, filter := range filters { ··· 163 163 return err 164 164 } 165 165 166 - func GetSpindleMembers(e Execer, filters ...filter) ([]models.SpindleMember, error) { 166 + func GetSpindleMembers(e Execer, filters ...Filter) ([]models.SpindleMember, error) { 167 167 var members []models.SpindleMember 168 168 169 169 var conditions []string
+2 -2
appview/db/star.go
··· 130 130 func GetStarStatuses(e Execer, userDid string, repoAts []syntax.ATURI) (map[string]bool, error) { 131 131 return getStarStatuses(e, userDid, repoAts) 132 132 } 133 - func GetStars(e Execer, limit int, filters ...filter) ([]models.Star, error) { 133 + func GetStars(e Execer, limit int, filters ...Filter) ([]models.Star, error) { 134 134 var conditions []string 135 135 var args []any 136 136 for _, filter := range filters { ··· 223 223 return stars, nil 224 224 } 225 225 226 - func CountStars(e Execer, filters ...filter) (int64, error) { 226 + func CountStars(e Execer, filters ...Filter) (int64, error) { 227 227 var conditions []string 228 228 var args []any 229 229 for _, filter := range filters {
+3 -3
appview/db/strings.go
··· 44 44 return err 45 45 } 46 46 47 - func GetStrings(e Execer, limit int, filters ...filter) ([]models.String, error) { 47 + func GetStrings(e Execer, limit int, filters ...Filter) ([]models.String, error) { 48 48 var all []models.String 49 49 50 50 var conditions []string ··· 127 127 return all, nil 128 128 } 129 129 130 - func CountStrings(e Execer, filters ...filter) (int64, error) { 130 + func CountStrings(e Execer, filters ...Filter) (int64, error) { 131 131 var conditions []string 132 132 var args []any 133 133 for _, filter := range filters { ··· 151 151 return count, nil 152 152 } 153 153 154 - func DeleteString(e Execer, filters ...filter) error { 154 + func DeleteString(e Execer, filters ...Filter) error { 155 155 var conditions []string 156 156 var args []any 157 157 for _, filter := range filters {
+3 -3
appview/db/timeline.go
··· 84 84 } 85 85 86 86 func getTimelineRepos(e Execer, limit int, loggedInUserDid string, userIsFollowing []string) ([]models.TimelineEvent, error) { 87 - filters := make([]filter, 0) 87 + filters := make([]Filter, 0) 88 88 if userIsFollowing != nil { 89 89 filters = append(filters, FilterIn("did", userIsFollowing)) 90 90 } ··· 144 144 } 145 145 146 146 func getTimelineStars(e Execer, limit int, loggedInUserDid string, userIsFollowing []string) ([]models.TimelineEvent, error) { 147 - filters := make([]filter, 0) 147 + filters := make([]Filter, 0) 148 148 if userIsFollowing != nil { 149 149 filters = append(filters, FilterIn("starred_by_did", userIsFollowing)) 150 150 } ··· 190 190 } 191 191 192 192 func getTimelineFollows(e Execer, limit int, loggedInUserDid string, userIsFollowing []string) ([]models.TimelineEvent, error) { 193 - filters := make([]filter, 0) 193 + filters := make([]Filter, 0) 194 194 if userIsFollowing != nil { 195 195 filters = append(filters, FilterIn("user_did", userIsFollowing)) 196 196 }
+1
appview/pages/pages.go
··· 1344 1344 LoggedInUser *oauth.User 1345 1345 RepoInfo repoinfo.RepoInfo 1346 1346 Pipelines []models.Pipeline 1347 + Pagination pagination.Pagination 1347 1348 Active string 1348 1349 } 1349 1350
+32 -1
appview/pages/templates/repo/pipelines/pipelines.html
··· 7 7 {{ end }} 8 8 9 9 {{ define "repoContent" }} 10 - <div class="flex justify-between items-center gap-4"> 10 + <div class="flex flex-col justify-between items-center gap-4"> 11 11 <div class="w-full flex flex-col gap-2"> 12 12 {{ range .Pipelines }} 13 13 {{ block "pipeline" (list $ .) }} {{ end }} ··· 17 17 </p> 18 18 {{ end }} 19 19 </div> 20 + {{ block "pagination" . }} {{ end }} 20 21 </div> 21 22 {{ end }} 22 23 ··· 100 101 </div> 101 102 {{ end }} 102 103 {{ end }} 104 + 105 + {{ define "pagination" }} 106 + <div class="flex place-self-end mt-4 gap-2"> 107 + {{ if .Pagination.HasPreviousPage }} 108 + {{ $prev := .Pagination.PreviousPage }} 109 + <a 110 + class="btn flex items-center gap-2 no-underline hover:no-underline dark:text-white dark:hover:bg-gray-700" 111 + hx-boost="true" 112 + href = "/{{ $.RepoInfo.FullName }}/pipelines?page={{ add $prev.No 1 }}&count={{ $prev.Count }}" 113 + > 114 + {{ i "chevron-left" "w-4 h-4" }} 115 + previous 116 + </a> 117 + {{ else }} 118 + <div></div> 119 + {{ end }} 120 + 121 + {{ if .Pagination.HasNextPage }} 122 + {{ $next := .Pagination.NextPage }} 123 + <a 124 + class="btn flex items-center gap-2 no-underline hover:no-underline dark:text-white dark:hover:bg-gray-700" 125 + hx-boost="true" 126 + href = "/{{ $.RepoInfo.FullName }}/pipelines?page={{ add $next.No 1 }}&count={{ $next.Count }}" 127 + > 128 + next 129 + {{ i "chevron-right" "w-4 h-4" }} 130 + </a> 131 + {{ end }} 132 + </div> 133 + {{ end }}
+29 -3
appview/pipelines/pipelines.go
··· 13 13 "tangled.org/core/appview/db" 14 14 "tangled.org/core/appview/oauth" 15 15 "tangled.org/core/appview/pages" 16 + "tangled.org/core/appview/pagination" 16 17 "tangled.org/core/appview/reporesolver" 17 18 "tangled.org/core/eventconsumer" 18 19 "tangled.org/core/idresolver" ··· 72 73 } 73 74 74 75 repoInfo := f.RepoInfo(user) 75 - 76 - ps, err := db.GetPipelineStatuses( 77 - p.db, 76 + filters := []db.Filter{ 78 77 db.FilterEq("repo_owner", repoInfo.OwnerDid), 79 78 db.FilterEq("repo_name", repoInfo.Name), 80 79 db.FilterEq("knot", repoInfo.Knot), 80 + } 81 + 82 + page, ok := r.Context().Value("page").(pagination.Page) 83 + if !ok { 84 + l.Error("failed to get page") 85 + page = pagination.Page{No: 0, Count: 16} 86 + } 87 + pipelinesCount, err := db.GetPipelineCount(p.db, filters...) 88 + if err != nil { 89 + l.Error("failed to get pipeline count", "err", err) 90 + p.pages.Notice(w, "pipelines", "Failed to load pipelines. Try again later.") 91 + return 92 + } 93 + paginate := pagination.NewFromPage(page, pipelinesCount) 94 + 95 + currentPage := paginate.CurrentPage() 96 + filters = append(filters, db.FilterBetween( 97 + "row_num", 98 + currentPage.Count*currentPage.No+1, 99 + currentPage.Count*(currentPage.No+1), 100 + )) 101 + 102 + ps, err := db.GetPipelineStatuses( 103 + p.db, 104 + filters..., 81 105 ) 82 106 if err != nil { 83 107 l.Error("failed to query db", "err", err) 108 + p.pages.Notice(w, "pipelines", "Failed to load pipelines. Try again later.") 84 109 return 85 110 } 86 111 87 112 p.pages.Pipelines(w, pages.PipelinesParams{ 88 113 LoggedInUser: user, 89 114 RepoInfo: repoInfo, 115 + Pagination: paginate, 90 116 Pipelines: ps, 91 117 }) 92 118 }
+1 -1
appview/pipelines/router.go
··· 9 9 10 10 func (p *Pipelines) Router(mw *middleware.Middleware) http.Handler { 11 11 r := chi.NewRouter() 12 - r.Get("/", p.Index) 12 + r.With(middleware.Paginate(16)).Get("/", p.Index) 13 13 r.Get("/{pipeline}/workflow/{workflow}", p.Workflow) 14 14 r.Get("/{pipeline}/workflow/{workflow}/logs", p.Logs) 15 15