chore: migrate to Angular 20 and Material 20

- Update Angular from 19.2.18 to 20.3.9
- Update Angular Material/CDK from 19.2.19 to 20.2.14
- Update TypeScript from 5.8.3 to 5.9.3
- Update @typescript-eslint from 6.21.0 to 8.18.2
- Update @angular-eslint from 19.8.1 to 20.0.0
- Update ng-packagr from 19.2.2 to 20.3.2
- Update @mat-datetimepicker/core from 15.0.2 to 16.0.1 (Angular 20 compatible)

Angular Migrations Applied:
- Convert templates to new control flow syntax (@if, @for, @switch)
- Migrate DOCUMENT imports from @angular/common to @angular/core
- Update Router.getCurrentNavigation() to currentNavigation signal
- Replace deprecated InjectFlags enum usage
- Replace TestBed.get with TestBed.inject

Breaking Changes Fixed:
- Remove deprecated Directionality.value setter (read-only in Angular 20)
- Update ESLint config: replace @typescript-eslint/no-var-requires with no-require-imports
- Remove @typescript-eslint/brace-style rule (deprecated in v8)

Configuration:
- Add .npmrc with legacy-peer-deps for CI/CD compatibility
- Update ESLint rules for @typescript-eslint v8 compatibility

BREAKING CHANGE: Requires Angular 20+ and @mat-datetimepicker/core@16.0.1

Note: Nx build system currently has plugin worker issues. TypeScript compilation
verified successfully. Full builds and tests pending Nx worker resolution.

See MIGRATION_SUMMARY.md for complete details.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Denys Vuika
2026-02-25 12:33:27 +00:00
co-authored by Cursor
parent 93d42b85a4
commit 711e5b4eac
399 changed files with 15570 additions and 16664 deletions
@@ -41,9 +41,12 @@ import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
`
],
template: `
<span [ngClass]="['activity-indicator', size]" *ngIf="isEnabled; else inActive">🟢</span>
<ng-template #inActive><span [ngClass]="['activity-indicator', size]">🔴</span></ng-template>
`,
@if (isEnabled) {
<span [ngClass]="['activity-indicator', size]">🟢</span>
} @else {
<span [ngClass]="['activity-indicator', size]">🔴</span>
}
`,
encapsulation: ViewEncapsulation.None,
changeDetection: ChangeDetectionStrategy.OnPush
})
@@ -13,20 +13,23 @@
</button>
</mat-toolbar>
<ng-container *ngIf="flags$ | async as flags">
@if (flags$ | async; as flags) {
<table mat-table [dataSource]="flags" class="adf-feature-flags-overrides-table mat-elevation-z0">
<ng-container matColumnDef="icon">
<th mat-header-cell class="adf-icon-col adf-header-cell" *matHeaderCellDef>
<mat-icon class="material-icons-outlined adf-search-icon" adf-icon="search" />
</th>
<td mat-cell class="adf-icon-col" *matCellDef="let element">
<button mat-icon-button *ngIf="element.fictive; else flagFromApi" class="adf-fictive-flag-button" (click)="onDelete(element.flag)">
<mat-icon class="material-icons-outlined adf-custom-flag-icon" adf-icon="memory" />
<mat-icon class="material-icons-outlined adf-trash-icon" adf-icon="delete" />
</button>
@if (element.fictive) {
<button mat-icon-button class="adf-fictive-flag-button" (click)="onDelete(element.flag)">
<mat-icon class="material-icons-outlined adf-custom-flag-icon" adf-icon="memory" />
<mat-icon class="material-icons-outlined adf-trash-icon" adf-icon="delete" />
</button>
} @else {
<mat-icon class="material-icons-outlined" adf-icon="cloud" />
}
</td>
</ng-container>
<ng-container matColumnDef="flag">
<th mat-header-cell class="flag-col header-cell" *matHeaderCellDef>
<mat-form-field class="adf-flag-form-field" appearance="fill" floatLabel="auto">
@@ -35,16 +38,19 @@
</th>
<td mat-cell class="flag-col" *matCellDef="let element">{{ element.flag }}</td>
</ng-container>
<ng-container matColumnDef="value">
<th mat-header-cell class="adf-val-col header-cell" *matHeaderCellDef>
<div class="adf-input-field-buttons-container">
<button *ngIf="showPlusButton$ | async" mat-icon-button title="{{'CORE.FEATURE-FLAGS.ADD_NEW' | translate}}" color="accent" (click)="onAddButtonClick()">
<mat-icon class="material-icons-outlined" adf-icon="add_circle" />
</button>
<button *ngIf="inputValue" matSuffix mat-icon-button aria-label="Clear" (click)="onClearInput()" class="adf-clear-button">
<mat-icon adf-icon="cancel" />
</button>
@if (showPlusButton$ | async) {
<button mat-icon-button title="{{'CORE.FEATURE-FLAGS.ADD_NEW' | translate}}" color="accent" (click)="onAddButtonClick()">
<mat-icon class="material-icons-outlined" adf-icon="add_circle" />
</button>
}
@if (inputValue) {
<button matSuffix mat-icon-button aria-label="Clear" (click)="onClearInput()" class="adf-clear-button">
<mat-icon adf-icon="cancel" />
</button>
}
</div>
</th>
<td mat-cell class="adf-val-col" *matCellDef="let element">
@@ -54,13 +60,9 @@
[disabled]="!isEnabled" />
</td>
</ng-container>
<tr mat-header-row *matHeaderRowDef="displayedColumns; sticky: true"></tr>
<tr mat-row *matRowDef="let row; columns: displayedColumns"></tr>
</table>
</ng-container>
}
<ng-template #flagFromApi>
<mat-icon class="material-icons-outlined" adf-icon="cloud" />
</ng-template>
@@ -15,7 +15,7 @@
* limitations under the License.
*/
import { inject, provideAppInitializer } from '@angular/core';
import { inject, provideAppInitializer, DOCUMENT } from '@angular/core';
import {
FlagsOverrideToken,
FeaturesServiceToken,
@@ -28,7 +28,7 @@ import {
import { StorageFeaturesService } from '../services/storage-features.service';
import { DebugFeaturesService } from '../services/debug-features.service';
import { QaFeaturesHelper } from '../services/qa-features.helper';
import { DOCUMENT } from '@angular/common';
/**
*