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
@@ -6,10 +6,12 @@
}}</span>
</h2>
</div>
<button mat-raised-button class="activate" (click)="runCatchUp()" *ngIf="!isCatchUpRunning">
<fa-icon icon="times-circle" class="m-r-10"></fa-icon>
{{ 'labels.buttons.Run Catch-Up' | translate }}
</button>
@if (!isCatchUpRunning) {
<button mat-raised-button class="activate" (click)="runCatchUp()">
<fa-icon icon="times-circle" class="m-r-10"></fa-icon>
{{ 'labels.buttons.Run Catch-Up' | translate }}
</button>
}
</div>
<div class="container space-top">
@@ -1,4 +1,4 @@
import { Component, Input, OnDestroy, OnInit } from '@angular/core';
import { Component, Input, OnDestroy, OnInit, inject } from '@angular/core';
import { SystemService } from 'app/system/system.service';
import { environment } from '../../../../environments/environment';
import { FaIconComponent } from '@fortawesome/angular-fontawesome';
@@ -16,6 +16,8 @@ import { STANDALONE_SHARED_IMPORTS } from 'app/standalone-shared.module';
]
})
export class CobWorkflowComponent implements OnInit, OnDestroy {
private systemService = inject(SystemService);
/** Wait time between API status calls 30 seg */
waitTime = environment.waitTimeForCOBCatchUp || 30;
/** Process running flag */
@@ -23,8 +25,6 @@ export class CobWorkflowComponent implements OnInit, OnDestroy {
/** Timer to refetch COB Catch-Up status every 5 seconds */
timer: any;
constructor(private systemService: SystemService) {}
ngOnInit(): void {
this.getCOBCatchUpStatus();
}
@@ -1,100 +1,103 @@
<div class="tab-container mat-typography" *ngIf="loans && loans.length > 0">
<div class="layout-row align-start-center">
<div class="search-box flex-40">
<mat-form-field class="flex-90">
<input matInput placeholder="Filter by loan Id or error" (keyup)="applyFilter($event.target.value)" />
</mat-form-field>
@if (loans && loans.length > 0) {
<div class="tab-container mat-typography">
<div class="layout-row align-start-center">
<div class="search-box flex-40">
<mat-form-field class="flex-90">
<input matInput placeholder="Filter by loan Id or error" (keyup)="applyFilter($event.target.value)" />
</mat-form-field>
</div>
@if (allowRunInlineJob) {
<div class="flex-60">
<button
mat-raised-button
color="success"
*mifosxHasPermission="'EXECUTE_INLINE_JOB'"
(click)="runInlineCOB()"
>
<fa-icon icon="play" class="m-r-10"></fa-icon>{{ 'Start inline COB' | translate }}
</button>
</div>
}
</div>
<div class="flex-60" *ngIf="allowRunInlineJob">
<button mat-raised-button color="success" *mifosxHasPermission="'EXECUTE_INLINE_JOB'" (click)="runInlineCOB()">
<fa-icon icon="play" class="m-r-10"></fa-icon>{{ 'Start inline COB' | translate }}
</button>
<table mat-table [dataSource]="dataSource">
<ng-container matColumnDef="select">
<th mat-header-cell *matHeaderCellDef>
<mat-checkbox
(change)="$event ? masterToggle() : null"
[checked]="selection.hasValue() && isAllSelected()"
[indeterminate]="selection.hasValue() && !isAllSelected()"
[aria-label]="checkboxLabel()"
>
</mat-checkbox>
</th>
<td mat-cell *matCellDef="let row">
<mat-checkbox
(click)="$event.stopPropagation()"
(change)="$event ? selection.toggle(row) : null"
[checked]="selection.isSelected(row)"
[aria-label]="checkboxLabel(row)"
>
</mat-checkbox>
</td>
</ng-container>
<ng-container matColumnDef="loanId">
<th mat-header-cell *matHeaderCellDef>{{ 'labels.inputs.Loan Id' | translate }}</th>
<td mat-cell *matCellDef="let loan" class="view-details">{{ loan.loanId }}</td>
</ng-container>
<ng-container matColumnDef="lockPlacedOn">
<th mat-header-cell *matHeaderCellDef>{{ 'labels.inputs.Lock Placed On' | translate }}</th>
<td mat-cell *matCellDef="let loan" class="view-details">{{ loan.lockPlacedOn | datetimeFormat }}</td>
</ng-container>
<ng-container matColumnDef="lockOwner">
<th mat-header-cell *matHeaderCellDef>{{ 'labels.inputs.Lock Owner' | translate }}</th>
<td mat-cell *matCellDef="let loan" class="view-details">{{ loan.lockOwner }}</td>
</ng-container>
<ng-container matColumnDef="error">
<th mat-header-cell *matHeaderCellDef>{{ 'labels.inputs.Error' | translate }}</th>
<td mat-cell *matCellDef="let loan" class="view-details">{{ loan.error }}</td>
</ng-container>
<ng-container matColumnDef="details">
<th mat-header-cell *matHeaderCellDef>{{ 'labels.heading.Details' | translate }}</th>
<td mat-cell *matCellDef="let loan" class="view-details">
<button
mat-icon-button
class="error-log"
matTooltip="{{ 'tooltips.Error details' | translate }}"
(click)="showDetails(loan)"
matTooltipPosition="left"
>
<fa-icon icon="exclamation-circle" size="lg"></fa-icon>
</button>
<button
mat-icon-button
matTooltip="{{ 'tooltips.View Loan Account' | translate }}"
(click)="viewLoanAccount(loan)"
matTooltipPosition="right"
>
<fa-icon icon="eye" size="lg"></fa-icon>
</button>
</td>
</ng-container>
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
<tr mat-row *matRowDef="let row; columns: displayedColumns" (click)="selection.toggle(row)"></tr>
</table>
<mat-paginator
[hidden]="!showPaginator"
[pageSizeOptions]="[100, 500, 1000, 5000]"
[pageSize]="pageSize"
[pageIndex]="currentPage"
showFirstLastButtons
(page)="changePaging($event)"
>
</mat-paginator>
</div>
}
@if (loans && loans.length === 0) {
<div class="alert">
<div class="message">
<i class="fa fa-exclamation-circle alert-check"></i>
{{ 'labels.text.No loan locked available' | translate }}.
</div>
</div>
<table mat-table [dataSource]="dataSource">
<ng-container matColumnDef="select">
<th mat-header-cell *matHeaderCellDef>
<mat-checkbox
(change)="$event ? masterToggle() : null"
[checked]="selection.hasValue() && isAllSelected()"
[indeterminate]="selection.hasValue() && !isAllSelected()"
[aria-label]="checkboxLabel()"
>
</mat-checkbox>
</th>
<td mat-cell *matCellDef="let row">
<mat-checkbox
(click)="$event.stopPropagation()"
(change)="$event ? selection.toggle(row) : null"
[checked]="selection.isSelected(row)"
[aria-label]="checkboxLabel(row)"
>
</mat-checkbox>
</td>
</ng-container>
<ng-container matColumnDef="loanId">
<th mat-header-cell *matHeaderCellDef>{{ 'labels.inputs.Loan Id' | translate }}</th>
<td mat-cell *matCellDef="let loan" class="view-details">{{ loan.loanId }}</td>
</ng-container>
<ng-container matColumnDef="lockPlacedOn">
<th mat-header-cell *matHeaderCellDef>{{ 'labels.inputs.Lock Placed On' | translate }}</th>
<td mat-cell *matCellDef="let loan" class="view-details">{{ loan.lockPlacedOn | datetimeFormat }}</td>
</ng-container>
<ng-container matColumnDef="lockOwner">
<th mat-header-cell *matHeaderCellDef>{{ 'labels.inputs.Lock Owner' | translate }}</th>
<td mat-cell *matCellDef="let loan" class="view-details">{{ loan.lockOwner }}</td>
</ng-container>
<ng-container matColumnDef="error">
<th mat-header-cell *matHeaderCellDef>{{ 'labels.inputs.Error' | translate }}</th>
<td mat-cell *matCellDef="let loan" class="view-details">{{ loan.error }}</td>
</ng-container>
<ng-container matColumnDef="details">
<th mat-header-cell *matHeaderCellDef>{{ 'labels.heading.Details' | translate }}</th>
<td mat-cell *matCellDef="let loan" class="view-details">
<button
mat-icon-button
class="error-log"
matTooltip="{{ 'tooltips.Error details' | translate }}"
(click)="showDetails(loan)"
matTooltipPosition="left"
>
<fa-icon icon="exclamation-circle" size="lg"></fa-icon>
</button>
<button
mat-icon-button
matTooltip="{{ 'tooltips.View Loan Account' | translate }}"
(click)="viewLoanAccount(loan)"
matTooltipPosition="right"
>
<fa-icon icon="eye" size="lg"></fa-icon>
</button>
</td>
</ng-container>
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
<tr mat-row *matRowDef="let row; columns: displayedColumns" (click)="selection.toggle(row)"></tr>
</table>
<mat-paginator
[hidden]="!showPaginator"
[pageSizeOptions]="[100, 500, 1000, 5000]"
[pageSize]="pageSize"
[pageIndex]="currentPage"
showFirstLastButtons
(page)="changePaging($event)"
>
</mat-paginator>
</div>
<div class="alert" *ngIf="loans && loans.length === 0">
<div class="message">
<i class="fa fa-exclamation-circle alert-check"></i>
{{ 'labels.text.No loan locked available' | translate }}.
</div>
</div>
}
@@ -1,5 +1,5 @@
import { SelectionModel } from '@angular/cdk/collections';
import { Component, OnInit, ViewChild } from '@angular/core';
import { Component, OnInit, ViewChild, inject } from '@angular/core';
import { MatDialog } from '@angular/material/dialog';
import { MatPaginator } from '@angular/material/paginator';
import {
@@ -53,6 +53,14 @@ import { STANDALONE_SHARED_IMPORTS } from 'app/standalone-shared.module';
]
})
export class LoanLockedComponent implements OnInit {
private route = inject(ActivatedRoute);
private router = inject(Router);
private loansService = inject(LoansService);
private systemService = inject(SystemService);
private tasksService = inject(TasksService);
private dialog = inject(MatDialog);
private translateService = inject(TranslateService);
/** Loans Data */
loans: any[] = [];
/** Batch Requests */
@@ -89,22 +97,6 @@ export class LoanLockedComponent implements OnInit {
showPaginator = false;
/**
* @param {LoansService} loansService Loans Service
* @param {Router} router Router for navigation.
* @param {MatDialog} dialog Dialog reference.
* @param {TranslateService} translateService Translate Service.
*/
constructor(
private route: ActivatedRoute,
private router: Router,
private loansService: LoansService,
private systemService: SystemService,
private tasksService: TasksService,
private dialog: MatDialog,
private translateService: TranslateService
) {}
ngOnInit(): void {
this.allowRunInlineJob = false;
this.getLoansLocked(0);
@@ -10,6 +10,7 @@ export class LoanLockedResolver {
/**
* @param {TasksService} tasksService Tasks service.
*/
// eslint-disable-next-line @angular-eslint/prefer-inject
constructor(private tasksService: TasksService) {}
/**
@@ -1,4 +1,4 @@
import { Component } from '@angular/core';
import { Component, inject } from '@angular/core';
import { MatTabChangeEvent, MatTabGroup, MatTab } from '@angular/material/tabs';
import { SystemService } from '../system.service';
import { TranslateService } from '@ngx-translate/core';
@@ -21,14 +21,12 @@ import { STANDALONE_SHARED_IMPORTS } from 'app/standalone-shared.module';
]
})
export class ManageJobsComponent {
private systemService = inject(SystemService);
private translateService = inject(TranslateService);
/** Process running flag */
isCatchUpRunning = true;
constructor(
private systemService: SystemService,
private translateService: TranslateService
) {}
onJobTabChange(event: MatTabChangeEvent) {
if (event.index === 2) {
this.systemService.getCOBCatchUpStatus().subscribe((response: any) => {
@@ -2,22 +2,26 @@
<mat-dialog-content>
<div class="jobs-container">
<div *ngFor="let job of selectedJobs">
<mifosx-custom-parameters-table
[displayName]="job.displayName"
[jobId]="job.jobId"
[jobParameters]="job.jobParameters"
(retrieveData)="runSelectedJobs($event)"
>
</mifosx-custom-parameters-table>
</div>
@for (job of selectedJobs; track job) {
<div>
<mifosx-custom-parameters-table
[displayName]="job.displayName"
[jobId]="job.jobId"
[jobParameters]="job.jobParameters"
(retrieveData)="runSelectedJobs($event)"
>
</mifosx-custom-parameters-table>
</div>
}
</div>
</mat-dialog-content>
<mat-list>
<mat-list-item *ngFor="let message of messages" class="message" [ngClass]="{ green: message.status }">
{{ message.message }}
</mat-list-item>
@for (message of messages; track message) {
<mat-list-item class="message" [ngClass]="{ green: message.status }">
{{ message.message }}
</mat-list-item>
}
</mat-list>
<mat-dialog-actions>
@@ -1,5 +1,5 @@
import { SelectionModel } from '@angular/cdk/collections';
import { Component, Inject, OnInit, QueryList, ViewChildren } from '@angular/core';
import { Component, OnInit, QueryList, ViewChildren, inject } from '@angular/core';
import {
MAT_DIALOG_DATA,
MatDialogTitle,
@@ -71,6 +71,9 @@ interface JobDataType {
]
})
export class CustomParametersPopoverComponent implements OnInit {
private systemService = inject(SystemService);
data = inject<SelectedJobsDataType>(MAT_DIALOG_DATA);
/* Job table childer */
@ViewChildren(CustomParametersTableComponent) tableComponents: QueryList<CustomParametersTableComponent>;
@@ -81,11 +84,6 @@ export class CustomParametersPopoverComponent implements OnInit {
/* API call response message */
messages: { message: string; status: number }[] = [];
constructor(
private systemService: SystemService,
@Inject(MAT_DIALOG_DATA) public data: SelectedJobsDataType
) {}
ngOnInit(): void {
this.selectedJobs = this.data.selectedJobs.selected.map((jobJSON) => ({
...jobJSON,
@@ -6,19 +6,23 @@
<mat-form-field>
<mat-label>{{ 'labels.inputs.Job Name' | translate }}</mat-label>
<input matInput required formControlName="displayName" />
<mat-error *ngIf="jobForm.controls.displayName.hasError('required')">
{{ 'labels.inputs.Job Name' | translate }} {{ 'labels.commons.is' | translate }}
<strong>{{ 'labels.commons.required' | translate }}</strong>
</mat-error>
@if (jobForm.controls.displayName.hasError('required')) {
<mat-error>
{{ 'labels.inputs.Job Name' | translate }} {{ 'labels.commons.is' | translate }}
<strong>{{ 'labels.commons.required' | translate }}</strong>
</mat-error>
}
</mat-form-field>
<mat-form-field>
<mat-label>{{ 'labels.inputs.Cron Expression' | translate }}</mat-label>
<input matInput required formControlName="cronExpression" />
<mat-error *ngIf="jobForm.controls.cronExpression.hasError('required')">
{{ 'labels.inputs.Cron Expression' | translate }} {{ 'labels.commons.is' | translate }}
<strong>{{ 'labels.commons.required' | translate }}</strong>
</mat-error>
@if (jobForm.controls.cronExpression.hasError('required')) {
<mat-error>
{{ 'labels.inputs.Cron Expression' | translate }} {{ 'labels.commons.is' | translate }}
<strong>{{ 'labels.commons.required' | translate }}</strong>
</mat-error>
}
</mat-form-field>
<mat-checkbox labelPosition="before" formControlName="active">
@@ -1,5 +1,5 @@
/** Angular Imports */
import { Component, OnInit } from '@angular/core';
import { Component, OnInit, inject } from '@angular/core';
import { ActivatedRoute, Router, RouterLink } from '@angular/router';
import { UntypedFormBuilder, Validators, ReactiveFormsModule } from '@angular/forms';
@@ -21,6 +21,11 @@ import { STANDALONE_SHARED_IMPORTS } from 'app/standalone-shared.module';
]
})
export class EditSchedulerJobComponent implements OnInit {
private route = inject(ActivatedRoute);
private systemService = inject(SystemService);
private router = inject(Router);
private formBuilder = inject(UntypedFormBuilder);
/** Job Data. */
jobData: any;
/** Job Form. */
@@ -33,12 +38,7 @@ export class EditSchedulerJobComponent implements OnInit {
* @param {Router} router Router for navigation.
* @param {ActivatedRoute} route Activated Route.
*/
constructor(
private route: ActivatedRoute,
private systemService: SystemService,
private router: Router,
private formBuilder: UntypedFormBuilder
) {
constructor() {
this.route.data.subscribe((data: { jobSelected: any }) => {
this.jobData = data.jobSelected;
});
@@ -15,9 +15,11 @@
<div #content class="note-field" [class.show]="show" [class.note-text]="content.scrollHeight > 18">
<span>{{ job.lastRunHistory.jobRunErrorLog }}</span>
</div>
<button mat-flat-button *ngIf="content.scrollHeight > 18" class="show-button" (click)="show = !show">
{{ buttonLabel() }}
</button>
@if (content.scrollHeight > 18) {
<button mat-flat-button class="show-button" (click)="show = !show">
{{ buttonLabel() }}
</button>
}
</td>
</tr>
</tbody>
@@ -1,4 +1,4 @@
import { Component, Inject, OnInit } from '@angular/core';
import { Component, OnInit, inject } from '@angular/core';
import {
MAT_DIALOG_DATA,
MatDialogTitle,
@@ -31,16 +31,14 @@ interface ErrorJobDataType {
]
})
export class ErrorLogPopoverComponent implements OnInit {
data = inject<ErrorJobDataType>(MAT_DIALOG_DATA);
private translateService = inject(TranslateService);
show = false;
/* Initialize Selected Job */
job: SchedulerJob;
constructor(
@Inject(MAT_DIALOG_DATA) public data: ErrorJobDataType,
private translateService: TranslateService
) {}
ngOnInit(): void {
this.job = this.data.job;
}
@@ -1,5 +1,5 @@
/** Angular Imports */
import { Injectable } from '@angular/core';
import { Injectable, inject } from '@angular/core';
import { ActivatedRouteSnapshot } from '@angular/router';
/** rxjs Imports */
@@ -13,10 +13,7 @@ import { SystemService } from '../../system.service';
*/
@Injectable()
export class ManageSchedulerJobResolver {
/**
* @param {SystemService} systemService System service.
*/
constructor(private systemService: SystemService) {}
private systemService = inject(SystemService);
/**
* Returns the edit scheduler jobs data.
@@ -6,14 +6,18 @@
}}</span>
</h2>
</div>
<button mat-raised-button class="suspend" (click)="suspendScheduler()" *ngIf="schedulerActive">
<fa-icon icon="times-circle" class="m-r-10"></fa-icon>
{{ 'labels.buttons.Suspend' | translate }}
</button>
<button mat-raised-button class="activate" (click)="activateScheduler()" *ngIf="!schedulerActive">
<fa-icon icon="times-circle" class="m-r-10"></fa-icon>
{{ 'labels.buttons.Activate' | translate }}
</button>
@if (schedulerActive) {
<button mat-raised-button class="suspend" (click)="suspendScheduler()">
<fa-icon icon="times-circle" class="m-r-10"></fa-icon>
{{ 'labels.buttons.Suspend' | translate }}
</button>
}
@if (!schedulerActive) {
<button mat-raised-button class="activate" (click)="activateScheduler()">
<fa-icon icon="times-circle" class="m-r-10"></fa-icon>
{{ 'labels.buttons.Activate' | translate }}
</button>
}
</div>
<div class="container">
@@ -52,14 +56,15 @@
</mat-checkbox>
</th>
<td mat-cell *matCellDef="let row">
<mat-checkbox
class="m-r-10"
*ngIf="!row.currentlyRunning"
(click)="$event.stopPropagation()"
(change)="$event ? selection.toggle(row) : null"
[checked]="selection.isSelected(row)"
>
</mat-checkbox>
@if (!row.currentlyRunning) {
<mat-checkbox
class="m-r-10"
(click)="$event.stopPropagation()"
(change)="$event ? selection.toggle(row) : null"
[checked]="selection.isSelected(row)"
>
</mat-checkbox>
}
</td>
</ng-container>
@@ -85,27 +90,31 @@
<ng-container matColumnDef="previousRunTime">
<th mat-header-cell *matHeaderCellDef mat-sort-header>{{ 'labels.inputs.Previous Run' | translate }}</th>
<td mat-cell *matCellDef="let job">
<div *ngIf="job.lastRunHistory">
<fa-icon
*ngIf="job.lastRunHistory.status === 'success'"
class="success"
[matTooltip]="'tooltips.Successful' | translate"
matTooltipPosition="right"
icon="check-circle"
size="lg"
></fa-icon>
<fa-icon
*ngIf="!(job.lastRunHistory.status === 'success')"
class="fail"
[matTooltip]="'tooltips.Failed' | translate"
matTooltipPosition="right"
icon="times-circle"
size="lg"
></fa-icon>
<span *ngIf="job.lastRunHistory" class="m-l-5">
{{ job.lastRunHistory.jobRunStartTime | datetimeFormat }}</span
>
</div>
@if (job.lastRunHistory) {
<div>
@if (job.lastRunHistory.status === 'success') {
<fa-icon
class="success"
[matTooltip]="'tooltips.Successful' | translate"
matTooltipPosition="right"
icon="check-circle"
size="lg"
></fa-icon>
}
@if (!(job.lastRunHistory.status === 'success')) {
<fa-icon
class="fail"
[matTooltip]="'tooltips.Failed' | translate"
matTooltipPosition="right"
icon="times-circle"
size="lg"
></fa-icon>
}
@if (job.lastRunHistory) {
<span class="m-l-5"> {{ job.lastRunHistory.jobRunStartTime | datetimeFormat }}</span>
}
</div>
}
</td>
</ng-container>
@@ -131,16 +140,17 @@
<ng-container matColumnDef="errorLog">
<th mat-header-cell *matHeaderCellDef mat-sort-header>{{ 'labels.inputs.Error Log' | translate }}</th>
<td mat-cell *matCellDef="let job" class="center">
<button
mat-icon-button
class="errorlog"
(click)="showErrorLog(job)"
*ngIf="jobWithError(job)"
matTooltip="{{ 'labels.inputs.Error Log' | translate }}"
matTooltipPosition="right"
>
<fa-icon icon="exclamation-circle" size="lg"></fa-icon>
</button>
@if (jobWithError(job)) {
<button
mat-icon-button
class="errorlog"
(click)="showErrorLog(job)"
matTooltip="{{ 'labels.inputs.Error Log' | translate }}"
matTooltipPosition="right"
>
<fa-icon icon="exclamation-circle" size="lg"></fa-icon>
</button>
}
</td>
</ng-container>
@@ -1,5 +1,5 @@
/** Angular Imports */
import { Component, OnInit, TemplateRef, ElementRef, ViewChild, AfterViewInit } from '@angular/core';
import { Component, OnInit, TemplateRef, ElementRef, ViewChild, AfterViewInit, inject } from '@angular/core';
import { MatPaginator } from '@angular/material/paginator';
import { MatSort, MatSortHeader } from '@angular/material/sort';
import {
@@ -32,7 +32,7 @@ import { CustomParametersPopoverComponent } from './custom-parameters-popover/cu
import { SchedulerJob } from './models/scheduler-job.model';
import { ErrorLogPopoverComponent } from './error-log-popover/error-log-popover.component';
import { RunSelectedJobsPopoverComponent } from './run-selected-jobs-popover/run-selected-jobs-popover.component';
import { NgIf, NgClass } from '@angular/common';
import { NgClass } from '@angular/common';
import { MatButton, MatIconButton } from '@angular/material/button';
import { FaIconComponent } from '@fortawesome/angular-fontawesome';
import { MatCheckbox } from '@angular/material/checkbox';
@@ -73,6 +73,13 @@ import { STANDALONE_SHARED_IMPORTS } from 'app/standalone-shared.module';
]
})
export class ManageSchedulerJobsComponent implements OnInit, AfterViewInit {
private route = inject(ActivatedRoute);
private systemService = inject(SystemService);
private router = inject(Router);
private dialog = inject(MatDialog);
private configurationWizardService = inject(ConfigurationWizardService);
private popoverService = inject(PopoverService);
/** Jobs data. */
jobData: any;
/** Scheduler data */
@@ -118,14 +125,7 @@ export class ManageSchedulerJobsComponent implements OnInit, AfterViewInit {
* @param {ConfigurationWizardService} configurationWizardService ConfigurationWizard Service.
* @param {PopoverService} popoverService PopoverService.
*/
constructor(
private route: ActivatedRoute,
private systemService: SystemService,
private router: Router,
private dialog: MatDialog,
private configurationWizardService: ConfigurationWizardService,
private popoverService: PopoverService
) {
constructor() {
this.route.data.subscribe((data: { jobsScheduler: any }) => {
if (data.jobsScheduler) {
this.jobData = data.jobsScheduler[0];
@@ -6,7 +6,7 @@ import { Resolve } from '@angular/router';
import { Observable, forkJoin } from 'rxjs';
/** Custom Services */
import { SystemService } from '../system.service';
import { SystemService } from '../../system.service';
/**
* Manage Scheduler Jobs data resolver.
@@ -16,6 +16,7 @@ export class ManageSchedulerJobsResolver implements Resolve<Object> {
/**
* @param {SystemService} systemService System service.
*/
// eslint-disable-next-line @angular-eslint/prefer-inject
constructor(private systemService: SystemService) {}
/**
@@ -8,9 +8,11 @@
</mat-dialog-content>
<mat-list>
<mat-list-item *ngFor="let message of messages" class="message" ngClass]="{'green' : message.status}">
{{ message.message }}
</mat-list-item>
@for (message of messages; track message) {
<mat-list-item class="message" ngClass]="{'green' : message.status}">
{{ message.message }}
</mat-list-item>
}
</mat-list>
<mat-dialog-actions>
<button mat-raised-button color="primary" (click)="runSelectedJobs()">
@@ -1,5 +1,5 @@
import { SelectionModel } from '@angular/cdk/collections';
import { Component, EventEmitter, Inject, OnInit, Output, QueryList, ViewChildren } from '@angular/core';
import { Component, EventEmitter, OnInit, Output, QueryList, ViewChildren, inject } from '@angular/core';
import {
MAT_DIALOG_DATA,
MatDialogTitle,
@@ -52,6 +52,9 @@ export interface JobDataType {
]
})
export class RunSelectedJobsPopoverComponent implements OnInit {
private systemService = inject(SystemService);
data = inject<SelectedJobsDataType>(MAT_DIALOG_DATA);
/** Confirmed jobs event emitter */
@Output() confirmedJobs = new EventEmitter<JobDataType[]>();
@@ -66,12 +69,6 @@ export class RunSelectedJobsPopoverComponent implements OnInit {
/** API call response message */
messages: { message: string; status: number }[] = [];
constructor(
private systemService: SystemService,
@Inject(MAT_DIALOG_DATA)
public data: SelectedJobsDataType
) {}
ngOnInit(): void {
this.selectedJobs = this.data.selectedJobs.selected.sort((a, b) => a.jobId - b.jobId);
}
@@ -26,22 +26,24 @@
<ng-container matColumnDef="status">
<th mat-header-cell *matHeaderCellDef mat-sort-header>{{ 'labels.inputs.Status' | translate }}</th>
<td mat-cell *matCellDef="let jobHistoryData">
<fa-icon
*ngIf="jobHistoryData.status === 'success'"
class="success"
matTooltip="{{ 'tooltips.Successful' | translate }}"
matTooltipPosition="right"
icon="check-circle"
size="lg"
></fa-icon>
<fa-icon
*ngIf="!(jobHistoryData.status === 'success')"
class="fail"
matTooltip="{{ 'tooltips.Failed' | translate }}"
matTooltipPosition="right"
icon="times-circle"
size="lg"
></fa-icon>
@if (jobHistoryData.status === 'success') {
<fa-icon
class="success"
matTooltip="{{ 'tooltips.Successful' | translate }}"
matTooltipPosition="right"
icon="check-circle"
size="lg"
></fa-icon>
}
@if (!(jobHistoryData.status === 'success')) {
<fa-icon
class="fail"
matTooltip="{{ 'tooltips.Failed' | translate }}"
matTooltipPosition="right"
icon="times-circle"
size="lg"
></fa-icon>
}
</td>
</ng-container>
@@ -53,16 +55,17 @@
<ng-container matColumnDef="error_log">
<th mat-header-cell *matHeaderCellDef mat-sort-header>{{ 'labels.inputs.Error Log' | translate }}</th>
<td mat-cell *matCellDef="let jobHistoryData">
<button
mat-icon-button
class="errorlog"
*ngIf="!(jobHistoryData.status === 'success')"
matTooltip="{{ 'tooltips.Error Log' | translate }}"
matTooltipPosition="right"
(click)="openError(jobHistoryData.version)"
>
<fa-icon icon="exclamation-circle" size="lg"></fa-icon>
</button>
@if (!(jobHistoryData.status === 'success')) {
<button
mat-icon-button
class="errorlog"
matTooltip="{{ 'tooltips.Error Log' | translate }}"
matTooltipPosition="right"
(click)="openError(jobHistoryData.version)"
>
<fa-icon icon="exclamation-circle" size="lg"></fa-icon>
</button>
}
</td>
</ng-container>
@@ -1,5 +1,5 @@
/** Angular Imports. */
import { Component, OnInit, ViewChild } from '@angular/core';
import { Component, OnInit, ViewChild, inject } from '@angular/core';
import { MatPaginator } from '@angular/material/paginator';
import {
MatTableDataSource,
@@ -50,6 +50,10 @@ import { STANDALONE_SHARED_IMPORTS } from 'app/standalone-shared.module';
]
})
export class ViewHistorySchedulerJobComponent implements OnInit {
private route = inject(ActivatedRoute);
private dialog = inject(MatDialog);
private router = inject(Router);
/** Job History data. */
jobHistoryData: any;
/** Columns to be displayed in Scheduler Job History. */
@@ -73,11 +77,7 @@ export class ViewHistorySchedulerJobComponent implements OnInit {
* Retrieves the scheduler Job History data from `resolve`.
* @param {ActivatedRoute} route Activated Route.
*/
constructor(
private route: ActivatedRoute,
private dialog: MatDialog,
private router: Router
) {
constructor() {
this.route.data.subscribe((data: { jobsSchedulerHistory: any }) => {
this.jobHistoryData = data.jobsSchedulerHistory;
});
@@ -1,5 +1,5 @@
/** Angular Imports */
import { Injectable } from '@angular/core';
import { Injectable, inject } from '@angular/core';
import { ActivatedRouteSnapshot } from '@angular/router';
/** rxjs Imports */
@@ -13,10 +13,7 @@ import { SystemService } from '../../../system.service';
*/
@Injectable()
export class ViewHistorySchedulerJobsResolver {
/**
* @param {SystemService} systemService System service.
*/
constructor(private systemService: SystemService) {}
private systemService = inject(SystemService);
/**
* Returns the Scheduler Jobs History data.
@@ -1,5 +1,5 @@
/** Angular Imports */
import { Component } from '@angular/core';
import { Component, inject } from '@angular/core';
import { ActivatedRoute, RouterLink } from '@angular/router';
import { FaIconComponent } from '@fortawesome/angular-fontawesome';
import { YesnoPipe } from '../../../../pipes/yesno.pipe';
@@ -19,6 +19,8 @@ import { STANDALONE_SHARED_IMPORTS } from 'app/standalone-shared.module';
]
})
export class ViewSchedulerJobComponent {
private route = inject(ActivatedRoute);
/** Job Data. */
jobData: any;
@@ -26,7 +28,7 @@ export class ViewSchedulerJobComponent {
* Retrieves the selected job data from `resolve`.
* @param {ActivatedRoute} route Activated Route.
*/
constructor(private route: ActivatedRoute) {
constructor() {
this.route.data.subscribe((data: { selectedJob: any }) => {
this.jobData = data.selectedJob;
});
@@ -1,5 +1,5 @@
/** Angular Imports */
import { Injectable } from '@angular/core';
import { Injectable, inject } from '@angular/core';
import { ActivatedRouteSnapshot } from '@angular/router';
/** rxjs Imports */
@@ -13,10 +13,7 @@ import { SystemService } from '../../../system.service';
*/
@Injectable()
export class ViewSchedulerJobResolver {
/**
* @param {SystemService} systemService System service.
*/
constructor(private systemService: SystemService) {}
private systemService = inject(SystemService);
/**
* Returns the selected scheduler job data.
@@ -40,13 +40,11 @@
</textPath>
</svg:text>
</svg:g>
<svg:g
class="link-midpoint"
*ngIf="link.midPoint"
[attr.transform]="'translate(' + link.midPoint.x + ',' + link.midPoint.y + ')'"
>
<ellipse rx="30" ry="10" />
<svg:text alignment-baseline="central">{{ link.data.linkText | translateKey: 'text' }}</svg:text>
</svg:g>
@if (link.midPoint) {
<svg:g class="link-midpoint" [attr.transform]="'translate(' + link.midPoint.x + ',' + link.midPoint.y + ')'">
<ellipse rx="30" ry="10" />
<svg:text alignment-baseline="central">{{ link.data.linkText | translateKey: 'text' }}</svg:text>
</svg:g>
}
</ng-template>
</ngx-graph>
@@ -2,71 +2,75 @@
<mat-form-field class="flex-31">
<mat-label>{{ 'labels.inputs.Job Name' | translate }}</mat-label>
<mat-select [formControl]="jobName" (selectionChange)="getWorkflowJobSteps($event.value)">
<mat-option *ngFor="let job of jobNameOptions" [value]="job">
{{ job | translateKey: 'catalogs' }}
</mat-option>
@for (job of jobNameOptions; track job) {
<mat-option [value]="job">
{{ job | translateKey: 'catalogs' }}
</mat-option>
}
</mat-select>
</mat-form-field>
<div class="action-button gap-25percent" *ngIf="jobStepName">
<button mat-raised-button color="primary" (click)="addJobStep()">
<fa-icon icon="plus" class="m-r-10"></fa-icon>{{ 'labels.buttons.Link Job Step' | translate }}
</button>
</div>
@if (jobStepName) {
<div class="action-button gap-25percent">
<button mat-raised-button color="primary" (click)="addJobStep()">
<fa-icon icon="plus" class="m-r-10"></fa-icon>{{ 'labels.buttons.Link Job Step' | translate }}
</button>
</div>
}
<div class="mat-elevation-z8 container" *ngIf="jobStepsData.length > 0">
<table
mat-table
[dataSource]="jobStepsData"
#table
cdkDropList
[cdkDropListData]="jobStepsData"
(cdkDropListDropped)="dropTable($event)"
>
<ng-container matColumnDef="stepName">
<th mat-header-cell *matHeaderCellDef>{{ 'labels.inputs.Step Name' | translate }}</th>
<td mat-cell *matCellDef="let jobStep">{{ jobStep.stepName }}</td>
</ng-container>
@if (jobStepsData.length > 0) {
<div class="mat-elevation-z8 container">
<table
mat-table
[dataSource]="jobStepsData"
#table
cdkDropList
[cdkDropListData]="jobStepsData"
(cdkDropListDropped)="dropTable($event)"
>
<ng-container matColumnDef="stepName">
<th mat-header-cell *matHeaderCellDef>{{ 'labels.inputs.Step Name' | translate }}</th>
<td mat-cell *matCellDef="let jobStep">{{ jobStep.stepName }}</td>
</ng-container>
<ng-container matColumnDef="stepOrder">
<th mat-header-cell *matHeaderCellDef>{{ 'labels.inputs.Order' | translate }}</th>
<td mat-cell *matCellDef="let jobStep">{{ jobStep.order }}</td>
</ng-container>
<ng-container matColumnDef="actions">
<th mat-header-cell *matHeaderCellDef>{{ 'labels.inputs.Actions' | translate }}</th>
<td mat-cell *matCellDef="let row; let rowIndex = index">
<button
type="button"
mat-icon-button
color="warn"
(click)="removeJobStep(rowIndex)"
matTooltip="{{ 'tooltips.Delete' | translate }}"
matTooltipPosition="left"
>
<fa-icon icon="trash"></fa-icon>
</button>
</td>
</ng-container>
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
<tr mat-row cdkDrag [cdkDragData]="row" *matRowDef="let row; columns: displayedColumns"></tr>
</table>
</div>
}
<ng-container matColumnDef="stepOrder">
<th mat-header-cell *matHeaderCellDef>{{ 'labels.inputs.Order' | translate }}</th>
<td mat-cell *matCellDef="let jobStep">{{ jobStep.order }}</td>
</ng-container>
@if (stepOrderHasChanged) {
<div class="container margin-t space-top layout-row gap-2percent layout-align-center layout-column-xs">
<button mat-raised-button [routerLink]="['../']">
{{ 'labels.buttons.Cancel' | translate }}
</button>
<button mat-raised-button color="primary" (click)="saveChanges()">
{{ 'labels.buttons.Apply Changes' | translate }}
</button>
</div>
}
<ng-container matColumnDef="actions">
<th mat-header-cell *matHeaderCellDef>{{ 'labels.inputs.Actions' | translate }}</th>
<td mat-cell *matCellDef="let row; let rowIndex = index">
<button
type="button"
mat-icon-button
color="warn"
(click)="removeJobStep(rowIndex)"
matTooltip="{{ 'tooltips.Delete' | translate }}"
matTooltipPosition="left"
>
<fa-icon icon="trash"></fa-icon>
</button>
</td>
</ng-container>
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
<tr mat-row cdkDrag [cdkDragData]="row" *matRowDef="let row; columns: displayedColumns"></tr>
</table>
</div>
<div
*ngIf="stepOrderHasChanged"
class="container margin-t space-top layout-row gap-2percent layout-align-center layout-column-xs"
>
<button mat-raised-button [routerLink]="['../']">
{{ 'labels.buttons.Cancel' | translate }}
</button>
<button mat-raised-button color="primary" (click)="saveChanges()">
{{ 'labels.buttons.Apply Changes' | translate }}
</button>
</div>
<div class="container space-top" *ngIf="jobStepsData.length > 0 && !stepOrderHasChanged">
<mifosx-workflow-diagram [jobStepsData]="jobStepsData"></mifosx-workflow-diagram>
</div>
@if (jobStepsData.length > 0 && !stepOrderHasChanged) {
<div class="container space-top">
<mifosx-workflow-diagram [jobStepsData]="jobStepsData"></mifosx-workflow-diagram>
</div>
}
</div>
@@ -1,5 +1,5 @@
import { CdkDragDrop, moveItemInArray, CdkDropList, CdkDrag } from '@angular/cdk/drag-drop';
import { Component, OnInit, ViewChild } from '@angular/core';
import { Component, OnInit, ViewChild, inject } from '@angular/core';
import { UntypedFormControl, Validators, ReactiveFormsModule } from '@angular/forms';
import { MatDialog } from '@angular/material/dialog';
import {
@@ -57,6 +57,10 @@ export interface JobStep {
]
})
export class WorkflowJobsComponent implements OnInit {
private systemService = inject(SystemService);
dialog = inject(MatDialog);
private translateService = inject(TranslateService);
stepOrderHasChanged = false;
jobNameOptions: any = [];
@@ -76,12 +80,6 @@ export class WorkflowJobsComponent implements OnInit {
'actions'
];
constructor(
private systemService: SystemService,
public dialog: MatDialog,
private translateService: TranslateService
) {}
ngOnInit(): void {
this.systemService
.getWorkflowJobNames()
@@ -171,7 +169,6 @@ export class WorkflowJobsComponent implements OnInit {
options: { label: 'stepDescription', value: 'stepName', data: this.jobAvailableStepsData },
order: 1
})
];
const data = {
title: this.translateService.instant('labels.text.Add Job Step to Workflow'),
@@ -10,6 +10,7 @@ export class WorkflowJobResolver {
/**
* @param {SystemService} systemService System service.
*/
// eslint-disable-next-line @angular-eslint/prefer-inject
constructor(private systemService: SystemService) {}
/**