Skip to content

Commit c93cd3d

Browse files
brechtvltechknowlogick
authored andcommitted
Add pagination for dashboard and user activity feeds
Previously only the last few activities where available. This works for all activity and for activity on a date chosen on the heatmap.
1 parent 740a5ec commit c93cd3d

File tree

9 files changed

+64
-25
lines changed

9 files changed

+64
-25
lines changed

models/activities/action.go

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -380,14 +380,14 @@ type GetFeedsOptions struct {
380380
}
381381

382382
// GetFeeds returns actions according to the provided options
383-
func GetFeeds(ctx context.Context, opts GetFeedsOptions) (ActionList, error) {
383+
func GetFeeds(ctx context.Context, opts GetFeedsOptions) (ActionList, int64, error) {
384384
if opts.RequestedUser == nil && opts.RequestedTeam == nil && opts.RequestedRepo == nil {
385-
return nil, fmt.Errorf("need at least one of these filters: RequestedUser, RequestedTeam, RequestedRepo")
385+
return nil, 0, fmt.Errorf("need at least one of these filters: RequestedUser, RequestedTeam, RequestedRepo")
386386
}
387387

388388
cond, err := activityQueryCondition(opts)
389389
if err != nil {
390-
return nil, err
390+
return nil, 0, err
391391
}
392392

393393
sess := db.GetEngine(ctx).Where(cond).
@@ -398,16 +398,16 @@ func GetFeeds(ctx context.Context, opts GetFeedsOptions) (ActionList, error) {
398398
sess = db.SetSessionPagination(sess, &opts)
399399

400400
actions := make([]*Action, 0, opts.PageSize)
401-
402-
if err := sess.Desc("`action`.created_unix").Find(&actions); err != nil {
403-
return nil, fmt.Errorf("Find: %w", err)
401+
count, err := sess.Desc("`action`.created_unix").FindAndCount(&actions)
402+
if err != nil {
403+
return nil, 0, fmt.Errorf("FindAndCount: %w", err)
404404
}
405405

406406
if err := ActionList(actions).loadAttributes(ctx); err != nil {
407-
return nil, fmt.Errorf("LoadAttributes: %w", err)
407+
return nil, 0, fmt.Errorf("LoadAttributes: %w", err)
408408
}
409409

410-
return actions, nil
410+
return actions, count, nil
411411
}
412412

413413
// ActivityReadable return whether doer can read activities of user

models/activities/action_test.go

Lines changed: 18 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ func TestGetFeeds(t *testing.T) {
4444
assert.NoError(t, unittest.PrepareTestDatabase())
4545
user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2})
4646

47-
actions, err := activities_model.GetFeeds(db.DefaultContext, activities_model.GetFeedsOptions{
47+
actions, count, err := activities_model.GetFeeds(db.DefaultContext, activities_model.GetFeedsOptions{
4848
RequestedUser: user,
4949
Actor: user,
5050
IncludePrivate: true,
@@ -56,15 +56,17 @@ func TestGetFeeds(t *testing.T) {
5656
assert.EqualValues(t, 1, actions[0].ID)
5757
assert.EqualValues(t, user.ID, actions[0].UserID)
5858
}
59+
assert.Equal(t, int64(1), count)
5960

60-
actions, err = activities_model.GetFeeds(db.DefaultContext, activities_model.GetFeedsOptions{
61+
actions, count, err = activities_model.GetFeeds(db.DefaultContext, activities_model.GetFeedsOptions{
6162
RequestedUser: user,
6263
Actor: user,
6364
IncludePrivate: false,
6465
OnlyPerformedBy: false,
6566
})
6667
assert.NoError(t, err)
6768
assert.Len(t, actions, 0)
69+
assert.Equal(t, int64(0), count)
6870
}
6971

7072
func TestGetFeedsForRepos(t *testing.T) {
@@ -74,38 +76,42 @@ func TestGetFeedsForRepos(t *testing.T) {
7476
pubRepo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 8})
7577

7678
// private repo & no login
77-
actions, err := activities_model.GetFeeds(db.DefaultContext, activities_model.GetFeedsOptions{
79+
actions, count, err := activities_model.GetFeeds(db.DefaultContext, activities_model.GetFeedsOptions{
7880
RequestedRepo: privRepo,
7981
IncludePrivate: true,
8082
})
8183
assert.NoError(t, err)
8284
assert.Len(t, actions, 0)
85+
assert.Equal(t, int64(0), count)
8386

8487
// public repo & no login
85-
actions, err = activities_model.GetFeeds(db.DefaultContext, activities_model.GetFeedsOptions{
88+
actions, count, err = activities_model.GetFeeds(db.DefaultContext, activities_model.GetFeedsOptions{
8689
RequestedRepo: pubRepo,
8790
IncludePrivate: true,
8891
})
8992
assert.NoError(t, err)
9093
assert.Len(t, actions, 1)
94+
assert.Equal(t, int64(1), count)
9195

9296
// private repo and login
93-
actions, err = activities_model.GetFeeds(db.DefaultContext, activities_model.GetFeedsOptions{
97+
actions, count, err = activities_model.GetFeeds(db.DefaultContext, activities_model.GetFeedsOptions{
9498
RequestedRepo: privRepo,
9599
IncludePrivate: true,
96100
Actor: user,
97101
})
98102
assert.NoError(t, err)
99103
assert.Len(t, actions, 1)
104+
assert.Equal(t, int64(1), count)
100105

101106
// public repo & login
102-
actions, err = activities_model.GetFeeds(db.DefaultContext, activities_model.GetFeedsOptions{
107+
actions, count, err = activities_model.GetFeeds(db.DefaultContext, activities_model.GetFeedsOptions{
103108
RequestedRepo: pubRepo,
104109
IncludePrivate: true,
105110
Actor: user,
106111
})
107112
assert.NoError(t, err)
108113
assert.Len(t, actions, 1)
114+
assert.Equal(t, int64(1), count)
109115
}
110116

111117
func TestGetFeeds2(t *testing.T) {
@@ -114,7 +120,7 @@ func TestGetFeeds2(t *testing.T) {
114120
org := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 3})
115121
user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2})
116122

117-
actions, err := activities_model.GetFeeds(db.DefaultContext, activities_model.GetFeedsOptions{
123+
actions, count, err := activities_model.GetFeeds(db.DefaultContext, activities_model.GetFeedsOptions{
118124
RequestedUser: org,
119125
Actor: user,
120126
IncludePrivate: true,
@@ -127,8 +133,9 @@ func TestGetFeeds2(t *testing.T) {
127133
assert.EqualValues(t, 2, actions[0].ID)
128134
assert.EqualValues(t, org.ID, actions[0].UserID)
129135
}
136+
assert.Equal(t, int64(1), count)
130137

131-
actions, err = activities_model.GetFeeds(db.DefaultContext, activities_model.GetFeedsOptions{
138+
actions, count, err = activities_model.GetFeeds(db.DefaultContext, activities_model.GetFeedsOptions{
132139
RequestedUser: org,
133140
Actor: user,
134141
IncludePrivate: false,
@@ -137,6 +144,7 @@ func TestGetFeeds2(t *testing.T) {
137144
})
138145
assert.NoError(t, err)
139146
assert.Len(t, actions, 0)
147+
assert.Equal(t, int64(0), count)
140148
}
141149

142150
func TestActivityReadable(t *testing.T) {
@@ -224,13 +232,14 @@ func TestGetFeedsCorrupted(t *testing.T) {
224232
RepoID: 1700,
225233
})
226234

227-
actions, err := activities_model.GetFeeds(db.DefaultContext, activities_model.GetFeedsOptions{
235+
actions, count, err := activities_model.GetFeeds(db.DefaultContext, activities_model.GetFeedsOptions{
228236
RequestedUser: user,
229237
Actor: user,
230238
IncludePrivate: true,
231239
})
232240
assert.NoError(t, err)
233241
assert.Len(t, actions, 0)
242+
assert.Equal(t, int64(0), count)
234243
}
235244

236245
func TestConsistencyUpdateAction(t *testing.T) {

models/activities/user_heatmap_test.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ func TestGetUserHeatmapDataByUser(t *testing.T) {
7373
}
7474

7575
// get the action for comparison
76-
actions, err := activities_model.GetFeeds(db.DefaultContext, activities_model.GetFeedsOptions{
76+
actions, count, err := activities_model.GetFeeds(db.DefaultContext, activities_model.GetFeedsOptions{
7777
RequestedUser: user,
7878
Actor: doer,
7979
IncludePrivate: true,
@@ -90,6 +90,7 @@ func TestGetUserHeatmapDataByUser(t *testing.T) {
9090
}
9191
assert.NoError(t, err)
9292
assert.Len(t, actions, contributions, "invalid action count: did the test data became too old?")
93+
assert.Equal(t, count, int64(contributions))
9394
assert.Equal(t, tc.CountResult, contributions, fmt.Sprintf("testcase '%s'", tc.desc))
9495

9596
// Test JSON rendering

routers/web/feed/profile.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ func ShowUserFeedAtom(ctx *context.Context) {
2626
func showUserFeed(ctx *context.Context, formatType string) {
2727
includePrivate := ctx.IsSigned && (ctx.Doer.IsAdmin || ctx.Doer.ID == ctx.ContextUser.ID)
2828

29-
actions, err := activities_model.GetFeeds(ctx, activities_model.GetFeedsOptions{
29+
actions, _, err := activities_model.GetFeeds(ctx, activities_model.GetFeedsOptions{
3030
RequestedUser: ctx.ContextUser,
3131
Actor: ctx.Doer,
3232
IncludePrivate: includePrivate,

routers/web/feed/repo.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ import (
1515

1616
// ShowRepoFeed shows user activity on the repo as RSS / Atom feed
1717
func ShowRepoFeed(ctx *context.Context, repo *repo_model.Repository, formatType string) {
18-
actions, err := activities_model.GetFeeds(ctx, activities_model.GetFeedsOptions{
18+
actions, _, err := activities_model.GetFeeds(ctx, activities_model.GetFeedsOptions{
1919
RequestedRepo: repo,
2020
Actor: ctx.Doer,
2121
IncludePrivate: true,

routers/web/user/home.go

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -72,12 +72,23 @@ func Dashboard(ctx *context.Context) {
7272
return
7373
}
7474

75+
var (
76+
date = ctx.FormString("date")
77+
page = ctx.FormInt("page")
78+
)
79+
80+
// Make sure page number is at least 1. Will be posted to ctx.Data.
81+
if page <= 1 {
82+
page = 1
83+
}
84+
7585
ctx.Data["Title"] = ctxUser.DisplayName() + " - " + ctx.Tr("dashboard")
7686
ctx.Data["PageIsDashboard"] = true
7787
ctx.Data["PageIsNews"] = true
7888
cnt, _ := organization.GetOrganizationCount(ctx, ctxUser)
7989
ctx.Data["UserOrgsCount"] = cnt
8090
ctx.Data["MirrorsEnabled"] = setting.Mirror.Enabled
91+
ctx.Data["Date"] = date
8192

8293
var uid int64
8394
if ctxUser != nil {
@@ -98,22 +109,30 @@ func Dashboard(ctx *context.Context) {
98109
ctx.Data["HeatmapData"] = data
99110
}
100111

101-
var err error
102-
ctx.Data["Feeds"], err = activities_model.GetFeeds(ctx, activities_model.GetFeedsOptions{
112+
feeds, count, err := activities_model.GetFeeds(ctx, activities_model.GetFeedsOptions{
103113
RequestedUser: ctxUser,
104114
RequestedTeam: ctx.Org.Team,
105115
Actor: ctx.Doer,
106116
IncludePrivate: true,
107117
OnlyPerformedBy: false,
108118
IncludeDeleted: false,
109119
Date: ctx.FormString("date"),
110-
ListOptions: db.ListOptions{PageSize: setting.UI.FeedPagingNum},
120+
ListOptions: db.ListOptions{
121+
Page: page,
122+
PageSize: setting.UI.FeedPagingNum,
123+
},
111124
})
112125
if err != nil {
113126
ctx.ServerError("GetFeeds", err)
114127
return
115128
}
116129

130+
ctx.Data["Feeds"] = feeds
131+
132+
pager := context.NewPagination(int(count), setting.UI.FeedPagingNum, page, 5)
133+
pager.AddParam(ctx, "date", "Date")
134+
ctx.Data["Page"] = pager
135+
117136
ctx.HTML(http.StatusOK, tplDashboard)
118137
}
119138

routers/web/user/profile.go

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -187,19 +187,25 @@ func Profile(ctx *context.Context) {
187187

188188
total = int(count)
189189
case "activity":
190-
ctx.Data["Feeds"], err = activities_model.GetFeeds(ctx, activities_model.GetFeedsOptions{
190+
items, count, err := activities_model.GetFeeds(ctx, activities_model.GetFeedsOptions{
191191
RequestedUser: ctx.ContextUser,
192192
Actor: ctx.Doer,
193193
IncludePrivate: showPrivate,
194194
OnlyPerformedBy: true,
195195
IncludeDeleted: false,
196196
Date: ctx.FormString("date"),
197-
ListOptions: db.ListOptions{PageSize: setting.UI.FeedPagingNum},
197+
ListOptions: db.ListOptions{
198+
PageSize: setting.UI.FeedPagingNum,
199+
Page: page,
200+
},
198201
})
199202
if err != nil {
200203
ctx.ServerError("GetFeeds", err)
201204
return
202205
}
206+
ctx.Data["Feeds"] = items
207+
208+
total = int(count)
203209
case "stars":
204210
ctx.Data["PageIsProfileStarList"] = true
205211
repos, count, err = repo_model.SearchRepository(ctx, &repo_model.SearchRepoOptions{

templates/user/dashboard/feeds.tmpl

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,3 +124,5 @@
124124
<div class="ui divider"></div>
125125
</div>
126126
{{end}}
127+
128+
{{template "base/paginate" .}}

web_src/js/components/ActivityHeatmap.vue

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,8 @@ export default {
7070
params.set('date', clickedDate);
7171
}
7272
73+
params.delete('page');
74+
7375
const newSearch = params.toString();
7476
window.location.search = newSearch.length ? `?${newSearch}` : '';
7577
}

0 commit comments

Comments
 (0)