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": {
"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"
},
"dependencies": {
"@angular/animations": "19.2.25",
"@angular/cdk": "19.2.19",
"@angular/common": "19.2.25",
"@angular/core": "19.2.25",
"@angular/forms": "19.2.25",
"@angular/platform-browser": "19.2.25",
"@angular/router": "19.2.25",
"@angular/animations": "20.3.31",
"@angular/cdk": "20.2.14",
"@angular/common": "20.3.31",
"@angular/core": "20.3.31",
"@angular/forms": "20.3.31",
"@angular/platform-browser": "20.3.31",
"@angular/router": "20.3.31",
"@awesome-cordova-plugins/calendar": "8.1.0",
"@awesome-cordova-plugins/core": "8.1.0",
"@capacitor-community/in-app-review": "8.0.0",
@@ -96,7 +96,7 @@
"ionic-appauth": "2.1.0",
"ionicons": "8.1.0",
"jsonpath-plus": "10.3.0",
"maplibre-gl": "6.0.0",
"maplibre-gl": "6.4.1",
"material-symbols": "0.17.1",
"moment": "2.30.1",
"ngx-date-fns": "11.0.0",
@@ -113,21 +113,21 @@
"zone.js": "0.16.2"
},
"devDependencies": {
"@angular-devkit/architect": "0.1902.27",
"@angular-devkit/build-angular": "19.2.27",
"@angular-devkit/core": "19.2.27",
"@angular-devkit/schematics": "19.2.27",
"@angular-eslint/builder": "19.8.1",
"@angular-eslint/eslint-plugin": "19.8.1",
"@angular-eslint/eslint-plugin-template": "19.8.1",
"@angular-eslint/schematics": "19.8.1",
"@angular-eslint/template-parser": "19.8.1",
"@angular/cli": "19.2.27",
"@angular/compiler": "19.2.25",
"@angular/compiler-cli": "19.2.25",
"@angular/language-server": "19.2.2",
"@angular/language-service": "19.2.25",
"@angular/platform-browser-dynamic": "19.2.25",
"@angular-devkit/architect": "0.2003.37",
"@angular-devkit/build-angular": "20.3.37",
"@angular-devkit/core": "20.3.37",
"@angular-devkit/schematics": "20.3.37",
"@angular-eslint/builder": "20.7.0",
"@angular-eslint/eslint-plugin": "20.7.0",
"@angular-eslint/eslint-plugin-template": "20.7.0",
"@angular-eslint/schematics": "20.7.0",
"@angular-eslint/template-parser": "20.7.0",
"@angular/cli": "20.3.37",
"@angular/compiler": "20.3.31",
"@angular/compiler-cli": "20.3.31",
"@angular/language-server": "20.3.0",
"@angular/language-service": "20.3.31",
"@angular/platform-browser-dynamic": "20.3.31",
"@capacitor/android": "8.2.0",
"@capacitor/assets": "3.0.5",
"@capacitor/cli": "8.2.0",
@@ -179,7 +179,7 @@
"stylelint-config-standard-scss": "17.0.0",
"surge": "0.23.1",
"ts-node": "10.9.2",
"typescript": "5.5.4"
"typescript": "5.9.3"
},
"cordova": {
"plugins": {},
+1 -6
View File
@@ -72,6 +72,7 @@ describe('AppComponent', () => {
configProvider.getAnyValue = jasmine.createSpy().and.callFake(function () {
return sampleAuthConfiguration;
});
inAppReviewProvider = jasmine.createSpyObj('InAppReviewProvider', ['init']);
ngxLogger = jasmine.createSpyObj('NGXLogger', ['log', 'error', 'warn']);
storageProvider = jasmine.createSpyObj('StorageProvider', ['init', 'get', 'has', 'put']);
simpleBrowser = jasmine.createSpyObj('SimpleBrowser', ['open']);
@@ -108,11 +109,5 @@ describe('AppComponent', () => {
it('should initialize the app', async () => {
TestBed.createComponent(AppComponent);
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 {
await this.authHelper.getProvider().getValidToken();
} catch {
const originNavigation = this.router.getCurrentNavigation();
const originNavigation = this.router.currentNavigation();
let extras: NavigationExtras = {};
if (originNavigation) {
const url = originNavigation.extractedUrl.toString();
@@ -95,7 +95,7 @@ export class DataDetailComponent implements OnInit {
readonly modalController: ModalController,
translateService: TranslateService,
) {
this.inputItem = router.getCurrentNavigation()?.extras.state?.item;
this.inputItem = router.currentNavigation()?.extras.state?.item;
if (!this.inputItem?.origin) {
// We received a ThingWithoutReferences.
// This can happen, for example, when detail views use `inPlace` list items
@@ -29,7 +29,6 @@ export class CompassControlComponent {
map(event => {
// const pitch = event.target.transform.pitch;
// const bearing = event.target.transform.bearing;
// return `rotateX(${pitch}deg) rotateZ(${bearing}deg)`;
}),
);
@@ -44,7 +44,7 @@ export class GeoNavigationDirective {
const address = this.geoNavigation.address
? this.translateService.instant(
'map.directions.ADDRESS',
this.thingTranslate.get(this.geoNavigation as SCThings, 'address'),
this.thingTranslate.get(this.geoNavigation as SCThings, 'address') as object,
)
: `${lat}, ${lon}`;
@@ -22,83 +22,89 @@
<ion-content>
<!-- Sort Context -->
<ion-list *ngIf="sortOption">
<ion-radio-group class="context-sort" [value]="0">
<ion-list-header>
<ion-icon name="sort"></ion-icon>
<ion-title>{{ 'menu.context.sort.title' | translate | titlecase }}</ion-title>
</ion-list-header>
<ion-item
class="sort-item"
*ngFor="let value of sortOption.values; let i = index"
(click)="sortChanged(sortOption, value)"
>
<ion-radio [value]="i">
{{ 'menu.context.sort.' + value.value | translate | titlecase }}
<span *ngIf="sortOption.value === value.value && value.reversible">
<ion-icon *ngIf="sortOption.reversed" name="arrow_downward"></ion-icon>
<ion-icon *ngIf="!sortOption.reversed" name="arrow_upward"></ion-icon>
</span>
</ion-radio>
</ion-item>
</ion-radio-group>
</ion-list>
@if (sortOption) {
<ion-list>
<ion-radio-group class="context-sort" [value]="0">
<ion-list-header>
<ion-icon name="sort"></ion-icon>
<ion-title>{{ 'menu.context.sort.title' | translate | titlecase }}</ion-title>
</ion-list-header>
@for (value of sortOption.values; track value; let i = $index) {
<ion-item class="sort-item" (click)="sortChanged(sortOption, value)">
<ion-radio [value]="i">
{{ 'menu.context.sort.' + value.value | translate | titlecase }}
@if (sortOption.value === value.value && value.reversible) {
<span>
@if (sortOption.reversed) {
<ion-icon name="arrow_downward"></ion-icon>
}
@if (!sortOption.reversed) {
<ion-icon name="arrow_upward"></ion-icon>
}
</span>
}
</ion-radio>
</ion-item>
}
</ion-radio-group>
</ion-list>
}
<!-- Filter Context -->
<form class="context-filter" *ngIf="filterOption">
<ion-list-header>
<ion-icon name="filter_list"></ion-icon>
<ion-title>{{ 'menu.context.filter.title' | translate | titlecase }}</ion-title>
<ion-button class="resetFilterButton" fill="clear" color="dark" (click)="resetFilter(filterOption)">
<ion-icon name="delete"></ion-icon>
</ion-button>
</ion-list-header>
<ion-list class="filter-group" *ngFor="let facet of facets">
<ion-list-header class="h3">
<ion-label>
<span *ngIf="facet.info.onlyOnType"
><b>{{ facet.info.onlyOnType | titlecase }}</b> /
</span>
{{ facet.info.field | titlecase }}
</ion-label>
@if (filterOption) {
<form class="context-filter">
<ion-list-header>
<ion-icon name="filter_list"></ion-icon>
<ion-title>{{ 'menu.context.filter.title' | translate | titlecase }}</ion-title>
<ion-button class="resetFilterButton" fill="clear" color="dark" (click)="resetFilter(filterOption)">
<ion-icon name="delete"></ion-icon>
</ion-button>
</ion-list-header>
<ng-container
*ngFor="
let bucket of !facet.compact ? facet.buckets.slice(0, compactFilterOptionCount) : facet.buckets
"
>
<ion-item>
<ion-checkbox
[(ngModel)]="bucket.checked"
(ngModelChange)="filterChanged()"
[name]="facet.onlyOnType + '-' + facet.field + '-' + bucket.key"
[value]="{
field: facet.field,
value: bucket.key,
onlyOnType: facet.onlyOnType
}"
class="filter-item-label"
>
({{ bucket.count }})
{{
facet.field === 'type'
? (getTranslatedPropertyValue($any(bucket.key), 'type') | titlecase)
: (facet.onlyOnType && getTranslatedPropertyValue(facet.onlyOnType, facet.field, bucket.key)
| titlecase)
}}
</ion-checkbox>
</ion-item>
</ng-container>
<ion-button
*ngIf="!facet.compact && facet.buckets.length > compactFilterOptionCount"
fill="clear"
(click)="facet.compact = true"
>
{{ 'menu.context.filter.showAll' | translate }}
</ion-button>
</ion-list>
</form>
@for (facet of facets; track facet) {
<ion-list class="filter-group">
<ion-list-header class="h3">
<ion-label>
@if (facet.info.onlyOnType) {
<span
><b>{{ facet.info.onlyOnType | titlecase }}</b> /
</span>
}
{{ facet.info.field | titlecase }}
</ion-label>
</ion-list-header>
@for (
bucket of !facet.compact ? facet.buckets.slice(0, compactFilterOptionCount) : facet.buckets;
track bucket
) {
<ion-item>
<ion-checkbox
[(ngModel)]="bucket.checked"
(ngModelChange)="filterChanged()"
[name]="facet.onlyOnType + '-' + facet.field + '-' + bucket.key"
[value]="{
field: facet.field,
value: bucket.key,
onlyOnType: facet.onlyOnType
}"
class="filter-item-label"
>
({{ bucket.count }})
{{
facet.field === 'type'
? (getTranslatedPropertyValue($any(bucket.key), 'type') | titlecase)
: (facet.onlyOnType &&
getTranslatedPropertyValue(facet.onlyOnType, facet.field, bucket.key) | titlecase)
}}
</ion-checkbox>
</ion-item>
}
@if (!facet.compact && facet.buckets.length > compactFilterOptionCount) {
<ion-button fill="clear" (click)="facet.compact = true">
{{ 'menu.context.filter.showAll' | translate }}
</ion-button>
}
</ion-list>
}
</form>
}
</ion-content>
@@ -35,7 +35,7 @@ export class RoutingStackService {
this.currentRoute = event.urlAfterRedirects;
this.lastDataDetail = this.currentDataDetail;
this.currentDataDetail = this.router.getCurrentNavigation()!.extras.state?.item;
this.currentDataDetail = this.router.currentNavigation()!.extras.state?.item;
}
});
}