Skip to content

Commit 450c900

Browse files
Garfield-frPascalRepond
authored andcommitted
feat(paginator): add configuration
* Adds the paginator configuration. * Adds tests on paginator feature. Co-Authored-by: Bertrand Zuchuat <[email protected]>
1 parent 3879aa2 commit 450c900

File tree

15 files changed

+209
-108
lines changed

15 files changed

+209
-108
lines changed

projects/admin/src/app/record/detail-view/document-detail-view/holdings/holding-content/holding-content.component.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,5 +80,5 @@
8080
}
8181
}
8282
@if (store.isPaginatorEnabled()) {
83-
<shared-paginator [paginatorState]="paginatorConfig()" (pageChange)="store.setPaginator($event)" />
83+
<shared-paginator [pager]="store.pager()" [total]="store.total()" (pageChange)="store.setPaginator($event)" />
8484
}

projects/admin/src/app/record/detail-view/document-detail-view/holdings/holding-content/holding-content.component.ts

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,8 @@
1414
* You should have received a copy of the GNU Affero General Public License
1515
* along with this program. If not, see <http://www.gnu.org/licenses/>.
1616
*/
17-
import { Component, effect, inject, input, model, Signal } from '@angular/core';
18-
import { deepComputed } from '@ngrx/signals';
19-
import { EsRecord, PaginatorConfig } from '@rero/shared';
17+
import { Component, effect, inject, input, model } from '@angular/core';
18+
import { EsRecord } from '@rero/shared';
2019
import { ItemsStore } from '../store/items-store';
2120

