This commit is contained in:
Michele Artini 2023-04-14 16:06:59 +02:00
parent f4399909a6
commit a855a6afff
16 changed files with 172 additions and 75 deletions

View File

@ -4,7 +4,7 @@
<parent> <parent>
<groupId>eu.dnetlib.dhp</groupId> <groupId>eu.dnetlib.dhp</groupId>
<artifactId>apps</artifactId> <artifactId>apps</artifactId>
<version>3.3.3-SNAPSHOT</version> <version>3.4.1-SNAPSHOT</version>
<relativePath>../</relativePath> <relativePath>../</relativePath>
</parent> </parent>

View File

@ -28,7 +28,12 @@ public class WfHistoryAjaxController extends AbstractDnetController {
return logger.history(total, from, to); return logger.history(total, from, to);
} }
@GetMapping("/{processId}") @GetMapping("/byConf/{wfConfId}")
public List<WfHistoryEntry> history(@PathVariable final String wfConfId) {
return logger.history(wfConfId);
}
@GetMapping("/proc/{processId}")
public WfHistoryEntry getProcessExecution(@PathVariable final String processId) { public WfHistoryEntry getProcessExecution(@PathVariable final String processId) {
return logger.getLog(processId); return logger.getLog(processId);
} }

View File

@ -37,7 +37,7 @@ import { SpinnerHttpInterceptor } from './common/spinner.service';
import { MdstoresComponent, MdstoreInspectorComponent, MDStoreVersionsDialog, AddMDStoreDialog } from './mdstores/mdstores.component'; import { MdstoresComponent, MdstoreInspectorComponent, MDStoreVersionsDialog, AddMDStoreDialog } from './mdstores/mdstores.component';
import { CleanerTesterComponent } from './cleaner-tester/cleaner-tester.component'; import { CleanerTesterComponent } from './cleaner-tester/cleaner-tester.component';
import { EmailDialog, EmailsComponent } from './emails/emails.component'; import { EmailDialog, EmailsComponent } from './emails/emails.component';
import { WfConfsComponent, WfConfDialog } from './wf-confs/wf-confs.component'; import { WfConfsComponent, WfConfDialog, WfConfSingle } from './wf-confs/wf-confs.component';
import { MatTabsModule } from '@angular/material/tabs'; import { MatTabsModule } from '@angular/material/tabs';
import { MatCheckboxModule } from '@angular/material/checkbox'; import { MatCheckboxModule } from '@angular/material/checkbox';
import { MatStepperModule } from '@angular/material/stepper'; import { MatStepperModule } from '@angular/material/stepper';
@ -75,7 +75,8 @@ import { MatStepperModule } from '@angular/material/stepper';
EmailsComponent, EmailsComponent,
EmailDialog, EmailDialog,
WfConfsComponent, WfConfsComponent,
WfConfDialog WfConfDialog,
WfConfSingle
], ],
imports: [ imports: [
BrowserModule, BrowserModule,

View File

@ -74,6 +74,10 @@ export class ISService {
this.httpGetWithOptions<WfHistoryEntry[]>('/ajax/wf_history/', { params: params }, onSuccess); this.httpGetWithOptions<WfHistoryEntry[]>('/ajax/wf_history/', { params: params }, onSuccess);
} }
loadWfHistoryForConf(wfConfId: string, onSuccess: Function): void {
this.httpGet<WfHistoryEntry[]>('/ajax/wf_history/byConf/' + encodeURIComponent(wfConfId), onSuccess);
}
loadContexts(onSuccess: Function): void { loadContexts(onSuccess: Function): void {
this.httpGet<Context[]>('./ajax/contexts/', onSuccess); this.httpGet<Context[]>('./ajax/contexts/', onSuccess);
} }

View File

@ -39,14 +39,12 @@
} }
.menu-count { .menu-count {
padding-top: 0.3em;
padding-bottom: 0.3em;
padding-left: 0.5em; padding-left: 0.5em;
padding-right: 0.5em; padding-right: 0.5em;
border-radius: 0.2em; border-radius: 1em;
font-size: 0.6em; font-size: 0.7em;
color: #fff; color: #fff;
text-align: center; text-align: center;
float: right; float: right;
width: 3em; width: 2em;
} }

