GoogleCloudPlatform / GoogleCloudPlatform/gcc-creative-studio
Admin table pagination: previous-page button is permanently disabled, stranding the user on page 2
- Dominant language
- Python
- Stars
- 144
- Forks
- 385
- Avg merge
- 1d 46m
- Merged PRs (30d)
- 5
Description
## Expected Behavior
On `/admin/media-gallery`, after advancing to page 2 of the results, the paginator should show the range for page 2 (`26 – 50 of 723`) and its previous-page arrow should be enabled so the user can go back.
## Actual Behavior
After advancing to page 2, the paginator resets to page 1: the range label reads `1 – 25 of 723` and the previous-page arrow stays greyed out, so there is no way back. The rows displayed are page 2's data, so the label and the table disagree. Clicking next again re-requests the same offset, so the user cannot move forward either. Effectively the table is limited to its first two pages, and only in one direction.
Browser-independent (reproduced in Chrome and Firefox); this is the in-page `mat-paginator` control, not browser history.
Affects two components:
- `frontend/src/app/admin/media-gallery-management/media-gallery-management.component.html` (route `/admin/media-gallery`)
- `frontend/src/app/admin/tags-management/tags-management.component.html`
### Cause
In both components the `` and the `` share one wrapper gated on the loading flag, e.g. `media-gallery-management.component.html:108`:
```html
```
`fetchPage()` sets `isLoading = true` before awaiting the request (`media-gallery-management.component.ts:135`), so every page change destroys the paginator and constructs a new one when the response lands. Neither template binds `[pageIndex]`, so the replacement always initialises to page 0, and `MatPaginator` disables its own previous-page button whenever `pageIndex === 0`:
```ts
_previousButtonsDisabled() { return this.disabled || !this.hasPreviousPage(); }
```
Both components already track the right value in `currentPageIndex` and assign it on success; it is simply never bound to the view.
`users-management` and `source-assets-management` have the identical loading wrapper and are unaffected, because both already bind `[pageIndex]="currentPageIndex"`. Those two are the pattern the fix follows.
`tags-management` additionally resets `currentPageIndex` to 0 on a page-size change and then calls `loadTags(event.pageIndex)`. Material recomputes that index to keep the first visible row on screen, so it is not 0, and `loadTags` reassigns `currentPageIndex` from it, undoing the reset.
## Steps to Reproduce the Problem
1. Sign in as an admin and go to `/admin/media-gallery`, with enough media in the workspace to fill more than two pages.
2. Click the paginator's next-page arrow.
3. Observe that the rows update to page 2, but the range label still reads `1 – 25 of ...` and the previous-page arrow is disabled. Clicking next again reloads the same page.
Same steps reproduce on `/admin/tags` (needs more than one page of tags).
## Specifications
- Version: `upstream/main` at `1f19478` ("Merge pull request #273 from GoogleCloudPlatform/cherry-pick-temp")
- Platform: Angular 18.2.1, Angular Material 18.2.1, Chrome 152 and Firefox; reproduced headless in Karma against an unmodified checkout of `main`
I have a fix plus regression specs for both components, and will open a PR referencing this issue. For what it's worth, the specs fail on unmodified `main` (5 failures across the two components) and pass with the one-line bindings added, so the behaviour is pinned in both directions.
While confirming the scope I noticed something adjacent that I have deliberately left out of the fix, in case it is useful: `media-templates-management.component.ts` assigns `this.dataSource.paginator = this.paginator` in `ngAfterViewInit`, but `isLoading` is initialised to `true`, so the paginator is not in the DOM at that point, `this.paginator` is `undefined`, and it is never reassigned once the table appears. If that is right, that table's client-side paging and sorting are inert rather than merely wrong on page 2. I have not confirmed it against a running app.
Contributor guide
Research direction
Start with the loading wrappers in frontend/src/app/admin/media-gallery-management/media-gallery-management.component.html and frontend/src/app/admin/tags-management/tags-management.component.html, then compare their paginator usage with users-management and source-assets-management. Check the existing regression specs for both components and verify that page 2 displays 26–50, enables the previous arrow, and allows subsequent navigation in both directions.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- angular, typescript
- Domain
- frontend
- Issue type
- Bug
- Difficulty
- 2/5
- Estimated time
- 1-3 hours
- Activity status
- Active
- Clarity
- Clearly specified
- Newbie friendliness
- 35/100