2221
@Component({
@@ -34,12 +33,6 @@ export class HoldingContentComponent {
3433

3534
protected filter = model<string>('');
3635

37-
protected paginatorConfig: Signal<PaginatorConfig> = deepComputed(() => ({
38-
first: this.store.paginator.first(),
39-
rows: this.store.paginator.rows(),
40-
total: this.store.total()
41-
}));
42-
4336
constructor() {
4437
this.store.setFilter(this.filter);
4538
effect(() => this.store.setHoldings(this.holding()));

projects/admin/src/app/record/detail-view/document-detail-view/holdings/store/items-store.ts

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ import { toObservable } from "@angular/core/rxjs-interop";
1919
import { patchState, signalMethod, signalStore, withComputed, withHooks, withMethods, withProps, withState } from "@ngrx/signals";
2020
import { rxMethod } from "@ngrx/signals/rxjs-interop";
2121
import { RecordUiService } from "@rero/ng-core";
22-
import { EsRecord, EsResult, nonNullable, paginatorInitialState, setFulfilled, setPending, withPaginator, withRequestStatus } from "@rero/shared";
22+
import { EsRecord, EsResult, nonNullable, Pager, setFulfilled, setPending, withPaginator, withRequestStatus } from "@rero/shared";
2323
import { PaginatorState } from "primeng/paginator";
2424
import { debounceTime, pipe, switchMap, tap } from "rxjs";
2525
import { ItemApiService } from "../../../../../api/item-api.service";
@@ -42,9 +42,16 @@ const itemsInitialState: ItemsState = {
4242
filterTotal: 0
4343
}
4444

45+
const initialPagerConfig: Pager = {
46+
page: 1,
47+
first: 1,
48+
rows: 10,
49+
rowsPerPageOptions: [10, 20, 50]
50+
}
51+
4552
export const ItemsStore = signalStore(
4653
withState<ItemsState>(itemsInitialState),
47-
withPaginator(),
54+
withPaginator(initialPagerConfig),
4855
withRequestStatus(),
4956
withProps(() => ({
5057
recordUiService: inject(RecordUiService),
@@ -53,14 +60,14 @@ export const ItemsStore = signalStore(
5360
withComputed((store) => ({
5461
holdingType: computed(() => store.holdings().metadata.holdings_type),
5562
isFilterEnabled: computed(() => store.total() >= 11 || '' !== store.filter()),
56-
isPaginatorEnabled: computed(() => store.paginator.rows() < store.filterTotal()),
63+
isPaginatorEnabled: computed(() => store.pager.rows() < store.filterTotal()),
5764
})),
5865
withMethods((store) => ({
5966
setHoldings(holdings: EsRecord) {
6067
patchState(store, { holdings });
6168
},
6269
setFilter: signalMethod<string>((filter?: string) => {
63-
patchState(store, { filter, paginator: paginatorInitialState.paginator });
70+
patchState(store, { filter, pager: initialPagerConfig });
6471
}),
6572
setPaginator(paginator: PaginatorState) {
6673
store.changePage(paginator);
@@ -71,8 +78,8 @@ export const ItemsStore = signalStore(
7178
tap(() => patchState(store, setPending())),
7279
switchMap(() => store.itemsApiService.getItemsByHoldings(
7380
store.holdings(),
74-
store.paginator.page(),
75-
store.paginator.rows(),
81+
store.pager.page(),
82+
store.pager.rows(),
7683
store.filter()
7784
)),
7885
tap((result: EsResult) => {
@@ -111,7 +118,7 @@ export const ItemsStore = signalStore(
111118
onInit: () => {
112119
toObservable(store.holdings).subscribe(() => store.load());
113120
toObservable(store.filter).pipe(nonNullable()).subscribe(() => store.load());
114-
toObservable(store.paginator).pipe(nonNullable()).subscribe(() => store.load());
121+
toObservable(store.pager).pipe(nonNullable()).subscribe(() => store.load());
115122
}
116123
}))
117124
);

projects/admin/src/app/record/detail-view/holding-detail-view/holdings-serial-store.ts

Lines changed: 16 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ import { patchState, signalMethod, signalStore, withComputed, withHooks, withMet
2323
import { rxMethod } from "@ngrx/signals/rxjs-interop";
2424
import { TranslateService } from "@ngx-translate/core";
2525
import { CONFIG, RecordUiService } from "@rero/ng-core";
26-
import { EsRecord, EsResult, nonNullable, paginatorInitialState, PERMISSIONS, PermissionsService, UserService, withPaginator } from "@rero/shared";
26+
import { EsRecord, EsResult, nonNullable, Pager, PERMISSIONS, PermissionsService, UserService, withPaginator } from "@rero/shared";
2727
import { MessageService } from "primeng/api";
2828
import { PaginatorState } from "primeng/paginator";
2929
import { numberGreatThan } from "projects/shared/src/public-api";
@@ -62,9 +62,16 @@ export const localFieldsPermissions = [
6262
PERMISSIONS.LOFI_CREATE
6363
];
6464

65+
const initialPagerConfig: Pager = {
66+
page: 1,
67+
first: 1,
68+
rows: 10,
69+
rowsPerPageOptions: [10, 20, 50]
70+
}
71+
6572
export const HoldingsSerialStore = signalStore(
6673
withState(initialState),
67-
withPaginator(),
74+
withPaginator(initialPagerConfig),
6875
withProps(() => ({
6976
holdingsService: inject(HoldingsService),
7077
holdingsApiService: inject(HoldingsApiService),
@@ -76,7 +83,7 @@ export const HoldingsSerialStore = signalStore(
7683
})),
7784
withComputed((store) => ({
7885
isFilterEnabled: computed(() => store.receivedItemsCount() >= 11 || '' !== store.filter()),
79-
isPaginatorEnabled: computed(() => store.paginator.rows() < store.filterTotal()),
86+
isPaginatorEnabled: computed(() => store.pager.rows() < store.filterTotal()),
8087
isAllowIssueCreation: computed(() => store.userService.user.currentLibrary === store.holdings().metadata.library.pid),
8188
isDisplayLocalFieldsTab: computed(() =>
8289
store.permissionsService.canAccess(localFieldsPermissions)
@@ -88,7 +95,7 @@ export const HoldingsSerialStore = signalStore(
8895
patchState(store, { holdings });
8996
}),
9097
setFilter: signalMethod<string>((filter: string) => {
91-
patchState(store, { filter, paginator: paginatorInitialState.paginator });
98+
patchState(store, { filter, pager: initialPagerConfig });
9299
}),
93100
setPaginator(paginator: PaginatorState) {
94101
store.changePage(paginator);
@@ -98,8 +105,8 @@ export const HoldingsSerialStore = signalStore(
98105
debounceTime(400),
99106
switchMap(() => store.holdingsApiService.getIssuesByHoldings(
100107
store.holdings().metadata.pid,
101-
store.paginator.page(),
102-
store.paginator.rows(),
108+
store.pager.page(),
109+
store.pager.rows(),
103110
store.quickReceive(),
104111
store.filter()
105112
)),
@@ -121,7 +128,7 @@ export const HoldingsSerialStore = signalStore(
121128
switchMap((item: EsRecord) => store.recordUiService.deleteRecord('items', item.metadata.pid)),
122129
tap((success: boolean) => {
123130
if (success) {
124-
patchState(store, { reload: true, filter: undefined, paginator: paginatorInitialState.paginator });
131+
patchState(store, { reload: true, filter: undefined, pager: initialPagerConfig });
125132
}
126133
})
127134
)
@@ -140,7 +147,7 @@ export const HoldingsSerialStore = signalStore(
140147
catchError(() => undefined),
141148
tap((result) => {
142149
if (result) {
143-
patchState(store, { quickReceive: true, paginator: paginatorInitialState.paginator });
150+
patchState(store, { quickReceive: true, pager: initialPagerConfig });
144151
} else {
145152
store.messageService.add({
146153
severity: 'error',
@@ -174,7 +181,7 @@ export const HoldingsSerialStore = signalStore(
174181
});
175182
toObservable(store.issuesCount).pipe(numberGreatThan(3)).subscribe(() => store.loadIssues());
176183
toObservable(store.filter).pipe(nonNullable()).subscribe(() => store.loadItems());
177-
toObservable(store.paginator).pipe(nonNullable()).subscribe(() => store.loadItems());
184+
toObservable(store.pager).pipe(nonNullable()).subscribe(() => store.loadItems());
178185
toObservable(store.reload).subscribe(reload => {
179186
if (reload) {
180187
store.loadItems();

projects/admin/src/app/record/detail-view/holding-detail-view/serial-holding-detail-view/serial-holding-detail-view.component.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,7 @@ <h4 translate>Issues</h4>
132132
<admin-received-issue [issue]="item" [holding]="holding()" />
133133
}
134134
@if (store.isPaginatorEnabled()) {
135-
<shared-paginator class="ui:mt-4" [paginatorState]="paginatorConfig()" (pageChange)="store.setPaginator($event)" />
135+
<shared-paginator class="ui:mt-4" [pager]="store.pager()" [total]="store.receivedItemsCount()" (pageChange)="store.setPaginator($event)" />
136136
}
137137
</div>
138138
</div>

projects/admin/src/app/record/detail-view/holding-detail-view/serial-holding-detail-view/serial-holding-detail-view.component.ts

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,8 @@
1515
* You should have received a copy of the GNU Affero General Public License
1616
* along with this program. If not, see <http://www.gnu.org/licenses/>.
1717
*/
18-
import { Component, inject, input, model, OnInit, Signal } from '@angular/core';
19-
import { deepComputed } from '@ngrx/signals';
20-
import { EsRecord, PaginatorConfig } from '@rero/shared';
18+
import { Component, inject, input, model, OnInit } from '@angular/core';
19+
import { EsRecord } from '@rero/shared';
2120
import { HoldingsSerialStore } from '../holdings-serial-store';
2221

2322
@Component({
@@ -34,12 +33,6 @@ export class SerialHoldingDetailViewComponent implements OnInit {
3433

3534
protected filter = model<string>('');
3635

37-
protected paginatorConfig: Signal<PaginatorConfig> = deepComputed(() => ({
38-
first: this.store.paginator.first(),
39-
rows: this.store.paginator.rows(),
40-
total: this.store.receivedItemsCount()
41-
}));
42-
4336
/** OnInit hook */
4437
ngOnInit(): void {
4538
this.store.setHoldings(this.holding);

projects/public-search/src/app/document-detail/holdings/items/items.component.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,5 +41,5 @@
4141
}
4242

4343
@if (store.isPaginatorEnabled()) {
44-
<shared-paginator [paginatorState]="paginatorConfig()" (pageChange)="store.setPaginator($event)" />
44+
<shared-paginator [pager]="store.pager()" [total]="store.total()" (pageChange)="store.setPaginator($event)" />
4545
}

projects/public-search/src/app/document-detail/holdings/items/items.component.ts

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,10 @@
1414
* You should have received a copy of the GNU Affero General Public License
1515
* along with this program. If not, see <http://www.gnu.org/licenses/>.
1616
*/
17-
import { Component, inject, Input, model, OnInit, Signal } from '@angular/core';
17+
import { Component, inject, Input, model, OnInit } from '@angular/core';
1818
import { FormsModule } from '@angular/forms';
19-
import { deepComputed } from '@ngrx/signals';
2019
import { TranslateDirective, TranslatePipe } from "@ngx-translate/core";
21-
import { EsRecord, PaginatorComponent, PaginatorConfig } from '@rero/shared';
20+
import { EsRecord, PaginatorComponent } from '@rero/shared';
2221
import { InputGroupModule } from 'primeng/inputgroup';
2322
import { InputGroupAddonModule } from 'primeng/inputgroupaddon';
2423
import { InputTextModule } from 'primeng/inputtext';
@@ -46,12 +45,6 @@ export class ItemsComponent implements OnInit {
4645

4746
protected filter = model<string>('');
4847

49-
protected paginatorConfig: Signal<PaginatorConfig> = deepComputed(() => ({
50-
first: this.store.paginator.first(),
51-
rows: this.store.paginator.rows(),
52-
total: this.store.total()
53-
}));
54-
5548
// COMPONENT ATTRIBUTES =====================================================
5649
/** Holding */
5750
@Input() holding: EsRecord;

projects/public-search/src/app/document-detail/store/items-store.spec.ts

Lines changed: 22 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ describe('ItemsStore', () => {
3535
});
3636

3737
it('should return the holdings Pid and view code', (store = TestBed.inject(ItemsStore)) => {
38-
store.setHoldingsAndViewCode(holdings,"global");
38+
store.setHoldingsAndViewCode(holdings, "global");
3939
expect(store.holdings()).toBe(holdings);
4040
expect(store.viewCode()).toBe("global");
4141
});
@@ -59,27 +59,27 @@ describe('ItemsStore', () => {
5959
expect(store.filterTotal()).toEqual(1);
6060
}));
6161

62-
it('should reset the paginator after setting a filter.', fakeAsync((store = TestBed.inject(ItemsStore)) => {
63-
store.setPaginator({page: 1, first: 11, rows: 10});
64-
expect(store.paginator.page()).toEqual(2);
62+
it('should reset the paginator after setting a filter.', fakeAsync((store = TestBed.inject(ItemsStore)) => {
63+
store.setPaginator({ page: 1, first: 11, rows: 10 });
64+
expect(store.pager.page()).toEqual(2);
6565
store.setFilter('f-0');
6666

6767
tick(500);
68-
expect(store.paginator.page()).toEqual(1);
68+
expect(store.pager.page()).toEqual(1);
6969
console.log(store.isFilterEnabled());
7070
expect(store.isFilterEnabled()).toBeTrue();
71-
}));
71+
}));
7272

73-
it('should return the status of the paginator display.', fakeAsync((store = TestBed.inject(ItemsStore)) => {
74-
store.setPaginator({page: 0, first: 1, rows: 10});
73+
it('should return the status of the paginator display.', fakeAsync((store = TestBed.inject(ItemsStore)) => {
74+
store.setPaginator({ page: 0, first: 1, rows: 10 });
7575
store.setHoldingsAndViewCode(holdings, "global");
7676
store.load();
7777

7878
tick(500);
7979
expect(store.isPaginatorEnabled()).toBeTrue();
80-
store.setPaginator({page: 0, first: 1, rows: 20});
80+
store.setPaginator({ page: 0, first: 1, rows: 20 });
8181
expect(store.isPaginatorEnabled()).toBeFalse();
82-
}));
82+
}));
8383
});
8484

8585
const holdings: EsRecord = {
@@ -92,9 +92,9 @@ const holdings: EsRecord = {
9292
$schema: "https://bib.rero.ch/schemas/holdings/holding-v0.0.1.json",
9393
pid: "641",
9494
library: {
95-
name: "Bibliothèque du Lycée de la Vallée d'Aoste",
96-
pid: "4",
97-
type: "lib"
95+
name: "Bibliothèque du Lycée de la Vallée d'Aoste",
96+
pid: "4",
97+
type: "lib"
9898
},
9999
},
100100
updated: "2025-10-23T05:30:43.803060+00:00"
@@ -109,17 +109,17 @@ class ItemApiServiceMock {
109109
created: "2025-10-22T11:59:23.738167+00:00",
110110
id: `${i}`,
111111
links: {
112-
self: `https://localhost:5000/api/items/${i}`
112+
self: `https://localhost:5000/api/items/${i}`
113113
},
114114
metadata: {
115-
$schema: "https://bib.rero.ch/schemas/items/item-v0.0.1.json",
116-
barcode: `f-${i}`,
117-
pid: `${i}`,
118-
holding: {
119-
pid: "641",
120-
type: "hold"
121-
},
122-
status: "on_shelf"
115+
$schema: "https://bib.rero.ch/schemas/items/item-v0.0.1.json",
116+
barcode: `f-${i}`,
117+
pid: `${i}`,
118+
holding: {
119+
pid: "641",
120+
type: "hold"
121+
},
122+
status: "on_shelf"
123123
}
124124
});
125125
}

projects/public-search/src/app/document-detail/store/items-store.ts

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ import { computed, inject } from "@angular/core";
1818
import { toObservable } from "@angular/core/rxjs-interop";
1919
import { patchState, signalMethod, signalStore, withComputed, withHooks, withMethods, withState } from "@ngrx/signals";
2020
import { rxMethod } from "@ngrx/signals/rxjs-interop";
21-
import { EsRecord, nonNullable, paginatorInitialState, withPaginator } from "@rero/shared";
21+
import { EsRecord, nonNullable, Pager, withPaginator } from "@rero/shared";
2222
import { PaginatorState } from "primeng/paginator";
2323
import { withViewCode } from "projects/shared/src/lib/store/viewcode-feature";
2424
import { EsResult } from "projects/shared/src/public-api";
@@ -41,20 +41,27 @@ const itemsInitialState: Items = {
4141
filterTotal: 0
4242
}
4343

44+
const initialPagerConfig: Pager = {
45+
page: 1,
46+
first: 1,
47+
rows: 10,
48+
rowsPerPageOptions: [10, 20, 50]
49+
}
50+
4451
export const ItemsStore = signalStore(
4552
withState(itemsInitialState),
46-
withPaginator(),
53+
withPaginator(initialPagerConfig),
4754
withViewCode(),
4855
withComputed((store) => ({
4956
isFilterEnabled: computed(() => store.total() > 11 || '' !== store.filter()),
50-
isPaginatorEnabled: computed(() => store.paginator.rows() < store.filterTotal()),
57+
isPaginatorEnabled: computed(() => store.pager.rows() < store.filterTotal()),
5158
})),
5259
withMethods((store, itemApiService = inject(ItemApiService)) => ({
5360
setHoldingsAndViewCode(holdings: EsRecord, viewCode: string) {
5461
patchState(store, { holdings, viewCode })
5562
},
5663
setFilter: signalMethod<string>((filter: string) => {
57-
patchState(store, { filter, paginator: paginatorInitialState.paginator });
64+
patchState(store, { filter, pager: initialPagerConfig });
5865
}),
5966
setPaginator(paginator: PaginatorState) {
6067
store.changePage(paginator);
@@ -65,8 +72,8 @@ export const ItemsStore = signalStore(
6572
switchMap(() => itemApiService.getItemsByHoldingsAndViewcode(
6673
store.holdings(),
6774
store.viewCode(),
68-
store.paginator.page(),
69-
store.paginator.rows(),
75+
store.pager.page(),
76+
store.pager.rows(),
7077
store.filter()
7178
)),
7279
tap((result: EsResult) => {
@@ -86,7 +93,7 @@ export const ItemsStore = signalStore(
8693
withHooks((store) => ({
8794
onInit: () => {
8895
toObservable(store.filter).pipe(nonNullable()).subscribe(() => store.load());
89-
toObservable(store.paginator).subscribe(() => store.load())
96+
toObservable(store.pager).subscribe(() => store.load())
9097
}
9198
}))
9299
);

0 commit comments

Comments
 (0)