View File

@ -93,7 +93,7 @@
<p>You are now done.</p> <p>You are now done.</p>
<div> <div>
<form [formGroup]="wfConfFormFinal" (ngSubmit)="onSubmit()"> <form [formGroup]="wfConfFormFinal" (ngSubmit)="onSubmit()">
<button mat-stroked-button color="primary" type="submit">Submit</button> <button mat-stroked-button color="primary" type="submit">Save</button>
<mat-error *ngIf="wfConfFormFinal.errors?.['serverError']"> <mat-error *ngIf="wfConfFormFinal.errors?.['serverError']">
{{ wfConfFormFinal.errors?.['serverError'] }} {{ wfConfFormFinal.errors?.['serverError'] }}
</mat-error> </mat-error>
@ -102,7 +102,3 @@
</mat-step> </mat-step>
</mat-vertical-stepper> </mat-vertical-stepper>
</div> </div>
<div mat-dialog-actions>
<button mat-stroked-button color="primary" mat-dialog-close>Close</button>
</div>

View File

@ -0,0 +1,73 @@
<div *ngIf="conf" style="padding: 16px; margin-top: 0.4em; border: 1px solid lightgray; border-radius: 8px;">
<h2>{{conf.name}}</h2>
<span *ngIf="conf.dsName"><b>Datasource Name:</b> {{conf.dsName}}<br /></span>
<span *ngIf="conf.dsId"><b>Datasource ID:</b> {{conf.dsId}}<br /></span>
<span *ngIf="conf.apiId"><b>Datasource API:</b> {{conf.apiId}}<br /></span>
<button mat-stroked-button color="primary" (click)="launchWfConf()">
<mat-icon fontIcon="play_circle"></mat-icon>
launch
</button>
<button mat-stroked-button color="primary" (click)="editConf()">
<mat-icon fontIcon="edit"></mat-icon>
configure
</button>
<a href="./api/resources/{{conf.workflow}}/content" mat-stroked-button color="link" target="_blank">
<mat-icon fontIcon="code"></mat-icon>
raw workflow
</a>
<button mat-stroked-button color="warn" (click)="deleteConf()">
<mat-icon fontIcon="delete"></mat-icon>
delete
</button>
<mat-divider style="margin-top: 1em; margin-bottom: 1em;"></mat-divider>
<table mat-table [dataSource]="historyDatasource" matSort>
<ng-container matColumnDef="processId">
<th mat-header-cell *matHeaderCellDef style="width: 15%;" mat-sort-header
sortActionDescription="Sort by Process ID"> Process Id </th>
<td mat-cell *matCellDef="let element">
<a (click)="openWfHistoryDialog(element)">{{element.processId}}</a>
</td>
</ng-container>
<ng-container matColumnDef="status">
<th mat-header-cell *matHeaderCellDef style="width: 10%;" mat-sort-header sortActionDescription="Sort by Status">
Status </th>
<td mat-cell *matCellDef="let element"><span class="badge-label"
[ngClass]="{'badge-success' : element.status === 'success', 'badge-failure' : element.status === 'failure'}">{{element.status}}</span>
</td>
</ng-container>
<ng-container matColumnDef="startDate">
<th mat-header-cell *matHeaderCellDef style="width: 15%;" mat-sort-header
sortActionDescription="Sort by Start Date"> Start Date </th>
<td mat-cell *matCellDef="let element"> {{element.startDate}} </td>
</ng-container>
<ng-container matColumnDef="endDate">
<th mat-header-cell *matHeaderCellDef style="width: 15%;" mat-sort-header
sortActionDescription="Sort by End Date">
End Date </th>
<td mat-cell *matCellDef="let element"> {{element.endDate}} </td>
</ng-container>
<tr mat-header-row *matHeaderRowDef="colums"></tr>
<tr mat-row *matRowDef="let row; columns: colums;"></tr>
<!-- Row shown when there is no matching data. -->
<tr class="mat-row" *matNoDataRow>
<td class="mat-cell" colspan="4" style="padding: 0 16px;">No execution in history"</td>
</tr>
</table>
<!-- <pre>{{conf | json}}</pre> -->
</div>
<div *ngIf="!conf" style="margin-top: 2em;">
Workflow Configuration does not exist
</div>

