@@ -81,6 +81,11 @@
}
-
-
+
+
+
+ @if (savedViews()?.length > pageSize) {
+
+ }
+
diff --git a/src-ui/src/app/components/manage/saved-views/saved-views.component.spec.ts b/src-ui/src/app/components/manage/saved-views/saved-views.component.spec.ts
index 735e5abf4..fbcdbe8c3 100644
--- a/src-ui/src/app/components/manage/saved-views/saved-views.component.spec.ts
+++ b/src-ui/src/app/components/manage/saved-views/saved-views.component.spec.ts
@@ -4,6 +4,7 @@ import { provideHttpClientTesting } from '@angular/common/http/testing'
import { signal } from '@angular/core'
import { ComponentFixture, TestBed } from '@angular/core/testing'
import { FormsModule, ReactiveFormsModule } from '@angular/forms'
+import { By } from '@angular/platform-browser'
import { NgbModal, NgbModule } from '@ng-bootstrap/ng-bootstrap'
import { NgxBootstrapIconsModule, allIcons } from 'ngx-bootstrap-icons'
import { Subject, of, throwError } from 'rxjs'
@@ -222,6 +223,44 @@ describe('SavedViewsComponent', () => {
).toEqual(view.show_on_dashboard)
})
+ it('should page saved views, clamp the page if views are removed', () => {
+ const manyViews = Array.from({ length: 30 }, (_, i) => ({
+ id: i + 1,
+ name: `view${i + 1}`,
+ })) as SavedView[]
+ const listSpy = jest.spyOn(savedViewService, 'list').mockReturnValue(
+ of({
+ all: manyViews.map((v) => v.id),
+ count: manyViews.length,
+ results: manyViews.concat([]),
+ })
+ )
+ component.ngOnInit()
+ fixture.detectChanges()
+ expect(listSpy).toHaveBeenCalledWith(1, 100000, null, false, {
+ full_perms: true,
+ })
+ expect(component.pagedSavedViews()).toHaveLength(25)
+ expect(fixture.debugElement.query(By.css('ngb-pagination'))).not.toBeNull()
+ // all views have controls, not just the current page
+ expect(
+ Object.keys(component.savedViewsForm.get('savedViews').value)
+ ).toHaveLength(30)
+
+ component.page.set(2)
+ expect(component.pagedSavedViews()).toHaveLength(5)
+
+ listSpy.mockReturnValue(
+ of({
+ all: manyViews.slice(0, 25).map((v) => v.id),
+ count: 25,
+ results: manyViews.slice(0, 25),
+ })
+ )
+ component.ngOnInit()
+ expect(component.page()).toEqual(1)
+ })
+
it('should support editing permissions', () => {
const confirmClicked = new Subject
()
const modalRef = {
diff --git a/src-ui/src/app/components/manage/saved-views/saved-views.component.ts b/src-ui/src/app/components/manage/saved-views/saved-views.component.ts
index 21942b9c1..3813e666f 100644
--- a/src-ui/src/app/components/manage/saved-views/saved-views.component.ts
+++ b/src-ui/src/app/components/manage/saved-views/saved-views.component.ts
@@ -1,12 +1,19 @@
import { AsyncPipe } from '@angular/common'
-import { Component, OnDestroy, OnInit, inject, signal } from '@angular/core'
+import {
+ Component,
+ OnDestroy,
+ OnInit,
+ computed,
+ inject,
+ signal,
+} from '@angular/core'
import {
FormControl,
FormGroup,
FormsModule,
ReactiveFormsModule,
} from '@angular/forms'
-import { NgbModal } from '@ng-bootstrap/ng-bootstrap'
+import { NgbModal, NgbPaginationModule } from '@ng-bootstrap/ng-bootstrap'
import { dirtyCheck } from '@ngneat/dirty-check-forms'
import { NgxBootstrapIconsModule } from 'ngx-bootstrap-icons'
import { BehaviorSubject, Observable, of, switchMap, takeUntil } from 'rxjs'
@@ -42,6 +49,7 @@ import { LoadingComponentWithPermissions } from '../../loading-component/loading
FormsModule,
ReactiveFormsModule,
AsyncPipe,
+ NgbPaginationModule,
NgxBootstrapIconsModule,
],
})
@@ -58,6 +66,14 @@ export class SavedViewsComponent
DisplayMode = DisplayMode
readonly savedViews = signal(undefined)
+ readonly page = signal(1)
+ public readonly pageSize = 25
+ // All views are loaded at init, so paging is only for display
+ readonly pagedSavedViews = computed(() => {
+ const start = (this.page() - 1) * this.pageSize
+ return this.savedViews()?.slice(start, start + this.pageSize)
+ })
+
private savedViewsGroup = new FormGroup({})
public savedViewsForm: FormGroup = new FormGroup({
savedViews: this.savedViewsGroup,
@@ -84,9 +100,11 @@ export class SavedViewsComponent
private reloadViews(): void {
this.loading.set(true)
this.savedViewService
- .list(null, null, null, false, { full_perms: true })
+ .list(1, 100000, null, false, { full_perms: true })
.subscribe((r) => {
this.savedViews.set(r.results)
+ const pageCount = Math.ceil(r.results.length / this.pageSize)
+ this.page.update((page) => Math.min(page, Math.max(1, pageCount)))
this.initialize()
})
}