Skip to content

Commit dd9f381

Browse files
feat: release v20.0.0
# πŸš€ Major Release: v20.0.0 ## πŸ“¦ Dependencies & Infrastructure ### Core Dependencies - **BREAKING**: Make `@ngrx/signals@20` a peer dependency - Upgrade to NgRx 20, Angular 20, and Nx 21 - Update GitHub Actions to use Node 20 ## πŸ”§ Bug Fixes ### Pagination Functions Fixed critical issues in `withPagination` functions: - `gotoPage`: Fixed page navigation logic - `setPageSize`: Corrected page size calculation - `nextPage`: Fixed next page navigation - `previousPage`: Fixed previous page navigation - `firstPage`: Corrected first page navigation ## πŸ”„ Algorithm Improvements ### Storage Sync (IndexedDB) - **BREAKING**: Changed algorithm in `withStorageSync` for `IndexedDB` to improve initial sync waiting behavior - Enhanced synchronization reliability and performance - Better handling of async storage operations ## ⚠️ Breaking Changes ### Immutable State - **BREAKING**: `withImmutableState` no longer supports immutability checks for primitive root properties - This is due to NgRx 20's new state structure where root properties are `WritableSignal` types - Only object-type root properties can be frozen (immutability checks still work for nested objects) ## 🎯 Impact This major release brings: - Full compatibility with Angular 20 and NgRx 20 - Improved pagination functionality with fixed navigation - Enhanced storage synchronization for better user experience - Updated immutability behavior to align with modern NgRx patterns ## πŸ”— Migration Guide For users upgrading from v19: 1. Update Angular to v20 and NgRx to v20 2. Review any usage of `withImmutableState` with primitive root properties 3. Test pagination functionality with the fixed navigation functions 4. Verify IndexedDB storage sync behavior in your applications
1 parent 38221ef commit dd9f381

23 files changed

+5425
-5254
lines changed

β€Ž.github/workflows/build.yml

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,13 +16,12 @@ jobs:
1616
version: 10
1717
- uses: actions/setup-node@v4
1818
with:
19-
node-version: '18'
20-
cache: "pnpm"
19+
node-version: '20'
20+
cache: pnpm
2121
- run: pnpm install --frozen-lockfile
2222
- run: pnpm run format:check
2323
- run: pnpm run lint:all
2424
- run: pnpm run test:all
2525
- run: pnpm run test:e2e
2626
- run: pnpm run build:all
2727
- run: ./integration-tests.sh
28-

β€Ž.github/workflows/deploy-docs.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ jobs:
2424
version: 10
2525
- uses: actions/setup-node@v4
2626
with:
27-
node-version: 18
27+
node-version: 20
2828
cache: pnpm
2929

3030
- name: Install dependencies for toolkit

β€Žapps/demo/src/app/core/sidebar/sidebar.component.ts

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { BreakpointObserver, Breakpoints } from '@angular/cdk/layout';
22
import { CommonModule } from '@angular/common';
3-
import { Component, Inject } from '@angular/core';
3+
import { Component, inject } from '@angular/core';
44
import { MatButtonModule } from '@angular/material/button';
55
import { MatIconModule } from '@angular/material/icon';
66
import { MatListModule } from '@angular/material/list';
@@ -24,12 +24,10 @@ import { map, shareReplay } from 'rxjs';
2424
styleUrls: ['./sidebar.component.css'],
2525
})
2626
export class SidebarComponent {
27+
private breakpointObserver = inject(BreakpointObserver);
28+
2729
isHandset$ = this.breakpointObserver.observe(Breakpoints.Handset).pipe(
2830
map((result) => result.matches),
2931
shareReplay(),
3032
);
31-
32-
constructor(
33-
@Inject(BreakpointObserver) private breakpointObserver: BreakpointObserver,
34-
) {}
3533
}