View File

@ -12,27 +12,4 @@
</a> </a>
</nav> </nav>
<div *ngIf="conf" style="margin-top: 2em;"> <wf-conf-single [conf]="conf"></wf-conf-single>
<button mat-stroked-button color="primary" (click)="launchWfConf()">
<mat-icon fontIcon="play_circle"></mat-icon>
launch
</button>
<button mat-stroked-button color="primary" (click)="editConf()">
<mat-icon fontIcon="edit"></mat-icon>
configure
</button>
<a href="./api/resources/{{conf.workflow}}/content" mat-stroked-button color="link" target="_blank">
<mat-icon fontIcon="code"></mat-icon>
raw workflow
</a>
<button mat-stroked-button color="warn" (click)="deleteConf()">
<mat-icon fontIcon="delete"></mat-icon>
delete
</button>
<pre>{{conf | json}}</pre>
</div>
<div *ngIf="!conf" style="margin-top: 2em;">
Workflow Configuration does not exist
</div>

View File

@ -1,13 +1,15 @@
import { JsonPipe } from '@angular/common'; import { JsonPipe } from '@angular/common';
import { Component, Inject, OnInit, SecurityContext } from '@angular/core'; import { Component, Inject, Input, OnChanges, OnInit, SecurityContext, SimpleChanges } from '@angular/core';
import { FormControl, FormGroup, ValidatorFn, Validators } from '@angular/forms'; import { FormControl, FormGroup, ValidatorFn, Validators } from '@angular/forms';
import { MatDialog, MatDialogRef, MAT_DIALOG_DATA } from '@angular/material/dialog'; import { MatDialog, MatDialogRef, MAT_DIALOG_DATA } from '@angular/material/dialog';
import { MatSelectChange } from '@angular/material/select'; import { MatSelectChange } from '@angular/material/select';
import { MatSnackBar } from '@angular/material/snack-bar'; import { MatSnackBar } from '@angular/material/snack-bar';
import { ActivatedRoute, Router } from '@angular/router'; import { ActivatedRoute, Router } from '@angular/router';
import { KeyValue, SimpleResource, WfConf, WfParam, WfProcessStatus, WfSection } from '../common/is.model'; import { KeyValue, SimpleResource, WfConf, WfHistoryEntry, WfParam, WfProcessStatus, WfSection } from '../common/is.model';
import { ISService } from '../common/is.service'; import { ISService } from '../common/is.service';
import { ResMetadataDialog } from '../resources/resources.component'; import { ResMetadataDialog } from '../resources/resources.component';
import { MatTableDataSource } from '@angular/material/table';
import { WfHistoryDialog } from '../wf-history/wf-history.component';
@Component({ @Component({
selector: 'app-wf-confs', selector: 'app-wf-confs',
@ -73,34 +75,6 @@ export class WfConfsComponent implements OnInit {
if (result) this.router.navigate(['/wfs/conf', result.id]);; if (result) this.router.navigate(['/wfs/conf', result.id]);;
}); });
} }
launchWfConf() {
if (this.conf?.id && this.conf?.workflow) {
this.service.startWfConfiguration(this.conf?.id, (data: WfProcessStatus) => this.snackBar.open('Workflow launched !!!', 'INFO', { duration: 5000 }));
}
}
editConf() {
const dialogRef = this.dialog.open(WfConfDialog, {
data: this.conf,
width: '80%'
});
}
deleteConf() {
if (this.conf?.destroyWf) {
if (this.conf?.id && this.conf?.workflow) {
this.service.startDestroyWfConfiguration(this.conf?.id, (data: WfProcessStatus) => this.snackBar.open('Destroy Workflow launched, PLEASE WAIT !!!', 'INFO', { duration: 5000 }));
}
} else if (this.conf?.id) {
this.service.deleteWfConfiguration(this.conf?.id, (data: void) => {
this.snackBar.open('Configuration deleted !!!', 'INFO', { duration: 5000 });
this.conf = undefined;
});
}
}
} }
@Component({ @Component({
@ -108,7 +82,6 @@ export class WfConfsComponent implements OnInit {
templateUrl: 'wf-conf-dialog.html', templateUrl: 'wf-conf-dialog.html',
styleUrls: ['./wf-confs.component.css'] styleUrls: ['./wf-confs.component.css']
}) })
export class WfConfDialog implements OnInit { export class WfConfDialog implements OnInit {
wfTemplates: SimpleResource[] = []; wfTemplates: SimpleResource[] = [];
@ -195,3 +168,67 @@ export class WfConfDialog implements OnInit {
this.dialogRef.close(); this.dialogRef.close();
} }
} }
@Component({
selector: 'wf-conf-single',
templateUrl: 'wf-conf-single.html',
styleUrls: ['./wf-confs.component.css']
})
export class WfConfSingle implements OnInit, OnChanges {
@Input() conf?: WfConf;
prevConfId = '';
historyDatasource: MatTableDataSource<WfHistoryEntry> = new MatTableDataSource<WfHistoryEntry>([]);
colums: string[] = ['processId', 'status', 'startDate', 'endDate'];
constructor(public service: ISService, public dialog: MatDialog, public snackBar: MatSnackBar) { }
ngOnInit(): void {
if (this.conf) {
this.service.loadWfHistoryForConf(this.conf?.id, (data: WfHistoryEntry[]) => this.historyDatasource.data = data);
}
}
ngOnChanges(changes: SimpleChanges): void {
if (this.conf && this.conf.id != this.prevConfId) {
this.prevConfId = this.conf.id;
this.service.loadWfHistoryForConf(this.conf?.id, (data: WfHistoryEntry[]) => this.historyDatasource.data = data);
}
}
launchWfConf() {
if (this.conf?.id && this.conf?.workflow) {
this.service.startWfConfiguration(this.conf?.id, (data: WfProcessStatus) => this.snackBar.open('Workflow launched !!!', 'INFO', { duration: 5000 }));
}
}
editConf() {
const dialogRef = this.dialog.open(WfConfDialog, {
data: this.conf,
width: '80%'
});
}
deleteConf() {
if (this.conf?.destroyWf) {
if (this.conf?.id && this.conf?.workflow) {
this.service.startDestroyWfConfiguration(this.conf?.id, (data: WfProcessStatus) => this.snackBar.open('Destroy Workflow launched, PLEASE WAIT !!!', 'INFO', { duration: 5000 }));
}
} else if (this.conf?.id) {
this.service.deleteWfConfiguration(this.conf?.id, (data: void) => {
this.snackBar.open('Configuration deleted !!!', 'INFO', { duration: 5000 });
this.conf = undefined;
});
}
}
openWfHistoryDialog(wf: WfHistoryEntry): void {
const wfDialogRef = this.dialog.open(WfHistoryDialog, {
data: wf
});
}
}

