System Jobs using confirmation dialog

This commit is contained in:
Jose Alberto Hernandez
2024-12-05 22:45:37 -05:00
committed by Jose Alberto Hernandez
parent 29cda98b62
commit c4338b44f0
25 changed files with 332 additions and 33 deletions
@@ -1,6 +1,7 @@
<div class="container m-b-20 space-top" fxLayout="row" fxLayoutGap="20px">
<div #schedulerStatus>
<h2 class="no-m">{{'labels.heading.Scheduler Status' | translate}}:<span class="m-l-20 m-r-20">{{ schedulerActive ? ( 'labels.inputs.Active' | translate ) : ('labels.catalogs.Inactive' | translate) }}</span>
<h2 class="no-m">{{'labels.heading.Scheduler Status' | translate}}:<span class="m-l-20 m-r-20">{{ schedulerActive ?
( 'labels.inputs.Active' | translate ) : ('labels.catalogs.Inactive' | translate) }}</span>
</h2>
</div>
<button mat-raised-button class="suspend" (click)="suspendScheduler()" *ngIf="schedulerActive">
@@ -24,7 +25,7 @@
</div>
<div class="space-top" fxLayout="row" fxLayoutGap="20px">
<button mat-raised-button color="primary" (click)="runSelectedJobs()" [disabled]="!isAnyJobSelected()">
<button mat-raised-button color="primary" (click)="openRunSelectedJobsDialog()" [disabled]="!isAnyJobSelected()">
<fa-icon icon="play" class="m-r-10"></fa-icon>
{{'labels.buttons.Run Selected Jobs' | translate}}
</button>
@@ -75,12 +76,14 @@
<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>
<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>
</td>
</ng-container>
@@ -94,8 +97,8 @@
<th mat-header-cell *matHeaderCellDef mat-sort-header> {{'labels.inputs.Currently Running' | translate}} </th>
<td mat-cell *matCellDef="let job" class="center">
<div [className]="job.currentlyRunning === true ? 'currently-running' : 'not-currently-running'">
<fa-icon matTooltip="{{ job.currentlyRunning === true | yesNo }}" matTooltipPosition="right"
icon="circle" size="lg"></fa-icon>
<fa-icon matTooltip="{{ job.currentlyRunning === true | yesNo }}" matTooltipPosition="right" icon="circle"
size="lg"></fa-icon>
</div>
</td>
</ng-container>
@@ -104,8 +107,8 @@
<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="!(job.lastRunHistory && job.lastRunHistory.status === 'success')" matTooltip="{{'labels.inputs.Error Log' | translate}}"
matTooltipPosition="right">
*ngIf="!(job.lastRunHistory && job.lastRunHistory.status === 'success')"
matTooltip="{{'labels.inputs.Error Log' | translate}}" matTooltipPosition="right">
<fa-icon icon="exclamation-circle" size="lg"></fa-icon>
</button>
</td>
@@ -123,13 +126,9 @@
</div>
<div class="container space-top" fxLayout="row" fxLayoutGap="20px">
<button mat-raised-button color="primary" (click)="runSelectedJobs()" [disabled]="!isAnyJobSelected()">
<button mat-raised-button color="primary" (click)="openRunSelectedJobsDialog()" [disabled]="!isAnyJobSelected()">
<fa-icon icon="play" class="m-r-10"></fa-icon>
{{'labels.buttons.Run Selected Jobs' | translate}}<ng-template #templateSchedulerJobs let-data let-popover="popover">
<h2>{{'labels.heading.Template' | translate}}</h2>
<p>{{'labels.text.Template I am trying to use' | translate}}.</p>
<button (click)="popover.close();nextStepSchedulerJobs()">{{'labels.buttons.Next' | translate }}</button>
</ng-template>
{{'labels.buttons.Run Selected Jobs' | translate}}
</button>
<button mat-raised-button color="primary" (click)="refresh()">
<fa-icon icon="sync" class="m-r-10"></fa-icon>
@@ -141,10 +140,13 @@
<h4>{{'labels.heading.Scheduler status' | translate}}.</h4>
<div fxLayout="row" fxLayoutAlign="end" fxLayoutGap="2%" fxLayout.lt-md="column">
<button mat-raised-button color="warn"
(click)="popover.close();configurationWizardService.closeConfigWizard()">{{'labels.buttons.Close' | translate}}</button>
<button mat-raised-button color="primary" (click)="popover.close();previousStep()">{{'labels.buttons.Back' | translate}}</button>
(click)="popover.close();configurationWizardService.closeConfigWizard()">{{'labels.buttons.Close' |
translate}}</button>
<button mat-raised-button color="primary" (click)="popover.close();previousStep()">{{'labels.buttons.Back' |
translate}}</button>
<button mat-raised-button color="primary"
(click)="popover.close();showPopover(templateFilter, filter, 'bottom', true)">{{'labels.buttons.Next' | translate}}</button>
(click)="popover.close();showPopover(templateFilter, filter, 'bottom', true)">{{'labels.buttons.Next' |
translate}}</button>
</div>
</ng-template>
@@ -152,22 +154,29 @@
<h4>{{'labels.heading.Search bar to filter jobs' | translate }}.</h4>
<div fxLayout="row" fxLayoutAlign="end" fxLayoutGap="2%" fxLayout.lt-md="column">
<button mat-raised-button color="warn"
(click)="popover.close();configurationWizardService.closeConfigWizard()">{{'labels.buttons.Close' | translate}}</button>
(click)="popover.close();configurationWizardService.closeConfigWizard()">{{'labels.buttons.Close' |
translate}}</button>
<button mat-raised-button color="primary"
(click)="popover.close();showPopover(templateSchedulerStatus,schedulerStatus, 'bottom', true)">{{'labels.buttons.Back' | translate}}</button>
(click)="popover.close();showPopover(templateSchedulerStatus,schedulerStatus, 'bottom', true)">{{'labels.buttons.Back'
| translate}}</button>
<button mat-raised-button color="primary"
(click)="popover.close();showPopover(templateJobsTable,jobsTable, 'top', true)">{{'labels.buttons.Next' | translate}}</button>
(click)="popover.close();showPopover(templateJobsTable,jobsTable, 'top', true)">{{'labels.buttons.Next' |
translate}}</button>
</div>
</ng-template>
<ng-template #templateJobsTable let-data let-popover="popover">
<h4>{{'labels.heading.List of all scheduled batch jobs' | translate }} <a
href="https://mifosforge.jira.com/wiki/spaces/docs/pages/67895356/Manage+Scheduler+Jobs" target="_blank">{{'labels.heading.Schedular Jobs' | translate}}</a></h4>
href="https://mifosforge.jira.com/wiki/spaces/docs/pages/67895356/Manage+Scheduler+Jobs"
target="_blank">{{'labels.heading.Schedular Jobs' | translate}}</a></h4>
<div fxLayout="row" fxLayoutAlign="end" fxLayoutGap="2%" fxLayout.lt-md="column">
<button mat-raised-button color="warn"
(click)="popover.close();configurationWizardService.closeConfigWizard()">{{'labels.buttons.Close' | translate}}</button>
(click)="popover.close();configurationWizardService.closeConfigWizard()">{{'labels.buttons.Close' |
translate}}</button>
<button mat-raised-button color="primary"
(click)="popover.close();showPopover(templateFilter, filter, 'bottom', true)">{{'labels.buttons.Back' | translate}}</button>
<button mat-raised-button color="primary" (click)="popover.close();nextStep()">{{'labels.buttons.Next' | translate}}</button>
(click)="popover.close();showPopover(templateFilter, filter, 'bottom', true)">{{'labels.buttons.Back' |
translate}}</button>
<button mat-raised-button color="primary" (click)="popover.close();nextStep()">{{'labels.buttons.Next' |
translate}}</button>
</div>
</ng-template>
</ng-template>
@@ -19,6 +19,7 @@ import { NextStepDialogComponent } from '../../../configuration-wizard/next-step
import { CustomParametersPopoverComponent } from './custom-parameters-popover/custom-parameters-popover.component';
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';
/**
* Manage scheduler jobs component.
@@ -264,4 +265,30 @@ export class ManageSchedulerJobsComponent implements OnInit, AfterViewInit {
}
}
/**
* Open Run Selected Jobs Confirmation Dialog
*/
openRunSelectedJobsDialog() {
const dialog = this.dialog.open(RunSelectedJobsPopoverComponent, {
data: {
selectedJobs: this.selection
}
});
dialog.componentInstance.confirmedJobs.subscribe(result => {
if (result) {
const selectedJobs = this.selection.selected;
const confirmedJobIds = result.map(job => job.jobId);
selectedJobs.forEach(job => {
if (!confirmedJobIds.includes(job.jobId)) {
this.selection.deselect(job);
}
});
dialog.close();
}
});
}
}
@@ -0,0 +1,23 @@
<h1 mat-dialog-title>{{'labels.heading.Selected Jobs' | translate}}:</h1>
<mat-dialog-content>
<div class="jobs-container">
<mifosx-run-selected-jobs-table [selectedJobs]="selectedJobs" (confirmedJobs)="runSelectedJobs()">
</mifosx-run-selected-jobs-table>
</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>
</mat-list>
<mat-dialog-actions>
<button mat-raised-button color="primary" (click)="runSelectedJobs()">
<fa-icon icon="play" class="m-r-10"></fa-icon>
{{'labels.buttons.Confirm' | translate}}
</button>
<button mat-raised-button color="warn" [mat-dialog-close]="{ show: 0 }">
{{'labels.buttons.Cancel' | translate}}
</button>
</mat-dialog-actions>
@@ -0,0 +1,9 @@
.message {
height: auto;
font-weight: 500;
color: #f44366;
}
.message.green {
color: #32cd32;
}
@@ -0,0 +1,23 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { RunSelectedJobsPopoverComponent } from './run-selected-jobs-popover.component';
describe('RunSelectedJobsPopoverComponent', () => {
let component: RunSelectedJobsPopoverComponent;
let fixture: ComponentFixture<RunSelectedJobsPopoverComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [ RunSelectedJobsPopoverComponent ]
})
.compileComponents();
fixture = TestBed.createComponent(RunSelectedJobsPopoverComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});
@@ -0,0 +1,81 @@
import { SelectionModel } from '@angular/cdk/collections';
import {
Component, EventEmitter, Inject, OnInit, Output, QueryList,
ViewChildren
} from '@angular/core';
import { MAT_DIALOG_DATA } from '@angular/material/dialog';
import { SystemService } from 'app/system/system.service';
import { RunSelectedJobsTableComponent } from './run-selected-jobs-table/run-selected-jobs-table.component';
interface SelectedJobsDataType {
selectedJobs: SelectionModel<JobDataType>;
}
export interface JobDataType {
active: boolean;
cronExpression: string;
currentlyRunning: boolean;
displayName: string;
jobId: number;
lastRunHistory: {
jobRunEndTime: string;
jobRunStartTime: string;
status: string;
triggerType: string;
version: number;
};
nextRunTime: string;
}
@Component({
selector: 'mifosx-run-selected-jobs-popover',
templateUrl: './run-selected-jobs-popover.component.html',
styleUrls: ['./run-selected-jobs-popover.component.scss']
})
export class RunSelectedJobsPopoverComponent implements OnInit {
/** Confirmed jobs event emitter */
@Output() confirmedJobs = new EventEmitter<JobDataType[]>();
/** Job table children */
@ViewChildren(RunSelectedJobsTableComponent) tableComponents:
QueryList<RunSelectedJobsTableComponent>;
/** Initialize Selected Jobs */
selectedJobs: JobDataType[] = [];
/** Show modal or not */
show: number;
/** 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);
}
/**
* Run all confirmed jobs from table
*/
runSelectedJobs(): void {
this.messages = [];
let tableData: JobDataType[] = [];
this.tableComponents.forEach((tableComponent) => {
tableData = (tableComponent.getTableData());
});
tableData.forEach((job) => {
this.systemService.runSelectedJob(job.jobId.toString())
.then((response) => {
this.messages.push({
message: `${job.displayName}: ${response.statusText} (${response.status})`,
status: response.ok
});
});
});
this.confirmedJobs.emit(tableData);
}
}
@@ -0,0 +1,23 @@
<div>
<table mat-table [dataSource]="selectedJobs">
<ng-container matColumnDef="displayName">
<th mat-header-cell *matHeaderCellDef>{{'labels.inputs.Display Name' |
translate}}</th>
<td mat-cell *matCellDef="let element; index as i">{{ element.displayName
}}</td>
</ng-container>
<ng-container matColumnDef="actions">
<th mat-header-cell *matHeaderCellDef></th>
<td mat-cell *matCellDef="let row; let rowIndex = index">
<button type="button" mat-icon-button color="warn" (click)="removeJobFromSelection(rowIndex)"
matTooltip="Delete" matTooltipPosition="left">
<fa-icon icon="trash"></fa-icon>
</button>
</td>
</ng-container>
<tr mat-header-row *matHeaderRowDef="columnsToDisplay" class="first-row"></tr>
<tr mat-row *matRowDef="let selectedJobs; columns: columnsToDisplay"></tr>
</table>
</div>
@@ -0,0 +1,13 @@
table td {
padding-right: 50px;
}
.jobs-container {
display: flex;
flex-direction: column;
gap: 10px;
}
.jobs-container table td {
padding-right: 50px;
}
@@ -0,0 +1,23 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { RunSelectedJobsTableComponent } from './run-selected-jobs-table.component';
describe('RunSelectedJobsTableComponent', () => {
let component: RunSelectedJobsTableComponent;
let fixture: ComponentFixture<RunSelectedJobsTableComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [ RunSelectedJobsTableComponent ]
})
.compileComponents();
fixture = TestBed.createComponent(RunSelectedJobsTableComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});
@@ -0,0 +1,52 @@
import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core';
import { JobDataType } from '../run-selected-jobs-popover.component';
/**
* Run Selected Jobs Table Component
*/
@Component({
selector: 'mifosx-run-selected-jobs-table',
templateUrl: './run-selected-jobs-table.component.html',
styleUrls: ['./run-selected-jobs-table.component.scss']
})
export class RunSelectedJobsTableComponent implements OnInit {
/** Selected Jobs For Table */
@Input() selectedJobs: JobDataType[];
/** Confirmed Jobs */
@Output() confirmedJobs: EventEmitter<JobDataType[]> = new
EventEmitter<JobDataType[]>();
/** Columns for the table */
columnsToDisplay: string[] = ['displayName', 'actions'];
constructor() {
}
ngOnInit(): void {
}
/**
* Removes job from selection array
* @param index
*/
removeJobFromSelection(index: number): void {
let idx = 0;
const finalSelectedJobs: JobDataType[] = [];
for (; idx < this.selectedJobs.length; idx) {
if (idx !== index) {
finalSelectedJobs.push(this.selectedJobs[idx]);
}
}
this.selectedJobs = finalSelectedJobs;
}
/**
* Gets selected jobs array
* @returns selected jobs array
*/
getTableData(): JobDataType[] {
return this.selectedJobs;
}
}
+5 -1
View File
@@ -75,6 +75,8 @@ import { LoanLockedComponent } from './manage-jobs/cob-workflow/loan-locked/loan
import { CustomParametersPopoverComponent } from './manage-jobs/scheduler-jobs/custom-parameters-popover/custom-parameters-popover.component';
import { CustomParametersTableComponent } from './manage-jobs/scheduler-jobs/custom-parameters-popover/custom-parameters-table/custom-parameters-table.component';
import { ErrorLogPopoverComponent } from './manage-jobs/scheduler-jobs/error-log-popover/error-log-popover.component';
import { RunSelectedJobsPopoverComponent } from './manage-jobs/scheduler-jobs/run-selected-jobs-popover/run-selected-jobs-popover.component';
import { RunSelectedJobsTableComponent } from './manage-jobs/scheduler-jobs/run-selected-jobs-popover/run-selected-jobs-table/run-selected-jobs-table.component';
@NgModule({
imports: [
@@ -149,7 +151,9 @@ import { ErrorLogPopoverComponent } from './manage-jobs/scheduler-jobs/error-log
LoanLockedComponent,
CustomParametersPopoverComponent,
CustomParametersTableComponent,
ErrorLogPopoverComponent
ErrorLogPopoverComponent,
RunSelectedJobsPopoverComponent,
RunSelectedJobsTableComponent
],
})
export class SystemModule { }
+1 -1
View File
@@ -339,7 +339,7 @@ export class SystemService {
* @returns {Observable<any>}
*/
runSelectedJob(jobId: string): Promise<any> {
return this.http.post(`/jobs/${jobId}?command=executeJob`, this.emptyPayload).toPromise();
return this.http.post(`/jobs/${jobId}?command=executeJob`, this.emptyPayload, { observe: 'response' }).toPromise();
}
/**
+1
View File
@@ -1084,6 +1084,7 @@
"Select Excel File": "Vyberte Soubor Excel",
"Selected Clients": "Vybraní klienti",
"Selected Groups": "Vybrané skupiny",
"Selected Jobs": "Vybrané práce",
"Session Timeout": "Časový limit relace",
"Settings": "Nastavení",
"Share Accounts": "Sdílet účty",
+1
View File
@@ -1085,6 +1085,7 @@
"Select Excel File": "Wählen Sie Excel-Datei",
"Selected Clients": "Ausgewählte Kunden",
"Selected Groups": "Ausgewählte Gruppen",
"Selected Jobs": "Ausgewählte Jobs",
"Session Timeout": "Session-Timeout",
"Settings": "Einstellungen",
"Share Accounts": "Konten teilen",
+1
View File
@@ -1086,6 +1086,7 @@
"Select Excel File": "Select Excel File",
"Selected Clients": "Selected Clients",
"Selected Groups": "Selected Groups",
"Selected Jobs": "Selected Jobs",
"Session Timeout": "Session Timeout",
"Settings": "Settings",
"Share Accounts": "Share Accounts",
+1
View File
@@ -1083,6 +1083,7 @@
"Select Excel File": "Seleccionar archivo de Excel",
"Selected Clients": "Clientes seleccionados",
"Selected Groups": "Grupos seleccionados",
"Selected Jobs": "Trabajos seleccionados",
"Session Timeout": "Término de la Sesión",
"Settings": "Ajustes",
"Share Accounts": "Cuentas de Acciones",
+1
View File
@@ -1085,6 +1085,7 @@
"Select Excel File": "Sélectionnez un fichier Excel",
"Selected Clients": "Clients sélectionnés",
"Selected Groups": "Groupes sélectionnés",
"Selected Jobs": "Emplois sélectionnés",
"Session Timeout": "Expiration de la session",
"Settings": "Paramètres",
"Share Accounts": "Partager des comptes",
+1
View File
@@ -1085,6 +1085,7 @@
"Select Excel File": "Seleziona File Excel",
"Selected Clients": "Clienti selezionati",
"Selected Groups": "Gruppi selezionati",
"Selected Jobs": "Lavori selezionati",
"Session Timeout": "Timeout della sessione",
"Settings": "Impostazioni",
"Share Accounts": "Condividi account",
+1
View File
@@ -1086,6 +1086,7 @@
"Select Excel File": "엑셀 파일 선택",
"Selected Clients": "선택된 클라이언트",
"Selected Groups": "선택된 그룹",
"Selected Jobs": "선택된 직업",
"Session Timeout": "세션 타임 아웃",
"Settings": "설정",
"Share Accounts": "계정 공유",
+1
View File
@@ -1085,6 +1085,7 @@
"Select Excel File": "Pasirinkite Excel failą",
"Selected Clients": "Atrinkti klientai",
"Selected Groups": "Pasirinktos grupės",
"Selected Jobs": "Pasirinkti darbai",
"Session Timeout": "Seanso skirtasis laikas",
"Settings": "Nustatymai",
"Share Accounts": "Bendrinti paskyras",
+1
View File
@@ -1085,6 +1085,7 @@
"Select Excel File": "Atlasiet Excel failu",
"Selected Clients": "Izvēlētie klienti",
"Selected Groups": "Atlasītās grupas",
"Selected Jobs": "Atlasītie darbi",
"Session Timeout": "Sesijas noildze",
"Settings": "Iestatījumi",
"Share Accounts": "Kopīgot kontus",
+1
View File
@@ -1085,6 +1085,7 @@
"Select Excel File": "एक्सेल फाइल चयन गर्नुहोस्",
"Selected Clients": "चयन गरिएका ग्राहकहरू",
"Selected Groups": "चयन गरिएका समूहहरू",
"Selected Jobs": "चयन गरिएका कार्यहरू",
"Session Timeout": "सत्र टाइमआउट",
"Settings": "सेटिङहरू",
"Share Accounts": "खाताहरू साझेदारी गर्नुहोस्",
+1
View File
@@ -1085,6 +1085,7 @@
"Select Excel File": "Selecione o arquivo Excel",
"Selected Clients": "Clientes Selecionados",
"Selected Groups": "Grupos Selecionados",
"Selected Jobs": "Empregos selecionados",
"Session Timeout": "Sessão expirada",
"Settings": "Configurações",
"Share Accounts": "Compartilhar contas",
+1
View File
@@ -1085,6 +1085,7 @@
"Select Excel File": "Chagua Faili ya Excel",
"Selected Clients": "Wateja Waliochaguliwa",
"Selected Groups": "Vikundi Vilivyochaguliwa",
"Selected Jobs": "Kazi Zilizochaguliwa",
"Session Timeout": "Muda wa Kikao umekwisha",
"Settings": "Mipangilio",
"Share Accounts": "Shiriki Akaunti",
+2 -2
View File
@@ -2,8 +2,8 @@
/* tslint:disable */
export default {
'mifos_x': {
'version': '240721',
'hash': 'd39a6d8a'
'version': '241204',
'hash': '29cda98b'
},
'allow_switching_backend_instance': true
};