Skip to content

Commit c564411

Browse files
committed
Fix "projects" page pagination
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 c564411

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)