View File

@ -17,7 +17,7 @@
<span><b>Count :</b> {{historyDatasource.filteredData.length}}</span> <span><b>Count :</b> {{historyDatasource.filteredData.length}}</span>
</p> </p>
<table mat-table [dataSource]="historyDatasource" matSort class="mat-elevation-z8"> <table mat-table [dataSource]="historyDatasource" matSort>
<ng-container matColumnDef="processId"> <ng-container matColumnDef="processId">
<th mat-header-cell *matHeaderCellDef style="width: 15%;" mat-sort-header <th mat-header-cell *matHeaderCellDef style="width: 15%;" mat-sort-header
@ -70,6 +70,6 @@
<!-- Row shown when there is no matching data. --> <!-- Row shown when there is no matching data. -->
<tr class="mat-row" *matNoDataRow> <tr class="mat-row" *matNoDataRow>
<td class="mat-cell" colspan="4" style="padding: 0 16px;">No data matching the filter "{{input.value}}"</td> <td class="mat-cell" colspan="7" style="padding: 0 16px;">No data matching the filter "{{input.value}}"</td>
</tr> </tr>
</table> </table>

View File

@ -3,7 +3,7 @@
<parent> <parent>
<groupId>eu.dnetlib.dhp</groupId> <groupId>eu.dnetlib.dhp</groupId>
<artifactId>libs</artifactId> <artifactId>libs</artifactId>
<version>3.3.3-SNAPSHOT</version> <version>3.4.1-SNAPSHOT</version>
<relativePath>../</relativePath> <relativePath>../</relativePath>
</parent> </parent>

