Upgrading to Angular 20:

Replaced checked in package-lock.json by regenerated one.
Ran ng update @angular/core@20 @angular/cli@20
Ran npm install @angular-builders/jest@^20.0.0 @fortawesome/angular-fontawesome@^3.0.0 @swimlane/ngx-graph@^11
Ran npm install ngx-mat-select-search@^8.0.2.
Ran ng update @angular/material@20.
Updated all eslint and typescript to the latest versions.
Removed @angular-devkit/schematics.
Updated fontawesome.
Updated rxjs and tslib.
Moved required node version from 16 to 20.
Updated jest-preset-angular.
Set preserveWhitespaces to false.
Corrected two type declarations in two typescript files to make ng serve run without errors.
Removed unused angular-devkit/schematics from view-user.component.ts .
Updated list of supported browsers.
Upgraded prettier.
Ran prettier . --write the first time.
Ran prettier . --write the second time.
Ran ng generate @angular/core:inject with defaults, excepted a handful of files.
Fixed remaining eslint problems.
Added dist directory to ignores in eslint.config.js.
Let prettier fix formatting, almost everything is just line breaks.
Made htmlhint ignore @if and @for Angular constructs.
Updated node version in Github workflow to 22.12.0 (build.yml).
Updated .env.ts.
Updated Angular datetime format strings from YYYY-MM-DD to yyyy-MM-dd.
Merged changes from dev into angular20 branch.
This commit is contained in:
Felix van Hove
2025-12-08 11:01:01 +01:00
parent f1b4ec2cf2
commit 7fd1486c08
1516 changed files with 39367 additions and 36037 deletions
@@ -66,164 +66,176 @@
</div>
<div class="mat-elevation-z8 container m-t-20">
<div *ngIf="isLoading" class="loader">
<div class="loading"></div>
</div>
<mat-accordion *ngIf="existsDataToFilter">
<mat-expansion-panel *ngFor="let record of searchResults; index as i" class="record">
<mat-expansion-panel-header>
<mat-panel-title>
<table>
<tr>
<td>
<div [ngClass]="itemStatus(record.status)" class="m-r-20">
<fa-icon icon="stop"></fa-icon>
<span class="m-l-10 status">{{ record.status }}</span>
</div>
</td>
<td class="field-name">{{ 'labels.inputs.Owner External Id' | translate }}</td>
<td>
<mifosx-external-identifier externalId="{{ record.owner.externalId }}"></mifosx-external-identifier>
</td>
<td class="field-name">{{ 'labels.inputs.Transfer External Id' | translate }}</td>
<td>
<mifosx-external-identifier
externalId="{{ record.transferExternalId }}"
></mifosx-external-identifier>
</td>
<td class="field-name">{{ 'labels.inputs.Effective From' | translate }}</td>
<td>{{ record.effectiveFrom | dateFormat }}</td>
</tr>
</table>
</mat-panel-title>
</mat-expansion-panel-header>
@if (isLoading) {
<div class="loader">
<div class="loading"></div>
</div>
}
@if (existsDataToFilter) {
<mat-accordion>
@for (record of searchResults; track record; let i = $index) {
<mat-expansion-panel class="record">
<mat-expansion-panel-header>
<mat-panel-title>
<table>
<tr>
<td>
<div [ngClass]="itemStatus(record.status)" class="m-r-20">
<fa-icon icon="stop"></fa-icon>
<span class="m-l-10 status">{{ record.status }}</span>
</div>
</td>
<td class="field-name">{{ 'labels.inputs.Owner External Id' | translate }}</td>
<td>
<mifosx-external-identifier
externalId="{{ record.owner.externalId }}"
></mifosx-external-identifier>
</td>
<td class="field-name">{{ 'labels.inputs.Transfer External Id' | translate }}</td>
<td>
<mifosx-external-identifier
externalId="{{ record.transferExternalId }}"
></mifosx-external-identifier>
</td>
<td class="field-name">{{ 'labels.inputs.Effective From' | translate }}</td>
<td>{{ record.effectiveFrom | dateFormat }}</td>
</tr>
</table>
</mat-panel-title>
</mat-expansion-panel-header>
<div class="external-asset-transfer">
<table>
<tbody>
<tr>
<td class="m-l-5 flex-25">
<b>{{ 'labels.inputs.Status' | translate }} :</b>
</td>
<td class="flex-25 m-l-5 left">
<div [ngClass]="itemStatus(record.status)">
<fa-icon icon="stop"></fa-icon>
<span class="m-l-5 status">{{ record.status }}</span>
</div>
</td>
<td class="m-l-5 flex-25">
<b>{{ 'labels.inputs.Owner External Id' | translate }} :</b>
</td>
<td class="flex-25 m-l-5 left">
<mifosx-external-identifier
externalId="{{ record.owner.externalId }}"
completed="true"
></mifosx-external-identifier>
</td>
</tr>
<tr>
<td class="m-l-5 flex-25">
<b>{{ 'labels.inputs.Settlement Date' | translate }} :</b>
</td>
<td class="m-l-5 flex-25">
{{ record.settlementDate | dateFormat }}
</td>
<td class="m-l-5 flex-25">
<b>{{ 'labels.inputs.Effective Date' | translate }} :</b>
</td>
<td class="m-l-5 flex-25">
{{ record.effectiveFrom | dateFormat }}
</td>
</tr>
@if (record.details) {
<tr>
<td class="m-l-5 flex-25">
<b>{{ 'labels.inputs.Details' | translate }} :</b>
</td>
<td class="flex-75 left">
<table>
<tbody>
<tr>
<td class="flex-50 m-l-5">
<b>{{ 'labels.inputs.Principal Outstanding' | translate }} :</b>
</td>
<td class="flex-50 r-amount">
{{ record.details.totalPrincipalOutstanding | formatNumber }}
</td>
</tr>
<tr>
<td class="flex-50 m-l-5">
<b>{{ 'labels.inputs.Interest Outstanding' | translate }} :</b>
</td>
<td class="flex-50 r-amount">
{{ record.details.totalInterestOutstanding | formatNumber }}
</td>
</tr>
<tr>
<td class="flex-50 m-l-5">
<b>{{ 'labels.inputs.Fees Outstanding' | translate }} :</b>
</td>
<td class="flex-50 r-amount">
{{ record.details.totalFeeChargesOutstanding | formatNumber }}
</td>
</tr>
<tr>
<td class="flex-50 m-l-5">
<b>{{ 'labels.inputs.Penalties Outstanding' | translate }} :</b>
</td>
<td class="flex-50 r-amount">
{{ record.details.totalPenaltyChargesOutstanding | formatNumber }}
</td>
</tr>
<tr>
<td class="flex-50 m-l-5">
<b>{{ 'labels.inputs.Outstanding' | translate }} :</b>
</td>
<td class="flex-50 r-amount">{{ record.details.totalOutstanding | formatNumber }}</td>
</tr>
<tr>
<td class="flex-50 m-l-5">
<b>{{ 'labels.inputs.Overpaid' | translate }} :</b>
</td>
<td class="flex-50 r-amount">{{ record.details.totalOverpaid | formatNumber }}</td>
</tr>
</tbody>
</table>
</td>
</tr>
}
</tbody>
</table>
</div>
<mat-divider [inset]="true"></mat-divider>
@if (canBeCancelled(record)) {
<div class="record-actions layout-row align-flex-end">
<button
mat-button
color="warn"
(click)="cancelPendingSale(record)"
matTooltip="{{ 'labels.text.Cancel Pending Sale' | translate }}"
>
<fa-icon icon="trash"></fa-icon>
</button>
</div>
}
</mat-expansion-panel>
}
</mat-accordion>
}
<div class="external-asset-transfer">
<table>
<tbody>
<tr>
<td class="m-l-5 flex-25">
<b>{{ 'labels.inputs.Status' | translate }} :</b>
</td>
<td class="flex-25 m-l-5 left">
<div [ngClass]="itemStatus(record.status)">
<fa-icon icon="stop"></fa-icon>
<span class="m-l-5 status">{{ record.status }}</span>
</div>
</td>
<td class="m-l-5 flex-25">
<b>{{ 'labels.inputs.Owner External Id' | translate }} :</b>
</td>
<td class="flex-25 m-l-5 left">
<mifosx-external-identifier
externalId="{{ record.owner.externalId }}"
completed="true"
></mifosx-external-identifier>
</td>
</tr>
<tr>
<td class="m-l-5 flex-25">
<b>{{ 'labels.inputs.Settlement Date' | translate }} :</b>
</td>
<td class="m-l-5 flex-25">
{{ record.settlementDate | dateFormat }}
</td>
<td class="m-l-5 flex-25">
<b>{{ 'labels.inputs.Effective Date' | translate }} :</b>
</td>
<td class="m-l-5 flex-25">
{{ record.effectiveFrom | dateFormat }}
</td>
</tr>
<tr *ngIf="record.details">
<td class="m-l-5 flex-25">
<b>{{ 'labels.inputs.Details' | translate }} :</b>
</td>
<td class="flex-75 left">
<table>
<tbody>
<tr>
<td class="flex-50 m-l-5">
<b>{{ 'labels.inputs.Principal Outstanding' | translate }} :</b>
</td>
<td class="flex-50 r-amount">
{{ record.details.totalPrincipalOutstanding | formatNumber }}
</td>
</tr>
<tr>
<td class="flex-50 m-l-5">
<b>{{ 'labels.inputs.Interest Outstanding' | translate }} :</b>
</td>
<td class="flex-50 r-amount">
{{ record.details.totalInterestOutstanding | formatNumber }}
</td>
</tr>
<tr>
<td class="flex-50 m-l-5">
<b>{{ 'labels.inputs.Fees Outstanding' | translate }} :</b>
</td>
<td class="flex-50 r-amount">
{{ record.details.totalFeeChargesOutstanding | formatNumber }}
</td>
</tr>
<tr>
<td class="flex-50 m-l-5">
<b>{{ 'labels.inputs.Penalties Outstanding' | translate }} :</b>
</td>
<td class="flex-50 r-amount">
{{ record.details.totalPenaltyChargesOutstanding | formatNumber }}
</td>
</tr>
<tr>
<td class="flex-50 m-l-5">
<b>{{ 'labels.inputs.Outstanding' | translate }} :</b>
</td>
<td class="flex-50 r-amount">{{ record.details.totalOutstanding | formatNumber }}</td>
</tr>
<tr>
<td class="flex-50 m-l-5">
<b>{{ 'labels.inputs.Overpaid' | translate }} :</b>
</td>
<td class="flex-50 r-amount">{{ record.details.totalOverpaid | formatNumber }}</td>
</tr>
</tbody>
</table>
</td>
</tr>
</tbody>
</table>
</div>
<mat-divider [inset]="true"></mat-divider>
<div class="record-actions layout-row align-flex-end" *ngIf="canBeCancelled(record)">
<button
mat-button
color="warn"
(click)="cancelPendingSale(record)"
matTooltip="{{ 'labels.text.Cancel Pending Sale' | translate }}"
>
<fa-icon icon="trash"></fa-icon>
</button>
</div>
</mat-expansion-panel>
</mat-accordion>
<mat-paginator
[pageSize]="pageSize"
[pageSizeOptions]="[50, 100, 200]"
[length]="totalRows"
(page)="pageChanged($event)"
showFirstLastButtons
*ngIf="existsDataToFilter"
></mat-paginator>
@if (existsDataToFilter) {
<mat-paginator
[pageSize]="pageSize"
[pageSizeOptions]="[50, 100, 200]"
[length]="totalRows"
(page)="pageChanged($event)"
showFirstLastButtons
></mat-paginator>
}
</div>
<div class="alert" *ngIf="!existsDataToFilter">
<div class="message">
<i class="fa fa-exclamation-circle alert-check"></i>
{{ 'labels.text.No data found' | translate }}
@if (!existsDataToFilter) {
<div class="alert">
<div class="message">
<i class="fa fa-exclamation-circle alert-check"></i>
{{ 'labels.text.No data found' | translate }}
</div>
</div>
</div>
}
</mat-card-content>
</mat-card>
@@ -1,5 +1,5 @@
import { animate, state, style, transition, trigger } from '@angular/animations';
import { Component, OnInit, ViewChild } from '@angular/core';
import { Component, OnInit, ViewChild, inject } from '@angular/core';
import { UntypedFormControl, ReactiveFormsModule } from '@angular/forms';
import { MatDialog } from '@angular/material/dialog';
import { MatPaginator, PageEvent } from '@angular/material/paginator';
@@ -12,7 +12,7 @@ import { ExternalAssetOwnerService } from 'app/loans/services/external-asset-own
import { SettingsService } from 'app/settings/settings.service';
import { CancelDialogComponent } from 'app/shared/cancel-dialog/cancel-dialog.component';
import { FaIconComponent } from '@fortawesome/angular-fontawesome';
import { NgIf, NgFor, NgClass } from '@angular/common';
import { NgClass } from '@angular/common';
import {
MatAccordion,
MatExpansionPanel,
@@ -34,8 +34,8 @@ import { STANDALONE_SHARED_IMPORTS } from 'app/standalone-shared.module';
trigger('detailExpand', [
state('collapsed', style({ height: '0px', minHeight: '0' })),
state('expanded', style({ height: '*' })),
transition('expanded <=> collapsed', animate('225ms cubic-bezier(0.4, 0.0, 0.2, 1)'))])
transition('expanded <=> collapsed', animate('225ms cubic-bezier(0.4, 0.0, 0.2, 1)'))
])
],
imports: [
...STANDALONE_SHARED_IMPORTS,
@@ -54,6 +54,13 @@ import { STANDALONE_SHARED_IMPORTS } from 'app/standalone-shared.module';
]
})
export class InvestorsComponent implements OnInit {
private settingsService = inject(SettingsService);
private router = inject(Router);
private dialog = inject(MatDialog);
private externalAssetOwner = inject(ExternalAssetOwner);
private externalAssetOwnerService = inject(ExternalAssetOwnerService);
private dateUtils = inject(Dates);
/** Minimum transaction date allowed. */
minDate = new Date(2000, 0, 1);
/** Maximum transaction date allowed. */
@@ -113,14 +120,6 @@ export class InvestorsComponent implements OnInit {
'totalAmount',
'actions'
];
constructor(
private settingsService: SettingsService,
private router: Router,
private dialog: MatDialog,
private externalAssetOwner: ExternalAssetOwner,
private externalAssetOwnerService: ExternalAssetOwnerService,
private dateUtils: Dates
) {}
ngOnInit(): void {
this.maxDate = this.settingsService.maxAllowedDate;