Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[JSS 22][Angular] Upgrade to version 18 #2029

Merged
merged 5 commits into from
Feb 5, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,18 @@ Our versioning strategy is as follows:
- Minor: may include breaking changes in framework packages (e.g. framework upgrades, new features, improvements)
- Major: may include breaking changes in core packages (e.g. major architectural changes, major features)

## 22.5.0

### 🎉 New Features & Improvements

* `[sitecore-jss-angular]` Support `CanActivate` `RedirectCommand` API ([#2029](https://github.com/Sitecore/jss/pull/2029))
* `[sitecore-jss-angular]` `CanActivate` and `CanResolve` now additionally accept `router` as a parameter ([#2029](https://github.com/Sitecore/jss/pull/2029))

### 🛠 Breaking Change

* Upgrade Angular to v18 ([#2029](https://github.com/Sitecore/jss/pull/2029))
* Updated Angular and core dependencies to ~18.2.13

## 22.4.1

### 🐛 Bug Fixes
Expand Down
42 changes: 21 additions & 21 deletions packages/create-sitecore-jss/src/templates/angular/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -45,20 +45,20 @@
"homepage": "https://jss.sitecore.com",
"license": "Apache-2.0",
"dependencies": {
"@angular/animations": "~17.3.11",
"@angular/common": "~17.3.11",
"@angular/compiler": "~17.3.11",
"@angular/core": "~17.3.11",
"@angular/forms": "~17.3.11",
"@angular/platform-browser": "~17.3.11",
"@angular/platform-browser-dynamic": "~17.3.11",
"@angular/platform-server": "~17.3.11",
"@angular/router": "~17.3.11",
"@apollo/client": "^3.3.12",
"@angular/animations": "~18.2.13",
"@angular/common": "~18.2.13",
"@angular/compiler": "~18.2.13",
"@angular/core": "~18.2.13",
"@angular/forms": "~18.2.13",
"@angular/platform-browser": "~18.2.13",
"@angular/platform-browser-dynamic": "~18.2.13",
"@angular/platform-server": "~18.2.13",
"@angular/router": "~18.2.13",
"@apollo/client": "^3.12.9",
"@ngx-translate/core": "~15.0.0",
"@ngx-translate/http-loader": "~8.0.0",
"@sitecore-jss/sitecore-jss-angular": "~<%- version %>",
"apollo-angular": "~6.0.0",
"apollo-angular": "~8.0.2",
"bootstrap": "^5.3.3",
"core-js": "~3.37.1",
"graphql": "15.5.0",
Expand All @@ -69,16 +69,16 @@
"reflect-metadata": "^0.2.2"
},
"devDependencies": {
"@angular-builders/custom-webpack": "^17.0.2",
"@angular-devkit/build-angular": "^17.3.8",
"@angular-eslint/builder": "^17.5.2",
"@angular-eslint/eslint-plugin": "^17.5.2",
"@angular-eslint/eslint-plugin-template": "^17.5.2",
"@angular-eslint/schematics": "^17.5.2",
"@angular-eslint/template-parser": "^17.5.2",
"@angular/cli": "~17.3.8",
"@angular/compiler-cli": "~17.3.11",
"@angular/language-service": "~17.3.11",
"@angular-builders/custom-webpack": "^18.0.0",
"@angular-devkit/build-angular": "^18.2.14",
"@angular-eslint/builder": "^18.4.3",
"@angular-eslint/eslint-plugin": "^18.4.3",
"@angular-eslint/eslint-plugin-template": "^18.4.3",
"@angular-eslint/schematics": "^18.4.3",
"@angular-eslint/template-parser": "^18.4.3",
"@angular/cli": "~18.2.13",
"@angular/compiler-cli": "~18.2.13",
"@angular/language-service": "~18.2.13",
"@sitecore-jss/sitecore-jss-angular-schematics": "~<%- version %>",
"@sitecore-jss/sitecore-jss-cli": "~<%- version %>",
"@sitecore-jss/sitecore-jss-dev-tools": "~<%- version %>",
Expand Down
6 changes: 3 additions & 3 deletions packages/sitecore-jss-angular-schematics/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,9 @@
},
"schematics": "./src/collection.json",
"dependencies": {
"@angular-devkit/core": "~17.3.8",
"@angular-devkit/schematics": "~17.3.8",
"@schematics/angular": "~17.3.8",
"@angular-devkit/core": "~18.2.14",
"@angular-devkit/schematics": "~18.2.14",
"@schematics/angular": "~18.2.14",
"chalk": "^2.4.2"
},
"devDependencies": {
Expand Down
22 changes: 11 additions & 11 deletions packages/sitecore-jss-angular/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,16 +23,16 @@
"url": "https://github.com/sitecore/jss/issues"
},
"devDependencies": {
"@angular-devkit/build-angular": "~17.3.8",
"@angular-eslint/eslint-plugin": "^17.5.2",
"@angular/cli": "~17.3.8",
"@angular/common": "~17.3.11",
"@angular/compiler": "~17.3.11",
"@angular/compiler-cli": "~17.3.11",
"@angular/core": "~17.3.11",
"@angular/platform-browser": "~17.3.11",
"@angular/platform-browser-dynamic": "~17.3.11",
"@angular/router": "~17.3.11",
"@angular-devkit/build-angular": "~18.2.14",
"@angular-eslint/eslint-plugin": "^18.4.3",
"@angular/cli": "~18.2.13",
"@angular/common": "~18.2.13",
"@angular/compiler": "~18.2.13",
"@angular/compiler-cli": "~18.2.13",
"@angular/core": "~18.2.13",
"@angular/platform-browser": "~18.2.13",
"@angular/platform-browser-dynamic": "~18.2.13",
"@angular/router": "~18.2.13",
"@sitecore-cloudsdk/events": "^0.4.2",
"@types/jasmine": "^5.1.4",
"@types/node": "^22.9.0",
Expand All @@ -47,7 +47,7 @@
"karma-firefox-launcher": "^2.1.3",
"karma-jasmine": "~5.1.0",
"karma-jasmine-html-reporter": "~2.1.0",
"ng-packagr": "^17.3.0",
"ng-packagr": "^18.2.1",
"reflect-metadata": "^0.1.13",
"rxjs": "~7.8.1",
"tslib": "^2.3.1",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import {
TemplateRef,
ViewChild,
} from '@angular/core';
import { Router } from '@angular/router';
import { RedirectCommand, Router } from '@angular/router';
import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
import { Location } from '@angular/common';
import { By } from '@angular/platform-browser';
Expand Down Expand Up @@ -525,6 +525,15 @@ class MockUrlTreeGuard implements JssCanActivate {
}
}

@Injectable()
class MockRedirectCommandGuard implements JssCanActivate {
constructor(private readonly router: Router) {}

canActivate() {
return new RedirectCommand(this.router.parseUrl('/404'));
}
}

@Component({
selector: 'not-found',
template: `
Expand Down Expand Up @@ -593,6 +602,11 @@ describe('<sc-placeholder /> with lazy loaded modules', () => {
loadChildren: loadChildrenFunc,
canActivate: [MockUrlTreeGuard],
},
{
path: 'JumbotronCanActivateRedirectCommand',
loadChildren: loadChildrenFunc,
canActivate: [MockRedirectCommandGuard],
},
{
path: 'JumbotronCanActivateUrlString',
loadChildren: loadChildrenFunc,
Expand All @@ -606,7 +620,7 @@ describe('<sc-placeholder /> with lazy loaded modules', () => {
]
),
],
providers: [MockUrlTreeGuard, MockUnexpectedErrorGuard],
providers: [MockUrlTreeGuard, MockRedirectCommandGuard, MockUnexpectedErrorGuard],
}).compileComponents();
})
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ import {
ViewChild,
ViewContainerRef,
} from '@angular/core';
import { Data, Router, UrlTree } from '@angular/router';
import { Data, RedirectCommand, Router, UrlTree } from '@angular/router';
import {
ComponentRendering,
HtmlElementRendering,
Expand Down Expand Up @@ -383,7 +383,9 @@ export class PlaceholderComponent implements OnInit, OnChanges, DoCheck, OnDestr
this.isLoading = false;
if (e instanceof JssCanActivateRedirectError) {
const redirectValue = e.redirectValue;
if (redirectValue instanceof UrlTree) {
if (redirectValue instanceof RedirectCommand) {
this.router.navigateByUrl(redirectValue.redirectTo);
} else if (redirectValue instanceof UrlTree) {
this.router.navigateByUrl(redirectValue);
} else if (typeof redirectValue === 'string') {
this.router.navigate([redirectValue]);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ export function dataResolverFactory(
activatedRoute: activatedRoute.snapshot,
routerState: router.routerState.snapshot,
rendering: factory.componentDefinition as ComponentRendering,
router,
});
const data$ = wrapIntoObservable(data);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

import { Injectable, Injector } from '@angular/core';
import { TestBed, waitForAsync } from '@angular/core/testing';
import { ActivatedRoute, Router } from '@angular/router';
import { ActivatedRoute, RedirectCommand, Router } from '@angular/router';
import { RouterTestingModule } from '@angular/router/testing';
import { Observable, of } from 'rxjs';
import { guardResolverFactory } from './guard-resolver-factory';
Expand Down Expand Up @@ -72,6 +72,15 @@ class MockUrlTreeGuard implements JssCanActivate {
}
}

@Injectable()
class MockRedirectCommandGuard implements JssCanActivate {
constructor(private readonly router: Router) {}

canActivate() {
return new RedirectCommand(this.router.parseUrl('/404'));
}
}

@Injectable()
class MockUrlGuard implements JssCanActivate {
canActivate() {
Expand Down Expand Up @@ -100,6 +109,7 @@ describe('guardResolverFactory', () => {
MockService,
MockInjectableGuard,
MockUrlTreeGuard,
MockRedirectCommandGuard,
MockUrlGuard,
MockUrlsGuard,
{
Expand Down Expand Up @@ -172,6 +182,18 @@ describe('guardResolverFactory', () => {
).toBeRejectedWithError(JssCanActivateRedirectError, "Value: '/404' is a redirect value");
});

it('Throws JssCanActivateRedirectError when returning RedirectCommand', () => {
return expectAsync(
resolver([
{
canActivate: MockRedirectCommandGuard,
componentDefinition: {} as any,
},
])
// eslint-disable-next-line quotes
).toBeRejectedWithError(JssCanActivateRedirectError, "Value: '/404' is a redirect value");
});

it('Throws JssCanActivateRedirectError when returning string', () => {
return expectAsync(
resolver([
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Injector, Type } from '@angular/core';
import { ActivatedRoute, Router, UrlTree } from '@angular/router';
import { ActivatedRoute, RedirectCommand, Router, UrlTree } from '@angular/router';
import { ComponentRendering } from '@sitecore-jss/sitecore-jss/layout';
import { lastValueFrom, of } from 'rxjs';
import { mergeMap, take } from 'rxjs/operators';
Expand All @@ -9,13 +9,18 @@ import { JssCanActivateRedirectError } from './jss-can-activate-error';
import { JssCanActivate, JssCanActivateFn } from './placeholder.token';

/**
* @param {boolean | string | string[] | UrlTree} value
* @param {boolean | string | string[] | UrlTree | RedirectCommand} value
* @returns instance of value
*/
function isRedirectValue(
value: boolean | string | string[] | UrlTree
): value is string | string[] | UrlTree {
return value instanceof UrlTree || typeof value === 'string' || Array.isArray(value);
value: boolean | string | string[] | UrlTree | RedirectCommand
): value is string | string[] | UrlTree | RedirectCommand {
return (
value instanceof UrlTree ||
value instanceof RedirectCommand ||
typeof value === 'string' ||
Array.isArray(value)
);
}

/**
Expand Down Expand Up @@ -78,6 +83,7 @@ export function guardResolverFactory(
activatedRoute: activatedRoute.snapshot,
routerState: router.routerState.snapshot,
rendering: factory.componentDefinition as ComponentRendering,
router,
});

const canActivate$ = wrapIntoObservable(guardValue);
Expand All @@ -87,8 +93,16 @@ export function guardResolverFactory(
take(1),
mergeMap((value) => {
if (isRedirectValue(value)) {
let message;

if (value instanceof RedirectCommand) {
message = value.redirectTo;
} else {
message = value;
}

throw new JssCanActivateRedirectError(
`Value: '${value.toString()}' is a redirect value`,
`Value: '${message.toString()}' is a redirect value`,
value
);
} else {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
import { UrlTree } from '@angular/router';
import { RedirectCommand, UrlTree } from '@angular/router';

/**
* Error thrown when a JssCanActivate guard returns a redirect value.
* The redirect value will be used to redirect the user to a different route.
*/
export class JssCanActivateRedirectError extends Error {
constructor(public message: string, public redirectValue: string | string[] | UrlTree) {
constructor(
public message: string,
public redirectValue: string | string[] | UrlTree | RedirectCommand
) {
super(message);
this.name = 'JssCanActivateRedirectError';
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { TestBed, fakeAsync, flush } from '@angular/core/testing';
import { JssStateService, BaseJssState } from './jss-state.service';
import { TransferState } from '@angular/platform-browser';
import { TransferState } from '@angular/core';

describe('JssStateService', () => {
let service: JssStateService;
Expand Down
15 changes: 12 additions & 3 deletions packages/sitecore-jss-angular/src/services/placeholder.token.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
import { InjectionToken, Type } from '@angular/core';
import { ActivatedRouteSnapshot, Data, RouterStateSnapshot, UrlTree } from '@angular/router';
import {
ActivatedRouteSnapshot,
Data,
RouterStateSnapshot,
UrlTree,
RedirectCommand,
Router,
} from '@angular/router';
import { Observable } from 'rxjs';
import { ComponentFactoryResult } from './jss-component-factory.service';
import { ComponentRendering } from '../public_api';
Expand Down Expand Up @@ -80,14 +87,16 @@ export interface GuardInput {
activatedRoute: ActivatedRouteSnapshot;
routerState: RouterStateSnapshot;
rendering: ComponentRendering;
router: Router;
}

export interface JssCanActivateFn {
(input: GuardInput):
| Observable<boolean | UrlTree | string | string[]>
| Promise<boolean | UrlTree | string | string[]>
| Observable<boolean | UrlTree | RedirectCommand | string | string[]>
| Promise<boolean | UrlTree | RedirectCommand | string | string[]>
| boolean
| UrlTree
| RedirectCommand
| string
| string[];
}
Expand Down
17 changes: 17 additions & 0 deletions packages/sitecore-jss-angular/src/test-data/lazy-loading/data.ts
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,23 @@ export const testDataNavigation: { label: string; data: ComponentRendering }[] =
},
},
},
{
label: 'jumbotron with canActivate with returning RedirectCommand',
data: {
componentName: 'dummy',
uid: 'dummy',
placeholders: {
main: [
{
componentName: 'JumbotronCanActivateRedirectCommand',
fields: {},
params: {},
uid: 'jumbotron-can-activate-url-tree',
},
],
},
},
},
{
label: 'jumbotron with canActivate with returning url string',
data: {
Expand Down
Loading