View File

@ -3,7 +3,7 @@
<parent> <parent>
<groupId>eu.dnetlib.dhp</groupId> <groupId>eu.dnetlib.dhp</groupId>
<artifactId>libs</artifactId> <artifactId>libs</artifactId>
<version>3.3.3-SNAPSHOT</version> <version>3.4.1-SNAPSHOT</version>
<relativePath>../</relativePath> <relativePath>../</relativePath>
</parent> </parent>

View File

@ -4,7 +4,7 @@
<parent> <parent>
<groupId>eu.dnetlib.dhp</groupId> <groupId>eu.dnetlib.dhp</groupId>
<artifactId>apps</artifactId> <artifactId>apps</artifactId>
<version>3.3.3-SNAPSHOT</version> <version>3.4.1-SNAPSHOT</version>
<relativePath>../</relativePath> <relativePath>../</relativePath>
</parent> </parent>

View File

@ -36,6 +36,10 @@ public class WorkflowLogger {
} }
} }
public List<WfHistoryEntry> history(final String wfConfId) {
return wfHistoryEntryRepository.findByWfConfigurationIdOrderByEndDateDesc(wfConfId);
}
public WfHistoryEntry getLog(final String processId) { public WfHistoryEntry getLog(final String processId) {
return wfHistoryEntryRepository.findById(processId).get(); return wfHistoryEntryRepository.findById(processId).get();
} }

View File

@ -12,5 +12,7 @@ public interface WfHistoryEntryRepository extends JpaRepository<WfHistoryEntry,
List<WfHistoryEntry> findByEndDateBetweenOrderByEndDateDesc(LocalDateTime start, LocalDateTime end); List<WfHistoryEntry> findByEndDateBetweenOrderByEndDateDesc(LocalDateTime start, LocalDateTime end);
List<WfHistoryEntry> findByWfConfigurationIdOrderByEndDateDesc(String id);
Optional<WfHistoryEntry> findFirstByWfConfigurationIdOrderByEndDateDesc(String id); Optional<WfHistoryEntry> findFirstByWfConfigurationIdOrderByEndDateDesc(String id);
} }

View File

@ -3,7 +3,7 @@
<parent> <parent>
<groupId>eu.dnetlib.dhp</groupId> <groupId>eu.dnetlib.dhp</groupId>
<artifactId>libs</artifactId> <artifactId>libs</artifactId>
<version>3.3.3-SNAPSHOT</version> <version>3.4.1-SNAPSHOT</version>
<relativePath>../</relativePath> <relativePath>../</relativePath>
</parent> </parent>