β€Žapps/demo/src/app/shared/flight.service.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
import { DataService } from '@angular-architects/ngrx-toolkit';
22
import { HttpClient, HttpHeaders, HttpParams } from '@angular/common/http';
3-
import { Injectable } from '@angular/core';
3+
import { inject, Injectable } from '@angular/core';
44
import { EntityId } from '@ngrx/signals/entities';
5-
import { Observable, firstValueFrom } from 'rxjs';
5+
import { firstValueFrom, Observable } from 'rxjs';
66
import { Flight } from './flight';
77

88
export type FlightFilter = {
@@ -16,7 +16,7 @@ export type FlightFilter = {
1616
export class FlightService implements DataService<Flight, FlightFilter> {
1717
baseUrl = `https://demo.angulararchitects.io/api`;
1818

19-
constructor(private http: HttpClient) {}
19+
private http = inject(HttpClient);
2020

2121
loadById(id: EntityId): Promise<Flight> {
2222
return firstValueFrom(this.findById('' + id));

β€Žapps/demo/src/test-setup.ts

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
1-
// @ts-expect-error https://thymikee.github.io/jest-preset-angular/docs/getting-started/test-environment
2-
globalThis.ngJest = {
3-
testEnvironmentOptions: {
4-
errorOnUnknownElements: true,
5-
errorOnUnknownProperties: true,
6-
},
7-
};
8-
import 'jest-preset-angular/setup-jest';
1+
import { setupZoneTestEnv } from 'jest-preset-angular/setup-env/zone';
2+
3+
setupZoneTestEnv({
4+
errorOnUnknownElements: true,
5+
errorOnUnknownProperties: true,
6+
});

β€Žjest.config.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { getJestProjectsAsync } from '@nx/jest';
2+
import type { Config } from 'jest';
23

3-
export default async () => ({
4+
export default async (): Promise<Config> => ({
45
projects: await getJestProjectsAsync(),
56
});

β€Žlibs/ngrx-toolkit/package.json

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,16 @@
11
{
22
"name": "@angular-architects/ngrx-toolkit",
3-
"version": "19.1.0",
3+
"version": "20.0.0",
44
"license": "MIT",
55
"repository": {
66
"type": "GitHub",
77
"url": "https://github.com/angular-architects/ngrx-toolkit"
88
},
99
"peerDependencies": {
10-
"@angular/core": "^19.0.0",
11-
"@angular/common": "^19.0.0",
12-
"@ngrx/signals": "^19.1.0",
13-
"@ngrx/store": "^19.1.0",
10+
"@angular/core": "^20.0.0",
11+
"@angular/common": "^20.0.0",
12+
"@ngrx/signals": "^20.0.0",
13+
"@ngrx/store": "^20.0.0",
1414
"rxjs": "^7.0.0"
1515
},
1616
"peerDependenciesMeta": {

β€Žlibs/ngrx-toolkit/src/lib/devtools/tests/action-name.spec.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ describe('updateState', () => {
4040
store.setName('i4');
4141
TestBed.flushEffects();
4242

43-
expect(sendSpy).lastCalledWith(
43+
expect(sendSpy).toHaveBeenLastCalledWith(
4444
{ type: 'Set Name' },
4545
{ shop: { name: 'i4' } },
4646
);

β€Žlibs/ngrx-toolkit/src/lib/devtools/tests/connecting.spec.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ describe('connect & send', () => {
1919
it('should not throw if it runs on the server', () => {
2020
setupExtensions(true, false);
2121
const Store = signalStore({ providedIn: 'root' }, withDevtools('flight'));
22-
expect(() => TestBed.inject(Store)).not.toThrowError();
22+
expect(() => TestBed.inject(Store)).not.toThrow();
2323
});
2424

2525
it('should only send when store is initialized', () => {

β€Žlibs/ngrx-toolkit/src/lib/devtools/tests/naming.spec.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ describe('withDevtools / renaming', () => {
3030

3131
TestBed.flushEffects();
3232

33-
expect(sendSpy).lastCalledWith(
33+
expect(sendSpy).toHaveBeenLastCalledWith(
3434
{ type: 'Store Update' },
3535
{
3636
flights: { airline: 'Lufthansa' },

0 commit comments

Comments
Β (0)