Skip to content

Commit 341f596

Browse files
Fix "projects" page pagination (#3793)
The projects page doesn't properly paginate the list of projects, limiting the total to 100 projects. This PR fixes that by adding pagination and associated tests.
1 parent 81d2c40 commit 341f596

3 files changed

Lines changed: 85 additions & 3 deletions

File tree

resources/js/vue/app.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,11 @@ const apolloClient = new ApolloClient({
6363
users: relayStylePagination(),
6464
},
6565
},
66+
User: {
67+
fields: {
68+
projects: relayStylePagination(),
69+
},
70+
},
6671
Project: {
6772
fields: {
6873
sites: relayStylePagination(),

resources/js/vue/components/ProjectsPage.vue

Lines changed: 27 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,7 @@ import {
126126
import {FontAwesomeIcon} from '@fortawesome/vue-fontawesome';
127127
128128
const PROJECT_LIST_QUERY = `
129-
projects {
129+
projects(after: $after) {
130130
edges {
131131
node {
132132
id
@@ -146,6 +146,10 @@ const PROJECT_LIST_QUERY = `
146146
}
147147
}
148148
}
149+
pageInfo {
150+
hasNextPage
151+
endCursor
152+
}
149153
}
150154
`;
151155
@@ -174,20 +178,30 @@ export default {
174178
apollo: {
175179
allVisibleProjects: {
176180
query: gql`
177-
query allVisibleProjects($countBuildsSince: DateTimeTz!) {
181+
query allVisibleProjects($countBuildsSince: DateTimeTz!, $after: String) {
178182
allVisibleProjects: ${PROJECT_LIST_QUERY}
179183
}
180184
`,
181185
variables() {
182186
return {
183187
countBuildsSince: this.oneDayAgo,
188+
after: null,
184189
};
185190
},
191+
result({data}) {
192+
if (data && data.allVisibleProjects.pageInfo.hasNextPage) {
193+
this.$apollo.queries.allVisibleProjects.fetchMore({
194+
variables: {
195+
after: data.allVisibleProjects.pageInfo.endCursor,
196+
},
197+
});
198+
}
199+
},
186200
},
187201
188202
myProjects: {
189203
query: gql`
190-
query myProjects($countBuildsSince: DateTimeTz!) {
204+
query myProjects($countBuildsSince: DateTimeTz!, $after: String) {
191205
me {
192206
id
193207
${PROJECT_LIST_QUERY}
@@ -198,8 +212,18 @@ export default {
198212
variables() {
199213
return {
200214
countBuildsSince: this.oneDayAgo,
215+
after: null,
201216
};
202217
},
218+
result({data}) {
219+
if (data && data.me?.projects.pageInfo.hasNextPage) {
220+
this.$apollo.queries.myProjects.fetchMore({
221+
variables: {
222+
after: data.me.projects.pageInfo.endCursor,
223+
},
224+
});
225+
}
226+
},
203227
},
204228
},
205229

tests/Browser/Pages/ProjectsPageTest.php

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -287,4 +287,57 @@ public function testShowsDateOfLastSubmission(): void
287287
});
288288
});
289289
}
290+
291+
public function testPaginationLoadsAllProjects(): void
292+
{
293+
$this->users['admin'] = $this->makeAdminUser();
294+
295+
// Create 110 public projects, each with a recent build so they appear on the active tab
296+
for ($i = 1; $i <= 110; $i++) {
297+
$project = $this->makePublicProject();
298+
$this->projects["project{$i}"] = $project;
299+
300+
$project->builds()->create([
301+
'siteid' => $this->site->id,
302+
'name' => Str::uuid()->toString(),
303+
'uuid' => Str::uuid()->toString(),
304+
'submittime' => Carbon::now(),
305+
]);
306+
307+
$project->users()->attach($this->users['admin'], ['role' => Project::PROJECT_USER]);
308+
}
309+
310+
// The first project created has the lowest ID (first pagination page) and the last has
311+
// the highest ID (final pagination page). Waiting for the last project's name guarantees
312+
// all pages have been fetched before asserting.
313+
$firstProjectName = $this->projects['project1']->name;
314+
$lastProjectName = $this->projects['project110']->name;
315+
316+
$this->browse(function (Browser $browser) use ($firstProjectName, $lastProjectName): void {
317+
$browser->loginAs($this->users['admin'])
318+
->visit('/projects')
319+
->whenAvailable('@projects-page', function (Browser $browser) use ($firstProjectName, $lastProjectName): void {
320+
// Test "All" tab shows projects with lowest and highest IDs
321+
$browser->click('@all-tab')
322+
->waitFor('@projects-table')
323+
->waitForText($lastProjectName)
324+
->assertSeeIn('@projects-table', $firstProjectName)
325+
->assertSeeIn('@projects-table', $lastProjectName);
326+
327+
// Test "Active" tab shows projects with lowest and highest IDs
328+
$browser->click('@active-tab')
329+
->waitFor('@projects-table')
330+
->waitForText($lastProjectName)
331+
->assertSeeIn('@projects-table', $firstProjectName)
332+
->assertSeeIn('@projects-table', $lastProjectName);
333+
334+
// Test "Member" tab shows projects with lowest and highest IDs
335+
$browser->click('@member-tab')
336+
->waitFor('@projects-table')
337+
->waitForText($lastProjectName)
338+
->assertSeeIn('@projects-table', $firstProjectName)
339+
->assertSeeIn('@projects-table', $lastProjectName);
340+
});
341+
});
342+
}
290343
}

0 commit comments

Comments
 (0)