From 70b4207f418a39f544c7a3f2994251db0e44211e Mon Sep 17 00:00:00 2001 From: dusk Date: Wed, 20 Aug 2025 23:27:42 +0300 Subject: [PATCH] appview: implement pagination for pipelines index Change-Id: usozmpkmzzzlvrotyyumquvwtrwuulqt Signed-off-by: dusk --- appview/db/artifact.go | 4 +- appview/db/collaborators.go | 2 +- appview/db/db.go | 32 ++++---- appview/db/follow.go | 2 +- appview/db/issues.go | 14 ++-- appview/db/label.go | 14 ++-- appview/db/language.go | 4 +- appview/db/notifications.go | 8 +- appview/db/pipeline.go | 76 +++++++++++++++---- appview/db/profile.go | 2 +- appview/db/pulls.go | 12 +-- appview/db/punchcard.go | 2 +- appview/db/registration.go | 6 +- appview/db/repos.go | 10 +-- appview/db/spindle.go | 10 +-- appview/db/star.go | 4 +- appview/db/strings.go | 6 +- appview/db/timeline.go | 6 +- appview/pages/pages.go | 1 + .../templates/repo/pipelines/pipelines.html | 33 +++++++- appview/pipelines/pipelines.go | 32 +++++++- appview/pipelines/router.go | 2 +- 22 files changed, 194 insertions(+), 88 deletions(-) diff --git a/appview/db/artifact.go b/appview/db/artifact.go index 407ff3a3..1c6b7460 100644 --- a/appview/db/artifact.go +++ b/appview/db/artifact.go @@ -37,7 +37,7 @@ func AddArtifact(e Execer, artifact models.Artifact) error { return err } -func GetArtifact(e Execer, filters ...filter) ([]models.Artifact, error) { +func GetArtifact(e Execer, filters ...Filter) ([]models.Artifact, error) { var artifacts []models.Artifact var conditions []string @@ -110,7 +110,7 @@ func GetArtifact(e Execer, filters ...filter) ([]models.Artifact, error) { return artifacts, nil } -func DeleteArtifact(e Execer, filters ...filter) error { +func DeleteArtifact(e Execer, filters ...Filter) error { var conditions []string var args []any for _, filter := range filters { diff --git a/appview/db/collaborators.go b/appview/db/collaborators.go index aaa8f81c..bccfb884 100644 --- a/appview/db/collaborators.go +++ b/appview/db/collaborators.go @@ -15,7 +15,7 @@ func AddCollaborator(e Execer, c models.Collaborator) error { return err } -func DeleteCollaborator(e Execer, filters ...filter) error { +func DeleteCollaborator(e Execer, filters ...Filter) error { var conditions []string var args []any for _, filter := range filters { diff --git a/appview/db/db.go b/appview/db/db.go index f440a30e..cfad17fa 100644 --- a/appview/db/db.go +++ b/appview/db/db.go @@ -1144,37 +1144,37 @@ func (d *DB) Close() error { return d.DB.Close() } -type filter struct { +type Filter struct { key string arg any cmp string } -func newFilter(key, cmp string, arg any) filter { - return filter{ +func newFilter(key, cmp string, arg any) Filter { + return Filter{ key: key, arg: arg, cmp: cmp, } } -func FilterEq(key string, arg any) filter { return newFilter(key, "=", arg) } -func FilterNotEq(key string, arg any) filter { return newFilter(key, "<>", arg) } -func FilterGte(key string, arg any) filter { return newFilter(key, ">=", arg) } -func FilterLte(key string, arg any) filter { return newFilter(key, "<=", arg) } -func FilterIs(key string, arg any) filter { return newFilter(key, "is", arg) } -func FilterIsNot(key string, arg any) filter { return newFilter(key, "is not", arg) } -func FilterIn(key string, arg any) filter { return newFilter(key, "in", arg) } -func FilterLike(key string, arg any) filter { return newFilter(key, "like", arg) } -func FilterNotLike(key string, arg any) filter { return newFilter(key, "not like", arg) } -func FilterContains(key string, arg any) filter { +func FilterEq(key string, arg any) Filter { return newFilter(key, "=", arg) } +func FilterNotEq(key string, arg any) Filter { return newFilter(key, "<>", arg) } +func FilterGte(key string, arg any) Filter { return newFilter(key, ">=", arg) } +func FilterLte(key string, arg any) Filter { return newFilter(key, "<=", arg) } +func FilterIs(key string, arg any) Filter { return newFilter(key, "is", arg) } +func FilterIsNot(key string, arg any) Filter { return newFilter(key, "is not", arg) } +func FilterIn(key string, arg any) Filter { return newFilter(key, "in", arg) } +func FilterLike(key string, arg any) Filter { return newFilter(key, "like", arg) } +func FilterNotLike(key string, arg any) Filter { return newFilter(key, "not like", arg) } +func FilterContains(key string, arg any) Filter { return newFilter(key, "like", fmt.Sprintf("%%%v%%", arg)) } -func FilterBetween(key string, arg1, arg2 any) filter { +func FilterBetween(key string, arg1, arg2 any) Filter { return newFilter(key, "between", []any{arg1, arg2}) } -func (f filter) Condition() string { +func (f Filter) Condition() string { rv := reflect.ValueOf(f.arg) kind := rv.Kind() @@ -1200,7 +1200,7 @@ func (f filter) Condition() string { return fmt.Sprintf("%s %s ?", f.key, f.cmp) } -func (f filter) Arg() []any { +func (f Filter) Arg() []any { rv := reflect.ValueOf(f.arg) kind := rv.Kind() if (kind == reflect.Slice && rv.Type().Elem().Kind() != reflect.Uint8) || kind == reflect.Array { diff --git a/appview/db/follow.go b/appview/db/follow.go index f69d4f56..3f98a2ee 100644 --- a/appview/db/follow.go +++ b/appview/db/follow.go @@ -134,7 +134,7 @@ func GetFollowerFollowingCounts(e Execer, dids []string) (map[string]models.Foll return result, nil } -func GetFollows(e Execer, limit int, filters ...filter) ([]models.Follow, error) { +func GetFollows(e Execer, limit int, filters ...Filter) ([]models.Follow, error) { var follows []models.Follow var conditions []string diff --git a/appview/db/issues.go b/appview/db/issues.go index c13ff146..f49e2398 100644 --- a/appview/db/issues.go +++ b/appview/db/issues.go @@ -82,7 +82,7 @@ func updateIssue(tx *sql.Tx, issue *models.Issue) error { return err } -func GetIssuesPaginated(e Execer, page pagination.Page, filters ...filter) ([]models.Issue, error) { +func GetIssuesPaginated(e Execer, page pagination.Page, filters ...Filter) ([]models.Issue, error) { issueMap := make(map[string]*models.Issue) // at-uri -> issue var conditions []string @@ -243,7 +243,7 @@ func GetIssuesPaginated(e Execer, page pagination.Page, filters ...filter) ([]mo return issues, nil } -func GetIssues(e Execer, filters ...filter) ([]models.Issue, error) { +func GetIssues(e Execer, filters ...Filter) ([]models.Issue, error) { return GetIssuesPaginated(e, pagination.Page{No: 0, Count: 30}, filters...) } @@ -310,7 +310,7 @@ func AddIssueComment(e Execer, c models.IssueComment) (int64, error) { return id, nil } -func DeleteIssueComments(e Execer, filters ...filter) error { +func DeleteIssueComments(e Execer, filters ...Filter) error { var conditions []string var args []any for _, filter := range filters { @@ -329,7 +329,7 @@ func DeleteIssueComments(e Execer, filters ...filter) error { return err } -func GetIssueComments(e Execer, filters ...filter) ([]models.IssueComment, error) { +func GetIssueComments(e Execer, filters ...Filter) ([]models.IssueComment, error) { var comments []models.IssueComment var conditions []string @@ -419,7 +419,7 @@ func GetIssueComments(e Execer, filters ...filter) ([]models.IssueComment, error return comments, nil } -func DeleteIssues(e Execer, filters ...filter) error { +func DeleteIssues(e Execer, filters ...Filter) error { var conditions []string var args []any for _, filter := range filters { @@ -437,7 +437,7 @@ func DeleteIssues(e Execer, filters ...filter) error { return err } -func CloseIssues(e Execer, filters ...filter) error { +func CloseIssues(e Execer, filters ...Filter) error { var conditions []string var args []any for _, filter := range filters { @@ -455,7 +455,7 @@ func CloseIssues(e Execer, filters ...filter) error { return err } -func ReopenIssues(e Execer, filters ...filter) error { +func ReopenIssues(e Execer, filters ...Filter) error { var conditions []string var args []any for _, filter := range filters { diff --git a/appview/db/label.go b/appview/db/label.go index e323ebb9..a1ecf154 100644 --- a/appview/db/label.go +++ b/appview/db/label.go @@ -59,7 +59,7 @@ func AddLabelDefinition(e Execer, l *models.LabelDefinition) (int64, error) { return id, nil } -func DeleteLabelDefinition(e Execer, filters ...filter) error { +func DeleteLabelDefinition(e Execer, filters ...Filter) error { var conditions []string var args []any for _, filter := range filters { @@ -75,7 +75,7 @@ func DeleteLabelDefinition(e Execer, filters ...filter) error { return err } -func GetLabelDefinitions(e Execer, filters ...filter) ([]models.LabelDefinition, error) { +func GetLabelDefinitions(e Execer, filters ...Filter) ([]models.LabelDefinition, error) { var labelDefinitions []models.LabelDefinition var conditions []string var args []any @@ -92,7 +92,7 @@ func GetLabelDefinitions(e Execer, filters ...filter) ([]models.LabelDefinition, query := fmt.Sprintf( ` - select + select id, did, rkey, @@ -167,7 +167,7 @@ func GetLabelDefinitions(e Execer, filters ...filter) ([]models.LabelDefinition, } // helper to get exactly one label def -func GetLabelDefinition(e Execer, filters ...filter) (*models.LabelDefinition, error) { +func GetLabelDefinition(e Execer, filters ...Filter) (*models.LabelDefinition, error) { labels, err := GetLabelDefinitions(e, filters...) if err != nil { return nil, err @@ -227,7 +227,7 @@ func AddLabelOp(e Execer, l *models.LabelOp) (int64, error) { return id, nil } -func GetLabelOps(e Execer, filters ...filter) ([]models.LabelOp, error) { +func GetLabelOps(e Execer, filters ...Filter) ([]models.LabelOp, error) { var labelOps []models.LabelOp var conditions []string var args []any @@ -302,7 +302,7 @@ func GetLabelOps(e Execer, filters ...filter) ([]models.LabelOp, error) { } // get labels for a given list of subject URIs -func GetLabels(e Execer, filters ...filter) (map[syntax.ATURI]models.LabelState, error) { +func GetLabels(e Execer, filters ...Filter) (map[syntax.ATURI]models.LabelState, error) { ops, err := GetLabelOps(e, filters...) if err != nil { return nil, err @@ -338,7 +338,7 @@ func GetLabels(e Execer, filters ...filter) (map[syntax.ATURI]models.LabelState, return results, nil } -func NewLabelApplicationCtx(e Execer, filters ...filter) (*models.LabelApplicationCtx, error) { +func NewLabelApplicationCtx(e Execer, filters ...Filter) (*models.LabelApplicationCtx, error) { labels, err := GetLabelDefinitions(e, filters...) if err != nil { return nil, err diff --git a/appview/db/language.go b/appview/db/language.go index 19adb648..1ea5f57e 100644 --- a/appview/db/language.go +++ b/appview/db/language.go @@ -9,7 +9,7 @@ import ( "tangled.org/core/appview/models" ) -func GetRepoLanguages(e Execer, filters ...filter) ([]models.RepoLanguage, error) { +func GetRepoLanguages(e Execer, filters ...Filter) ([]models.RepoLanguage, error) { var conditions []string var args []any for _, filter := range filters { @@ -85,7 +85,7 @@ func InsertRepoLanguages(e Execer, langs []models.RepoLanguage) error { return nil } -func DeleteRepoLanguages(e Execer, filters ...filter) error { +func DeleteRepoLanguages(e Execer, filters ...Filter) error { var conditions []string var args []any for _, filter := range filters { diff --git a/appview/db/notifications.go b/appview/db/notifications.go index 0584e8f2..288e5bea 100644 --- a/appview/db/notifications.go +++ b/appview/db/notifications.go @@ -43,7 +43,7 @@ func (d *DB) CreateNotification(ctx context.Context, notification *models.Notifi } // GetNotificationsPaginated retrieves notifications with filters and pagination -func GetNotificationsPaginated(e Execer, page pagination.Page, filters ...filter) ([]*models.Notification, error) { +func GetNotificationsPaginated(e Execer, page pagination.Page, filters ...Filter) ([]*models.Notification, error) { var conditions []string var args []any @@ -109,7 +109,7 @@ func GetNotificationsPaginated(e Execer, page pagination.Page, filters ...filter } // GetNotificationsWithEntities retrieves notifications with their related entities -func GetNotificationsWithEntities(e Execer, page pagination.Page, filters ...filter) ([]*models.NotificationWithEntity, error) { +func GetNotificationsWithEntities(e Execer, page pagination.Page, filters ...Filter) ([]*models.NotificationWithEntity, error) { var conditions []string var args []any @@ -246,11 +246,11 @@ func GetNotificationsWithEntities(e Execer, page pagination.Page, filters ...fil } // GetNotifications retrieves notifications with filters -func GetNotifications(e Execer, filters ...filter) ([]*models.Notification, error) { +func GetNotifications(e Execer, filters ...Filter) ([]*models.Notification, error) { return GetNotificationsPaginated(e, pagination.Page{No: 0, Count: 30}, filters...) } -func CountNotifications(e Execer, filters ...filter) (int64, error) { +func CountNotifications(e Execer, filters ...Filter) (int64, error) { var conditions []string var args []any for _, filter := range filters { diff --git a/appview/db/pipeline.go b/appview/db/pipeline.go index 04eacb3d..8b30dbef 100644 --- a/appview/db/pipeline.go +++ b/appview/db/pipeline.go @@ -9,7 +9,7 @@ import ( "tangled.org/core/appview/models" ) -func GetPipelines(e Execer, filters ...filter) ([]models.Pipeline, error) { +func GetPipelines(e Execer, filters ...Filter) ([]models.Pipeline, error) { var pipelines []models.Pipeline var conditions []string @@ -168,7 +168,7 @@ func AddPipelineStatus(e Execer, status models.PipelineStatus) error { // this is a mega query, but the most useful one: // get N pipelines, for each one get the latest status of its N workflows -func GetPipelineStatuses(e Execer, filters ...filter) ([]models.Pipeline, error) { +func GetPipelineStatuses(e Execer, filters ...Filter) ([]models.Pipeline, error) { var conditions []string var args []any for _, filter := range filters { @@ -183,6 +183,30 @@ func GetPipelineStatuses(e Execer, filters ...filter) ([]models.Pipeline, error) } query := fmt.Sprintf(` + with ranked_pipelines as ( + select + p.id, + p.knot, + p.rkey, + p.repo_owner, + p.repo_name, + p.sha, + p.created, + t.id, + t.kind, + t.push_ref, + t.push_new_sha, + t.push_old_sha, + t.pr_source_branch, + t.pr_target_branch, + t.pr_source_sha, + t.pr_action, + row_number() over (order by p.created desc) as row_num + from + pipelines p + join + triggers t ON p.trigger_id = t.id + ) select p.id, p.knot, @@ -191,19 +215,17 @@ func GetPipelineStatuses(e Execer, filters ...filter) ([]models.Pipeline, error) p.repo_name, p.sha, p.created, - t.id, - t.kind, - t.push_ref, - t.push_new_sha, - t.push_old_sha, - t.pr_source_branch, - t.pr_target_branch, - t.pr_source_sha, - t.pr_action + p.id, + p.kind, + p.push_ref, + p.push_new_sha, + p.push_old_sha, + p.pr_source_branch, + p.pr_target_branch, + p.pr_source_sha, + p.pr_action from - pipelines p - join - triggers t ON p.trigger_id = t.id + ranked_pipelines p %s `, whereClause) @@ -363,3 +385,29 @@ func GetPipelineStatuses(e Execer, filters ...filter) ([]models.Pipeline, error) return all, nil } + +// get pipeline counts, implement with filters +func GetPipelineCount(e Execer, filters ...Filter) (int, error) { + var conditions []string + var args []any + for _, filter := range filters { + conditions = append(conditions, filter.Condition()) + args = append(args, filter.Arg()...) + } + + whereClause := "" + if conditions != nil { + whereClause = " where " + strings.Join(conditions, " and ") + } + + query := fmt.Sprintf(`select count(*) as count from pipelines %s`, whereClause) + + row := e.QueryRow(query, args...) + + var count int + if err := row.Scan(&count); err != nil { + return 0, err + } + + return count, nil +} diff --git a/appview/db/profile.go b/appview/db/profile.go index 7eb5ba83..bd215816 100644 --- a/appview/db/profile.go +++ b/appview/db/profile.go @@ -197,7 +197,7 @@ func UpsertProfile(tx *sql.Tx, profile *models.Profile) error { return tx.Commit() } -func GetProfiles(e Execer, filters ...filter) (map[string]*models.Profile, error) { +func GetProfiles(e Execer, filters ...Filter) (map[string]*models.Profile, error) { var conditions []string var args []any for _, filter := range filters { diff --git a/appview/db/pulls.go b/appview/db/pulls.go index cacb6c42..edcd395f 100644 --- a/appview/db/pulls.go +++ b/appview/db/pulls.go @@ -110,7 +110,7 @@ func NextPullId(e Execer, repoAt syntax.ATURI) (int, error) { return pullId - 1, err } -func GetPullsWithLimit(e Execer, limit int, filters ...filter) ([]*models.Pull, error) { +func GetPullsWithLimit(e Execer, limit int, filters ...Filter) ([]*models.Pull, error) { pulls := make(map[syntax.ATURI]*models.Pull) var conditions []string @@ -277,7 +277,7 @@ func GetPullsWithLimit(e Execer, limit int, filters ...filter) ([]*models.Pull, return orderedByPullId, nil } -func GetPulls(e Execer, filters ...filter) ([]*models.Pull, error) { +func GetPulls(e Execer, filters ...Filter) ([]*models.Pull, error) { return GetPullsWithLimit(e, 0, filters...) } @@ -294,7 +294,7 @@ func GetPull(e Execer, repoAt syntax.ATURI, pullId int) (*models.Pull, error) { } // mapping from pull -> pull submissions -func GetPullSubmissions(e Execer, filters ...filter) (map[syntax.ATURI][]*models.PullSubmission, error) { +func GetPullSubmissions(e Execer, filters ...Filter) (map[syntax.ATURI][]*models.PullSubmission, error) { var conditions []string var args []any for _, filter := range filters { @@ -391,7 +391,7 @@ func GetPullSubmissions(e Execer, filters ...filter) (map[syntax.ATURI][]*models return m, nil } -func GetPullComments(e Execer, filters ...filter) ([]models.PullComment, error) { +func GetPullComments(e Execer, filters ...Filter) ([]models.PullComment, error) { var conditions []string var args []any for _, filter := range filters { @@ -600,7 +600,7 @@ func ResubmitPull(e Execer, pull *models.Pull, newPatch, sourceRev string) error return err } -func SetPullParentChangeId(e Execer, parentChangeId string, filters ...filter) error { +func SetPullParentChangeId(e Execer, parentChangeId string, filters ...Filter) error { var conditions []string var args []any @@ -624,7 +624,7 @@ func SetPullParentChangeId(e Execer, parentChangeId string, filters ...filter) e // Only used when stacking to update contents in the event of a rebase (the interdiff should be empty). // otherwise submissions are immutable -func UpdatePull(e Execer, newPatch, sourceRev string, filters ...filter) error { +func UpdatePull(e Execer, newPatch, sourceRev string, filters ...Filter) error { var conditions []string var args []any diff --git a/appview/db/punchcard.go b/appview/db/punchcard.go index 0ab2925c..4517615a 100644 --- a/appview/db/punchcard.go +++ b/appview/db/punchcard.go @@ -20,7 +20,7 @@ func AddPunch(e Execer, punch models.Punch) error { return err } -func MakePunchcard(e Execer, filters ...filter) (*models.Punchcard, error) { +func MakePunchcard(e Execer, filters ...Filter) (*models.Punchcard, error) { punchcard := &models.Punchcard{} now := time.Now() startOfYear := time.Date(now.Year(), 1, 1, 0, 0, 0, 0, time.UTC) diff --git a/appview/db/registration.go b/appview/db/registration.go index 69c5bcf4..de1a4247 100644 --- a/appview/db/registration.go +++ b/appview/db/registration.go @@ -9,7 +9,7 @@ import ( "tangled.org/core/appview/models" ) -func GetRegistrations(e Execer, filters ...filter) ([]models.Registration, error) { +func GetRegistrations(e Execer, filters ...Filter) ([]models.Registration, error) { var registrations []models.Registration var conditions []string @@ -69,7 +69,7 @@ func GetRegistrations(e Execer, filters ...filter) ([]models.Registration, error return registrations, nil } -func MarkRegistered(e Execer, filters ...filter) error { +func MarkRegistered(e Execer, filters ...Filter) error { var conditions []string var args []any for _, filter := range filters { @@ -94,7 +94,7 @@ func AddKnot(e Execer, domain, did string) error { return err } -func DeleteKnot(e Execer, filters ...filter) error { +func DeleteKnot(e Execer, filters ...Filter) error { var conditions []string var args []any for _, filter := range filters { diff --git a/appview/db/repos.go b/appview/db/repos.go index 27a88b66..347281ae 100644 --- a/appview/db/repos.go +++ b/appview/db/repos.go @@ -41,7 +41,7 @@ func (r Repo) DidSlashRepo() string { return p } -func GetRepos(e Execer, limit int, filters ...filter) ([]models.Repo, error) { +func GetRepos(e Execer, limit int, filters ...Filter) ([]models.Repo, error) { repoMap := make(map[syntax.ATURI]*models.Repo) var conditions []string @@ -312,7 +312,7 @@ func GetRepos(e Execer, limit int, filters ...filter) ([]models.Repo, error) { } // helper to get exactly one repo -func GetRepo(e Execer, filters ...filter) (*models.Repo, error) { +func GetRepo(e Execer, filters ...Filter) (*models.Repo, error) { repos, err := GetRepos(e, 0, filters...) if err != nil { return nil, err @@ -329,7 +329,7 @@ func GetRepo(e Execer, filters ...filter) (*models.Repo, error) { return &repos[0], nil } -func CountRepos(e Execer, filters ...filter) (int64, error) { +func CountRepos(e Execer, filters ...Filter) (int64, error) { var conditions []string var args []any for _, filter := range filters { @@ -521,7 +521,7 @@ func SubscribeLabel(e Execer, rl *models.RepoLabel) error { return err } -func UnsubscribeLabel(e Execer, filters ...filter) error { +func UnsubscribeLabel(e Execer, filters ...Filter) error { var conditions []string var args []any for _, filter := range filters { @@ -539,7 +539,7 @@ func UnsubscribeLabel(e Execer, filters ...filter) error { return err } -func GetRepoLabels(e Execer, filters ...filter) ([]models.RepoLabel, error) { +func GetRepoLabels(e Execer, filters ...Filter) ([]models.RepoLabel, error) { var conditions []string var args []any for _, filter := range filters { diff --git a/appview/db/spindle.go b/appview/db/spindle.go index 98fbfcea..af4b3b65 100644 --- a/appview/db/spindle.go +++ b/appview/db/spindle.go @@ -9,7 +9,7 @@ import ( "tangled.org/core/appview/models" ) -func GetSpindles(e Execer, filters ...filter) ([]models.Spindle, error) { +func GetSpindles(e Execer, filters ...Filter) ([]models.Spindle, error) { var spindles []models.Spindle var conditions []string @@ -91,7 +91,7 @@ func AddSpindle(e Execer, spindle models.Spindle) error { return err } -func VerifySpindle(e Execer, filters ...filter) (int64, error) { +func VerifySpindle(e Execer, filters ...Filter) (int64, error) { var conditions []string var args []any for _, filter := range filters { @@ -114,7 +114,7 @@ func VerifySpindle(e Execer, filters ...filter) (int64, error) { return res.RowsAffected() } -func DeleteSpindle(e Execer, filters ...filter) error { +func DeleteSpindle(e Execer, filters ...Filter) error { var conditions []string var args []any for _, filter := range filters { @@ -144,7 +144,7 @@ func AddSpindleMember(e Execer, member models.SpindleMember) error { return err } -func RemoveSpindleMember(e Execer, filters ...filter) error { +func RemoveSpindleMember(e Execer, filters ...Filter) error { var conditions []string var args []any for _, filter := range filters { @@ -163,7 +163,7 @@ func RemoveSpindleMember(e Execer, filters ...filter) error { return err } -func GetSpindleMembers(e Execer, filters ...filter) ([]models.SpindleMember, error) { +func GetSpindleMembers(e Execer, filters ...Filter) ([]models.SpindleMember, error) { var members []models.SpindleMember var conditions []string diff --git a/appview/db/star.go b/appview/db/star.go index f7f7c59b..473ae43d 100644 --- a/appview/db/star.go +++ b/appview/db/star.go @@ -130,7 +130,7 @@ func GetStarStatus(e Execer, userDid string, repoAt syntax.ATURI) bool { func GetStarStatuses(e Execer, userDid string, repoAts []syntax.ATURI) (map[string]bool, error) { return getStarStatuses(e, userDid, repoAts) } -func GetStars(e Execer, limit int, filters ...filter) ([]models.Star, error) { +func GetStars(e Execer, limit int, filters ...Filter) ([]models.Star, error) { var conditions []string var args []any for _, filter := range filters { @@ -223,7 +223,7 @@ func GetStars(e Execer, limit int, filters ...filter) ([]models.Star, error) { return stars, nil } -func CountStars(e Execer, filters ...filter) (int64, error) { +func CountStars(e Execer, filters ...Filter) (int64, error) { var conditions []string var args []any for _, filter := range filters { diff --git a/appview/db/strings.go b/appview/db/strings.go index 7e87e111..b66abcda 100644 --- a/appview/db/strings.go +++ b/appview/db/strings.go @@ -44,7 +44,7 @@ func AddString(e Execer, s models.String) error { return err } -func GetStrings(e Execer, limit int, filters ...filter) ([]models.String, error) { +func GetStrings(e Execer, limit int, filters ...Filter) ([]models.String, error) { var all []models.String var conditions []string @@ -127,7 +127,7 @@ func GetStrings(e Execer, limit int, filters ...filter) ([]models.String, error) return all, nil } -func CountStrings(e Execer, filters ...filter) (int64, error) { +func CountStrings(e Execer, filters ...Filter) (int64, error) { var conditions []string var args []any for _, filter := range filters { @@ -151,7 +151,7 @@ func CountStrings(e Execer, filters ...filter) (int64, error) { return count, nil } -func DeleteString(e Execer, filters ...filter) error { +func DeleteString(e Execer, filters ...Filter) error { var conditions []string var args []any for _, filter := range filters { diff --git a/appview/db/timeline.go b/appview/db/timeline.go index 46439c77..d017b9df 100644 --- a/appview/db/timeline.go +++ b/appview/db/timeline.go @@ -84,7 +84,7 @@ func getRepoStarInfo(repo *models.Repo, starStatuses map[string]bool) (bool, int } func getTimelineRepos(e Execer, limit int, loggedInUserDid string, userIsFollowing []string) ([]models.TimelineEvent, error) { - filters := make([]filter, 0) + filters := make([]Filter, 0) if userIsFollowing != nil { filters = append(filters, FilterIn("did", userIsFollowing)) } @@ -144,7 +144,7 @@ func getTimelineRepos(e Execer, limit int, loggedInUserDid string, userIsFollowi } func getTimelineStars(e Execer, limit int, loggedInUserDid string, userIsFollowing []string) ([]models.TimelineEvent, error) { - filters := make([]filter, 0) + filters := make([]Filter, 0) if userIsFollowing != nil { filters = append(filters, FilterIn("starred_by_did", userIsFollowing)) } @@ -190,7 +190,7 @@ func getTimelineStars(e Execer, limit int, loggedInUserDid string, userIsFollowi } func getTimelineFollows(e Execer, limit int, loggedInUserDid string, userIsFollowing []string) ([]models.TimelineEvent, error) { - filters := make([]filter, 0) + filters := make([]Filter, 0) if userIsFollowing != nil { filters = append(filters, FilterIn("user_did", userIsFollowing)) } diff --git a/appview/pages/pages.go b/appview/pages/pages.go index 3148f5ee..46178af6 100644 --- a/appview/pages/pages.go +++ b/appview/pages/pages.go @@ -1344,6 +1344,7 @@ type PipelinesParams struct { LoggedInUser *oauth.User RepoInfo repoinfo.RepoInfo Pipelines []models.Pipeline + Pagination pagination.Pagination Active string } diff --git a/appview/pages/templates/repo/pipelines/pipelines.html b/appview/pages/templates/repo/pipelines/pipelines.html index fd115444..8555f2c8 100644 --- a/appview/pages/templates/repo/pipelines/pipelines.html +++ b/appview/pages/templates/repo/pipelines/pipelines.html @@ -7,7 +7,7 @@ {{ end }} {{ define "repoContent" }} -
+
{{ range .Pipelines }} {{ block "pipeline" (list $ .) }} {{ end }} @@ -17,6 +17,7 @@

{{ end }}
+ {{ block "pagination" . }} {{ end }}
{{ end }} @@ -100,3 +101,33 @@
{{ end }} {{ end }} + +{{ define "pagination" }} +
+ {{ if .Pagination.HasPreviousPage }} + {{ $prev := .Pagination.PreviousPage }} + + {{ i "chevron-left" "w-4 h-4" }} + previous + + {{ else }} +
+ {{ end }} + + {{ if .Pagination.HasNextPage }} + {{ $next := .Pagination.NextPage }} + + next + {{ i "chevron-right" "w-4 h-4" }} + + {{ end }} +
+{{ end }} diff --git a/appview/pipelines/pipelines.go b/appview/pipelines/pipelines.go index 619087c4..15928373 100644 --- a/appview/pipelines/pipelines.go +++ b/appview/pipelines/pipelines.go @@ -13,6 +13,7 @@ import ( "tangled.org/core/appview/db" "tangled.org/core/appview/oauth" "tangled.org/core/appview/pages" + "tangled.org/core/appview/pagination" "tangled.org/core/appview/reporesolver" "tangled.org/core/eventconsumer" "tangled.org/core/idresolver" @@ -72,21 +73,46 @@ func (p *Pipelines) Index(w http.ResponseWriter, r *http.Request) { } repoInfo := f.RepoInfo(user) - - ps, err := db.GetPipelineStatuses( - p.db, + filters := []db.Filter{ db.FilterEq("repo_owner", repoInfo.OwnerDid), db.FilterEq("repo_name", repoInfo.Name), db.FilterEq("knot", repoInfo.Knot), + } + + page, ok := r.Context().Value("page").(pagination.Page) + if !ok { + l.Error("failed to get page") + page = pagination.Page{No: 0, Count: 16} + } + pipelinesCount, err := db.GetPipelineCount(p.db, filters...) + if err != nil { + l.Error("failed to get pipeline count", "err", err) + p.pages.Notice(w, "pipelines", "Failed to load pipelines. Try again later.") + return + } + paginate := pagination.NewFromPage(page, pipelinesCount) + + currentPage := paginate.CurrentPage() + filters = append(filters, db.FilterBetween( + "row_num", + currentPage.Count*currentPage.No+1, + currentPage.Count*(currentPage.No+1), + )) + + ps, err := db.GetPipelineStatuses( + p.db, + filters..., ) if err != nil { l.Error("failed to query db", "err", err) + p.pages.Notice(w, "pipelines", "Failed to load pipelines. Try again later.") return } p.pages.Pipelines(w, pages.PipelinesParams{ LoggedInUser: user, RepoInfo: repoInfo, + Pagination: paginate, Pipelines: ps, }) } diff --git a/appview/pipelines/router.go b/appview/pipelines/router.go index f55a7921..867dc484 100644 --- a/appview/pipelines/router.go +++ b/appview/pipelines/router.go @@ -9,7 +9,7 @@ import ( func (p *Pipelines) Router(mw *middleware.Middleware) http.Handler { r := chi.NewRouter() - r.Get("/", p.Index) + r.With(middleware.Paginate(16)).Get("/", p.Index) r.Get("/{pipeline}/workflow/{workflow}", p.Workflow) r.Get("/{pipeline}/workflow/{workflow}/logs", p.Logs) -- 2.43.0