refactor: angular 20 upgrade

This commit is contained in:
Rainer Killinger
2026-10-01 09:44:39 +02:00
parent 7105b38c71
commit 6d94dd74d7
10 changed files with 2698 additions and 1773 deletions
+24
View File
@@ -205,6 +205,30 @@
}, },
"@ionic/angular-toolkit:page": { "@ionic/angular-toolkit:page": {
"styleext": "scss" "styleext": "scss"
},
"@schematics/angular:component": {
"type": "component"
},
"@schematics/angular:directive": {
"type": "directive"
},
"@schematics/angular:service": {
"type": "service"
},
"@schematics/angular:guard": {
"typeSeparator": "."
},
"@schematics/angular:interceptor": {
"typeSeparator": "."
},
"@schematics/angular:module": {
"typeSeparator": "."
},
"@schematics/angular:pipe": {
"typeSeparator": "."
},
"@schematics/angular:resolver": {
"typeSeparator": "."
} }
} }
} }
+24 -24
View File
@@ -48,13 +48,13 @@
"test:integration": "sh integration-test.sh" "test:integration": "sh integration-test.sh"
}, },
"dependencies": { "dependencies": {
"@angular/animations": "19.2.25", "@angular/animations": "20.3.31",
"@angular/cdk": "19.2.19", "@angular/cdk": "20.2.14",
"@angular/common": "19.2.25", "@angular/common": "20.3.31",
"@angular/core": "19.2.25", "@angular/core": "20.3.31",
"@angular/forms": "19.2.25", "@angular/forms": "20.3.31",
"@angular/platform-browser": "19.2.25", "@angular/platform-browser": "20.3.31",
"@angular/router": "19.2.25", "@angular/router": "20.3.31",
"@awesome-cordova-plugins/calendar": "8.1.0", "@awesome-cordova-plugins/calendar": "8.1.0",
"@awesome-cordova-plugins/core": "8.1.0", "@awesome-cordova-plugins/core": "8.1.0",
"@capacitor-community/in-app-review": "8.0.0", "@capacitor-community/in-app-review": "8.0.0",
@@ -96,7 +96,7 @@
"ionic-appauth": "2.1.0", "ionic-appauth": "2.1.0",
"ionicons": "8.1.0", "ionicons": "8.1.0",
"jsonpath-plus": "10.3.0", "jsonpath-plus": "10.3.0",
"maplibre-gl": "6.0.0", "maplibre-gl": "6.4.1",
"material-symbols": "0.17.1", "material-symbols": "0.17.1",
"moment": "2.30.1", "moment": "2.30.1",
"ngx-date-fns": "11.0.0", "ngx-date-fns": "11.0.0",
@@ -113,21 +113,21 @@
"zone.js": "0.16.2" "zone.js": "0.16.2"
}, },
"devDependencies": { "devDependencies": {
"@angular-devkit/architect": "0.1902.27", "@angular-devkit/architect": "0.2003.37",
"@angular-devkit/build-angular": "19.2.27", "@angular-devkit/build-angular": "20.3.37",
"@angular-devkit/core": "19.2.27", "@angular-devkit/core": "20.3.37",
"@angular-devkit/schematics": "19.2.27", "@angular-devkit/schematics": "20.3.37",
"@angular-eslint/builder": "19.8.1", "@angular-eslint/builder": "20.7.0",
"@angular-eslint/eslint-plugin": "19.8.1", "@angular-eslint/eslint-plugin": "20.7.0",
"@angular-eslint/eslint-plugin-template": "19.8.1", "@angular-eslint/eslint-plugin-template": "20.7.0",
"@angular-eslint/schematics": "19.8.1", "@angular-eslint/schematics": "20.7.0",
"@angular-eslint/template-parser": "19.8.1", "@angular-eslint/template-parser": "20.7.0",
"@angular/cli": "19.2.27", "@angular/cli": "20.3.37",
"@angular/compiler": "19.2.25", "@angular/compiler": "20.3.31",
"@angular/compiler-cli": "19.2.25", "@angular/compiler-cli": "20.3.31",
"@angular/language-server": "19.2.2", "@angular/language-server": "20.3.0",
"@angular/language-service": "19.2.25", "@angular/language-service": "20.3.31",
"@angular/platform-browser-dynamic": "19.2.25", "@angular/platform-browser-dynamic": "20.3.31",
"@capacitor/android": "8.2.0", "@capacitor/android": "8.2.0",
"@capacitor/assets": "3.0.5", "@capacitor/assets": "3.0.5",
"@capacitor/cli": "8.2.0", "@capacitor/cli": "8.2.0",
@@ -179,7 +179,7 @@
"stylelint-config-standard-scss": "17.0.0", "stylelint-config-standard-scss": "17.0.0",
"surge": "0.23.1", "surge": "0.23.1",
"ts-node": "10.9.2", "ts-node": "10.9.2",
"typescript": "5.5.4" "typescript": "5.9.3"
}, },
"cordova": { "cordova": {
"plugins": {}, "plugins": {},
+1 -6
View File
@@ -72,6 +72,7 @@ describe('AppComponent', () => {
configProvider.getAnyValue = jasmine.createSpy().and.callFake(function () { configProvider.getAnyValue = jasmine.createSpy().and.callFake(function () {
return sampleAuthConfiguration; return sampleAuthConfiguration;
}); });
inAppReviewProvider = jasmine.createSpyObj('InAppReviewProvider', ['init']);
ngxLogger = jasmine.createSpyObj('NGXLogger', ['log', 'error', 'warn']); ngxLogger = jasmine.createSpyObj('NGXLogger', ['log', 'error', 'warn']);
storageProvider = jasmine.createSpyObj('StorageProvider', ['init', 'get', 'has', 'put']); storageProvider = jasmine.createSpyObj('StorageProvider', ['init', 'get', 'has', 'put']);
simpleBrowser = jasmine.createSpyObj('SimpleBrowser', ['open']); simpleBrowser = jasmine.createSpyObj('SimpleBrowser', ['open']);
@@ -108,11 +109,5 @@ describe('AppComponent', () => {
it('should initialize the app', async () => { it('should initialize the app', async () => {
TestBed.createComponent(AppComponent); TestBed.createComponent(AppComponent);
expect(platformSpy.ready).toHaveBeenCalled(); expect(platformSpy.ready).toHaveBeenCalled();
// await platformReadySpy;
// TODO: https://capacitorjs.com/docs/guides/mocking-plugins
// expect(splashScreenSpy.hide).toHaveBeenCalled();
}); });
// TODO: add more tests!
}); });
@@ -35,7 +35,7 @@ export class AuthGuardService implements CanActivate {
try { try {
await this.authHelper.getProvider().getValidToken(); await this.authHelper.getProvider().getValidToken();
} catch { } catch {
const originNavigation = this.router.getCurrentNavigation(); const originNavigation = this.router.currentNavigation();
let extras: NavigationExtras = {}; let extras: NavigationExtras = {};
if (originNavigation) { if (originNavigation) {
const url = originNavigation.extractedUrl.toString(); const url = originNavigation.extractedUrl.toString();
@@ -95,7 +95,7 @@ export class DataDetailComponent implements OnInit {
readonly modalController: ModalController, readonly modalController: ModalController,
translateService: TranslateService, translateService: TranslateService,
) { ) {
this.inputItem = router.getCurrentNavigation()?.extras.state?.item; this.inputItem = router.currentNavigation()?.extras.state?.item;
if (!this.inputItem?.origin) { if (!this.inputItem?.origin) {
// We received a ThingWithoutReferences. // We received a ThingWithoutReferences.
// This can happen, for example, when detail views use `inPlace` list items // This can happen, for example, when detail views use `inPlace` list items
@@ -29,7 +29,6 @@ export class CompassControlComponent {
map(event => { map(event => {
// const pitch = event.target.transform.pitch; // const pitch = event.target.transform.pitch;
// const bearing = event.target.transform.bearing; // const bearing = event.target.transform.bearing;
// return `rotateX(${pitch}deg) rotateZ(${bearing}deg)`; // return `rotateX(${pitch}deg) rotateZ(${bearing}deg)`;
}), }),
); );
@@ -44,7 +44,7 @@ export class GeoNavigationDirective {
const address = this.geoNavigation.address const address = this.geoNavigation.address
? this.translateService.instant( ? this.translateService.instant(
'map.directions.ADDRESS', 'map.directions.ADDRESS',
this.thingTranslate.get(this.geoNavigation as SCThings, 'address'), this.thingTranslate.get(this.geoNavigation as SCThings, 'address') as object,
) )
: `${lat}, ${lon}`; : `${lat}, ${lon}`;
@@ -22,30 +22,37 @@
<ion-content> <ion-content>
<!-- Sort Context --> <!-- Sort Context -->
<ion-list *ngIf="sortOption"> @if (sortOption) {
<ion-list>
<ion-radio-group class="context-sort" [value]="0"> <ion-radio-group class="context-sort" [value]="0">
<ion-list-header> <ion-list-header>
<ion-icon name="sort"></ion-icon> <ion-icon name="sort"></ion-icon>
<ion-title>{{ 'menu.context.sort.title' | translate | titlecase }}</ion-title> <ion-title>{{ 'menu.context.sort.title' | translate | titlecase }}</ion-title>
</ion-list-header> </ion-list-header>
<ion-item @for (value of sortOption.values; track value; let i = $index) {
class="sort-item" <ion-item class="sort-item" (click)="sortChanged(sortOption, value)">
*ngFor="let value of sortOption.values; let i = index"
(click)="sortChanged(sortOption, value)"
>
<ion-radio [value]="i"> <ion-radio [value]="i">
{{ 'menu.context.sort.' + value.value | translate | titlecase }} {{ 'menu.context.sort.' + value.value | translate | titlecase }}
<span *ngIf="sortOption.value === value.value && value.reversible"> @if (sortOption.value === value.value && value.reversible) {
<ion-icon *ngIf="sortOption.reversed" name="arrow_downward"></ion-icon> <span>
<ion-icon *ngIf="!sortOption.reversed" name="arrow_upward"></ion-icon> @if (sortOption.reversed) {
<ion-icon name="arrow_downward"></ion-icon>
}
@if (!sortOption.reversed) {
<ion-icon name="arrow_upward"></ion-icon>
}
</span> </span>
}
</ion-radio> </ion-radio>
</ion-item> </ion-item>
}
</ion-radio-group> </ion-radio-group>
</ion-list> </ion-list>
}
<!-- Filter Context --> <!-- Filter Context -->
<form class="context-filter" *ngIf="filterOption"> @if (filterOption) {
<form class="context-filter">
<ion-list-header> <ion-list-header>
<ion-icon name="filter_list"></ion-icon> <ion-icon name="filter_list"></ion-icon>
<ion-title>{{ 'menu.context.filter.title' | translate | titlecase }}</ion-title> <ion-title>{{ 'menu.context.filter.title' | translate | titlecase }}</ion-title>
@@ -53,22 +60,22 @@
<ion-icon name="delete"></ion-icon> <ion-icon name="delete"></ion-icon>
</ion-button> </ion-button>
</ion-list-header> </ion-list-header>
@for (facet of facets; track facet) {
<ion-list class="filter-group" *ngFor="let facet of facets"> <ion-list class="filter-group">
<ion-list-header class="h3"> <ion-list-header class="h3">
<ion-label> <ion-label>
<span *ngIf="facet.info.onlyOnType" @if (facet.info.onlyOnType) {
<span
><b>{{ facet.info.onlyOnType | titlecase }}</b> / ><b>{{ facet.info.onlyOnType | titlecase }}</b> /
</span> </span>
}
{{ facet.info.field | titlecase }} {{ facet.info.field | titlecase }}
</ion-label> </ion-label>
</ion-list-header> </ion-list-header>
@for (
<ng-container bucket of !facet.compact ? facet.buckets.slice(0, compactFilterOptionCount) : facet.buckets;
*ngFor=" track bucket
let bucket of !facet.compact ? facet.buckets.slice(0, compactFilterOptionCount) : facet.buckets ) {
"
>
<ion-item> <ion-item>
<ion-checkbox <ion-checkbox
[(ngModel)]="bucket.checked" [(ngModel)]="bucket.checked"
@@ -85,20 +92,19 @@
{{ {{
facet.field === 'type' facet.field === 'type'
? (getTranslatedPropertyValue($any(bucket.key), 'type') | titlecase) ? (getTranslatedPropertyValue($any(bucket.key), 'type') | titlecase)
: (facet.onlyOnType && getTranslatedPropertyValue(facet.onlyOnType, facet.field, bucket.key) : (facet.onlyOnType &&
| titlecase) getTranslatedPropertyValue(facet.onlyOnType, facet.field, bucket.key) | titlecase)
}} }}
</ion-checkbox> </ion-checkbox>
</ion-item> </ion-item>
</ng-container> }
@if (!facet.compact && facet.buckets.length > compactFilterOptionCount) {
<ion-button <ion-button fill="clear" (click)="facet.compact = true">
*ngIf="!facet.compact && facet.buckets.length > compactFilterOptionCount"
fill="clear"
(click)="facet.compact = true"
>
{{ 'menu.context.filter.showAll' | translate }} {{ 'menu.context.filter.showAll' | translate }}
</ion-button> </ion-button>
}
</ion-list> </ion-list>
}
</form> </form>
}
</ion-content> </ion-content>
@@ -35,7 +35,7 @@ export class RoutingStackService {
this.currentRoute = event.urlAfterRedirects; this.currentRoute = event.urlAfterRedirects;
this.lastDataDetail = this.currentDataDetail; this.lastDataDetail = this.currentDataDetail;
this.currentDataDetail = this.router.getCurrentNavigation()!.extras.state?.item; this.currentDataDetail = this.router.currentNavigation()!.extras.state?.item;
} }
}); });
} }
+2563 -1662
View File
File diff suppressed because it is too large Load Diff