From 091e125d8048419db11e074934a9fbf6eb142a45 Mon Sep 17 00:00:00 2001
From: Alicia de Dios Fuente <Alicia.DeDiosFuente@unige.ch>
Date: Wed, 29 Jan 2020 17:45:06 +0100
Subject: [PATCH] feat: added reports info for JobExecutionReport

---
 package-lock.json                             |  15 +-
 .../aip-detail-edit.routable.html             |   2 +
 .../aip/stores/aip-aip/aip-aip.state.ts       |   9 --
 .../job-execution-list.container.ts           |  14 +-
 .../job-execution-detail.dialog.ts            |   2 +-
 .../job-execution-form.presentational.html    | 105 ++++++++++++
 .../job-execution-form.presentational.ts      |  78 +++++++++
 .../job-detail-edit.routable.html             |  55 ++++---
 .../job-detail-edit.routable.ts               |  46 +++++-
 .../job-execution-detail.routable.html        |  30 ++++
 .../job-execution-detail.routable.scss        |   7 +
 .../job-execution-detail.routable.ts          | 153 ++++++++++++++++++
 .../preservation/job/helper/job.helper.ts     |  26 +++
 .../job/preservation-job-routing.module.ts    |   9 ++
 .../job/preservation-job.module.ts            |   4 +
 .../preservation-job-execution.action.ts      |  24 ++-
 .../preservation-job-execution.state.ts       |  85 +++++++++-
 .../job/stores/preservation-job.state.ts      |   4 +-
 src/app/shared/enums/api-action.enum.ts       |   2 +-
 .../shared/enums/api-resource-name.enum.ts    |   1 +
 .../business/job-report-aip-status.enum.ts    |   5 +
 src/app/shared/enums/local-state.enum.ts      |   5 +-
 src/app/shared/enums/routes.enum.ts           |   3 +
 .../job-execution-report-line.model.ts        |  10 ++
 .../business/job-execution-report.model.ts    |  10 ++
 .../models/business/job-execution.model.ts    |   3 +-
 src/app/shared/stores/report/report.action.ts |   0
 src/app/shared/stores/report/report.state.ts  |   0
 src/assets/i18n/de.json                       |  39 ++++-
 src/assets/i18n/en.json                       |  34 +++-
 src/assets/i18n/fr.json                       |  34 +++-
 31 files changed, 752 insertions(+), 62 deletions(-)
 create mode 100644 src/app/features/preservation/job/components/presentationals/job-execution-form/job-execution-form.presentational.html
 create mode 100644 src/app/features/preservation/job/components/presentationals/job-execution-form/job-execution-form.presentational.ts
 create mode 100644 src/app/features/preservation/job/components/routables/job-execution-detail/job-execution-detail.routable.html
 create mode 100644 src/app/features/preservation/job/components/routables/job-execution-detail/job-execution-detail.routable.scss
 create mode 100644 src/app/features/preservation/job/components/routables/job-execution-detail/job-execution-detail.routable.ts
 create mode 100644 src/app/shared/enums/business/job-report-aip-status.enum.ts
 create mode 100644 src/app/shared/models/business/job-execution-report-line.model.ts
 create mode 100644 src/app/shared/models/business/job-execution-report.model.ts
 create mode 100644 src/app/shared/stores/report/report.action.ts
 create mode 100644 src/app/shared/stores/report/report.state.ts

diff --git a/package-lock.json b/package-lock.json
index f857bf8f2..24095876b 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1559,7 +1559,7 @@
         "@angular/compiler": "^8.1.3",
         "boxen": "^4.1.0",
         "colorette": "^1.1.0",
-        "flat": "git://github.com/lenchvolodymyr/flat.git#ffe77efe8c33bc80ffb2f7a465537610dea4f611",
+        "flat": "git://github.com/lenchvolodymyr/flat.git#ffe77ef",
         "gettext-parser": "^4.0.1",
         "glob": "^7.1.4",
         "mkdirp": "^0.5.1",
@@ -5563,7 +5563,8 @@
         },
         "ansi-regex": {
           "version": "2.1.1",
-          "bundled": true
+          "bundled": true,
+          "optional": true
         },
         "aproba": {
           "version": "1.2.0",
@@ -5928,7 +5929,8 @@
         },
         "safe-buffer": {
           "version": "5.1.2",
-          "bundled": true
+          "bundled": true,
+          "optional": true
         },
         "safer-buffer": {
           "version": "2.1.2",
@@ -5976,6 +5978,7 @@
         "strip-ansi": {
           "version": "3.0.1",
           "bundled": true,
+          "optional": true,
           "requires": {
             "ansi-regex": "^2.0.0"
           }
@@ -6014,11 +6017,13 @@
         },
         "wrappy": {
           "version": "1.0.2",
-          "bundled": true
+          "bundled": true,
+          "optional": true
         },
         "yallist": {
           "version": "3.0.3",
-          "bundled": true
+          "bundled": true,
+          "optional": true
         }
       }
     },
diff --git a/src/app/features/preservation/aip/components/routables/aip-detail-edit/aip-detail-edit.routable.html b/src/app/features/preservation/aip/components/routables/aip-detail-edit/aip-detail-edit.routable.html
index bf3f0c773..d7fbe9189 100644
--- a/src/app/features/preservation/aip/components/routables/aip-detail-edit/aip-detail-edit.routable.html
+++ b/src/app/features/preservation/aip/components/routables/aip-detail-edit/aip-detail-edit.routable.html
@@ -1,3 +1,5 @@
+<script src="../../../aip-routing.module.ts"></script>
+<script src="../../../../job/preservation-job-routing.module.ts"></script>
 <dlcm-shared-banner-edit-mode [isEdit]="isEdit"></dlcm-shared-banner-edit-mode>
 
 <dlcm-button-toolbar-detail [mode]="'detail'"
diff --git a/src/app/features/preservation/aip/stores/aip-aip/aip-aip.state.ts b/src/app/features/preservation/aip/stores/aip-aip/aip-aip.state.ts
index 805a812fc..2aeb828b7 100644
--- a/src/app/features/preservation/aip/stores/aip-aip/aip-aip.state.ts
+++ b/src/app/features/preservation/aip/stores/aip-aip/aip-aip.state.ts
@@ -4,7 +4,6 @@ import {ApiActionEnum} from "@app/shared/enums/api-action.enum";
 import {ApiResourceNameEnum} from "@app/shared/enums/api-resource-name.enum";
 import {ArchivalStorageResourceApiEnum} from "@app/shared/enums/api.enum";
 import {LocalStateEnum} from "@app/shared/enums/local-state.enum";
-import {Navigate} from "@ngxs/router-plugin";
 import {
   Action,
   Actions,
@@ -13,15 +12,8 @@ import {
   StateContext,
   Store,
 } from "@ngxs/store";
-import {AipHelper} from "@preservation/aip/helpers/aip.helper";
 import {AipExtended} from "@preservation/aip/models/aip-extended.model";
 import {PreservationAipAction} from "@preservation/aip/stores/aip.action";
-import {
-  AppRoutesEnum,
-  PreservationPlanningRoutesEnum,
-  RoutesEnum,
-  urlSeparator,
-} from "@shared/enums/routes.enum";
 import {DownloadService} from "@shared/services/download.service";
 import {
   PreservationAipAipAction,
@@ -32,7 +24,6 @@ import {
   PreservationAipAipStatusHistoryStateModel,
 } from "@preservation/aip/stores/aip-aip/status-history/aip-aip-status-history.state";
 import {defaultStatusHistoryInitValue} from "@shared/stores/status-history/status-history.state";
-import {saveAs} from "file-saver";
 import {
   ApiService,
   CompositionState,
diff --git a/src/app/features/preservation/job/components/containers/job-execution-list/job-execution-list.container.ts b/src/app/features/preservation/job/components/containers/job-execution-list/job-execution-list.container.ts
index 65484c55c..01414c86e 100644
--- a/src/app/features/preservation/job/components/containers/job-execution-list/job-execution-list.container.ts
+++ b/src/app/features/preservation/job/components/containers/job-execution-list/job-execution-list.container.ts
@@ -12,6 +12,7 @@ import {PreservationJobAction} from "@app/features/preservation/job/stores/prese
 import {PreservationJobState} from "@app/features/preservation/job/stores/preservation-job.state";
 import {PreservationJob} from "@app/generated-api";
 import {SharedAbstractPresentational} from "@app/shared/components/presentationals/shared-abstract/shared-abstract.presentational";
+import {Navigate} from "@ngxs/router-plugin";
 import {
   Actions,
   ofActionCompleted,
@@ -20,8 +21,13 @@ import {
 import {JobStatusEnum} from "@shared/enums/business/job-status.enum";
 import {DataTableComponentEnum} from "@shared/enums/data-table-component.enum";
 import {FieldTypeEnum} from "@shared/enums/field-type.enum";
-import {AppRoutesEnum} from "@shared/enums/routes.enum";
 import {PollingHelper} from "@shared/helpers/polling.helper";
+import {
+  AppRoutesEnum,
+  PreservationPlanningRoutesEnum,
+  RoutesEnum,
+  urlSeparator,
+} from "@shared/enums/routes.enum";
 import {JobExecution} from "@shared/models/business/job-execution.model";
 import {DataTableColumns} from "@shared/models/data-table-columns.model";
 import {Observable} from "rxjs";
@@ -191,8 +197,8 @@ export class JobExecutionListContainer extends SharedAbstractPresentational impl
   }
 
   showExecutionDetail(jobExecution: JobExecution): void {
-    const dialogRef = this._dialog.open(JobExecutionDetailDialog, {
-      data: jobExecution,
-    });
+    const pathExecution = RoutesEnum.preservation + AppRoutesEnum.separator + PreservationPlanningRoutesEnum.job + AppRoutesEnum.separator + PreservationPlanningRoutesEnum.jobDetail + AppRoutesEnum.separator + this._resId + AppRoutesEnum.separator + PreservationPlanningRoutesEnum.preservationPlanningExecution;
+    const path = [pathExecution, jobExecution.resId];
+    this._store.dispatch(new Navigate(path));
   }
 }
diff --git a/src/app/features/preservation/job/components/dialogs/job-execution-detail/job-execution-detail.dialog.ts b/src/app/features/preservation/job/components/dialogs/job-execution-detail/job-execution-detail.dialog.ts
index 1ce54a18c..95d55ce54 100644
--- a/src/app/features/preservation/job/components/dialogs/job-execution-detail/job-execution-detail.dialog.ts
+++ b/src/app/features/preservation/job/components/dialogs/job-execution-detail/job-execution-detail.dialog.ts
@@ -91,7 +91,7 @@ export class JobExecutionDetailDialog extends SharedAbstractContainer implements
   }
 
   resume(): void {
-    this._store.dispatch(new PreservationJobExecutionAction.Resume(this.jobExecution.jobId, this.jobExecution));
+    this._store.dispatch(new PreservationJobExecutionAction.Resume(this.jobExecution.jobId, this.jobExecution.resId));
     this.subscribe(this._actions$.pipe(ofActionCompleted(PreservationJobExecutionAction.ResumeSuccess))
       .pipe(
         tap(result => {
diff --git a/src/app/features/preservation/job/components/presentationals/job-execution-form/job-execution-form.presentational.html b/src/app/features/preservation/job/components/presentationals/job-execution-form/job-execution-form.presentational.html
new file mode 100644
index 000000000..4fd919a0b
--- /dev/null
+++ b/src/app/features/preservation/job/components/presentationals/job-execution-form/job-execution-form.presentational.html
@@ -0,0 +1,105 @@
+<form [formGroup]="form"
+>
+      <mat-form-field *ngIf="getFormControl(formDefinition.status) as fd">
+        <mat-label>{{'preservation.jobExecution.form.status' | translate}}</mat-label>
+        <mat-select [formControl]="fd"
+                    [required]="formValidationHelper.hasRequiredField(fd)"
+        >
+          <mat-option *ngFor="let executionStatus of listExecutionStatus"
+                      [value]="executionStatus.key"
+          >
+            {{executionStatus.value | translate}}
+          </mat-option>
+        </mat-select>
+      </mat-form-field>
+
+
+      <mat-form-field [matTooltip]="'preservation.jobExecution.form.statusMessage' | translate"
+                      [matTooltipPosition]="'left'"
+                      aria-label="publication date tooltip"
+                      matTooltipClass="tooltip"
+                      *ngIf="getFormControl(formDefinition.statusMessage) as fd"
+      >
+        <input [formControl]="fd"
+               matInput
+               [placeholder]="'preservation.jobExecution.statusMessage' | translate"
+               [required]="formValidationHelper.hasRequiredField(fd)"
+        >
+      </mat-form-field>
+
+      <mat-form-field [matTooltip]="'preservation.jobExecution.form.startDate' | translate"
+                      [matTooltipPosition]="'left'"
+                      matTooltipClass="tooltip"
+                      *ngIf="getFormControl(formDefinition.startDate) as fd"
+      >
+        <input [formControl]="fd"
+               matInput
+               [placeholder]="'preservation.jobExecution.startDate' | translate"
+               [required]="formValidationHelper.hasRequiredField(fd)"
+        >
+      </mat-form-field>
+
+      <mat-form-field [matTooltip]="'preservation.jobExecution.form.endDate' | translate"
+                      [matTooltipPosition]="'left'"
+                      aria-label="publication date tooltip"
+                      matTooltipClass="tooltip"
+                      *ngIf="getFormControl(formDefinition.endDate) as fd"
+      >
+        <input [formControl]="fd"
+               matInput
+               [placeholder]="'preservation.jobExecution.endDate' | translate"
+               [required]="formValidationHelper.hasRequiredField(fd)"
+        >
+      </mat-form-field>
+
+<!--    <div class="right-part">-->
+
+<!--      <mat-form-field [matTooltip]="'preservation.jobExecution.form.total' | translate"-->
+<!--                      [matTooltipPosition]="'left'"-->
+<!--                      matTooltipClass="tooltip"-->
+<!--                      *ngIf="getFormControl(formDefinition.totalItems) as fd"-->
+<!--      >-->
+<!--        <input [formControl]="fd"-->
+<!--               matInput-->
+<!--               [placeholder]="'preservation.jobExecution.total' | translate"-->
+<!--               [required]="formValidationHelper.hasRequiredField(fd)"-->
+<!--        >-->
+<!--      </mat-form-field>-->
+
+<!--      <mat-form-field [matTooltip]="'preservation.jobExecution.form.processed' | translate"-->
+<!--                      [matTooltipPosition]="'left'"-->
+<!--                      matTooltipClass="tooltip"-->
+<!--                      *ngIf="getFormControl(formDefinition.processedItems) as fd"-->
+<!--      >-->
+<!--        <input [formControl]="fd"-->
+<!--               matInput-->
+<!--               [placeholder]="'preservation.jobExecution.processed' | translate"-->
+<!--               [required]="formValidationHelper.hasRequiredField(fd)"-->
+<!--        >-->
+<!--      </mat-form-field>-->
+
+<!--      <mat-form-field [matTooltip]="'preservation.jobExecution.form.ignored' | translate"-->
+<!--                      [matTooltipPosition]="'left'"-->
+<!--                      matTooltipClass="tooltip"-->
+<!--                      *ngIf="getFormControl(formDefinition.ignoredItems) as fd"-->
+<!--      >-->
+<!--        <input [formControl]="fd"-->
+<!--               matInput-->
+<!--               [placeholder]="'preservation.jobExecution.ignored' | translate"-->
+<!--               [required]="formValidationHelper.hasRequiredField(fd)"-->
+<!--        >-->
+<!--      </mat-form-field>-->
+
+<!--      <mat-form-field [matTooltip]="'preservation.jobExecution.form.inError' | translate"-->
+<!--                      [matTooltipPosition]="'left'"-->
+<!--                      matTooltipClass="tooltip"-->
+<!--                      *ngIf="getFormControl(formDefinition.inErrorItems) as fd"-->
+<!--      >-->
+<!--        <input [formControl]="fd"-->
+<!--               matInput-->
+<!--               [placeholder]="'preservation.jobExecution.inError' | translate"-->
+<!--               [required]="formValidationHelper.hasRequiredField(fd)"-->
+<!--        >-->
+<!--      </mat-form-field>-->
+<!--    </div>-->
+</form>
diff --git a/src/app/features/preservation/job/components/presentationals/job-execution-form/job-execution-form.presentational.ts b/src/app/features/preservation/job/components/presentationals/job-execution-form/job-execution-form.presentational.ts
new file mode 100644
index 000000000..10bb49cc0
--- /dev/null
+++ b/src/app/features/preservation/job/components/presentationals/job-execution-form/job-execution-form.presentational.ts
@@ -0,0 +1,78 @@
+import {
+  ChangeDetectionStrategy,
+  ChangeDetectorRef,
+  Component,
+} from "@angular/core";
+import {
+  FormBuilder,
+  Validators,
+} from "@angular/forms";
+import {JobHelper} from "@preservation/job/helper/job.helper";
+import {SharedAbstractFormPresentational} from "@shared/components/presentationals/shared-abstract-form/shared-abstract-form.presentational";
+import {BaseFormDefinition} from "@shared/models/base-form-definition.model";
+import {JobExecution} from "@shared/models/business/job-execution.model";
+import {
+  KeyValue,
+  PropertyName,
+  SolidifyValidator,
+} from "solidify-frontend";
+
+@Component({
+  selector: "dlcm-job-execution-form",
+  templateUrl: "./job-execution-form.presentational.html",
+  styleUrls: ["../../../../../../shared/components/presentationals/shared-abstract-form/shared-abstract-form.presentational.scss"],
+  changeDetection: ChangeDetectionStrategy.OnPush,
+})
+export class JobExecutionFormPresentational extends SharedAbstractFormPresentational<JobExecution> {
+  formDefinition: FormComponentFormDefinition = new FormComponentFormDefinition();
+
+  listExecutionStatus: KeyValue[] = JobHelper.getExecutionStatus();
+
+
+  constructor(protected readonly _changeDetectorRef: ChangeDetectorRef,
+              private readonly _fb: FormBuilder) {
+    super(_changeDetectorRef);
+  }
+
+  protected bindFormTo(jobExecution: JobExecution): void {
+    this.form = this._fb.group({
+      [this.formDefinition.status]: [jobExecution.status, [Validators.required, SolidifyValidator]],
+      [this.formDefinition.statusMessage]: [jobExecution.statusMessage, [SolidifyValidator]],
+      [this.formDefinition.startDate]: [jobExecution.startDate, [Validators.required, SolidifyValidator]],
+      [this.formDefinition.endDate]: [jobExecution.endDate, [Validators.required, SolidifyValidator]],
+      [this.formDefinition.totalItems]: [jobExecution.ignoredItems + jobExecution.processedItems + jobExecution.inErrorItems, [Validators.required, SolidifyValidator]],
+      [this.formDefinition.ignoredItems]: [jobExecution.ignoredItems, [Validators.required, SolidifyValidator]],
+      [this.formDefinition.processedItems]: [jobExecution.processedItems, [Validators.required, SolidifyValidator]],
+      [this.formDefinition.inErrorItems]: [jobExecution.inErrorItems, [Validators.required, SolidifyValidator]],
+    });
+  }
+
+  protected initNewForm(): void {
+    this.form = this._fb.group({
+      [this.formDefinition.status]: ["", [Validators.required, SolidifyValidator]],
+      [this.formDefinition.statusMessage]: ["", [SolidifyValidator]],
+      [this.formDefinition.startDate]: ["", [Validators.required, SolidifyValidator]],
+      [this.formDefinition.endDate]: ["", [Validators.required, SolidifyValidator]],
+      [this.formDefinition.totalItems]: ["", [Validators.required, SolidifyValidator]],
+      [this.formDefinition.ignoredItems]: ["", [Validators.required, SolidifyValidator]],
+      [this.formDefinition.processedItems]: ["", [Validators.required, SolidifyValidator]],
+      [this.formDefinition.inErrorItems]: ["", [Validators.required, SolidifyValidator]],
+    });
+  }
+
+  protected treatmentBeforeSubmit(model: JobExecution): JobExecution {
+    return undefined;
+  }
+
+}
+
+class FormComponentFormDefinition extends BaseFormDefinition {
+  @PropertyName() status: string;
+  @PropertyName() statusMessage: string;
+  @PropertyName() startDate: string;
+  @PropertyName() endDate: string;
+  @PropertyName() totalItems: string;
+  @PropertyName() ignoredItems: string;
+  @PropertyName() processedItems: string;
+  @PropertyName() inErrorItems: string;
+}
diff --git a/src/app/features/preservation/job/components/routables/job-detail-edit/job-detail-edit.routable.html b/src/app/features/preservation/job/components/routables/job-detail-edit/job-detail-edit.routable.html
index 272b4285d..5a87f9fe1 100644
--- a/src/app/features/preservation/job/components/routables/job-detail-edit/job-detail-edit.routable.html
+++ b/src/app/features/preservation/job/components/routables/job-detail-edit/job-detail-edit.routable.html
@@ -1,26 +1,33 @@
-<dlcm-button-toolbar-detail [mode]="isEdit ? 'edit' : 'detail'"
-                            [currentModel]="currentObs | async"
-                            (editChange)="edit()"
-                            (deleteChange)="delete()"
-                            (backToDetailChange)="backToDetail()"
-                            (backToListChange)="backToList()"
-                            [listExtraButtons]="listExtraButtons()"
->
-</dlcm-button-toolbar-detail>
+<router-outlet></router-outlet>
 
-<div class="wrapper"
-     [dlcmSpinner]="isLoadingWithDependencyObs | async"
->
-  <dlcm-job-form #formPresentational
-                 *ngIf="isReadyToBeDisplayedObs | async"
-                 [model]="currentObs| async"
-                 [readonly]="!isEdit"
-                 (submitChange)="update($event)"
-                 (dirtyChange)="updateCanDeactivate($event)"
-  ></dlcm-job-form>
-</div>
+<ng-template [ngIf]="this.preservationJob">
+  <dlcm-shared-button-id [resource]="currentObs | async"></dlcm-shared-button-id>
+
+  <dlcm-button-toolbar-detail [mode]="isEdit ? 'edit' : 'detail'"
+                              [currentModel]="currentObs | async"
+                              (editChange)="edit()"
+                              (deleteChange)="delete()"
+                              (backToDetailChange)="backToDetail()"
+                              (backToListChange)="backToList()"
+                              [listExtraButtons]="listExtraButtons()"
+  >
+  </dlcm-button-toolbar-detail>
+
+  <div class="wrapper"
+       [dlcmSpinner]="isLoadingWithDependencyObs | async"
+  >
+    <dlcm-job-form #formPresentational
+                   *ngIf="isReadyToBeDisplayedObs | async"
+                   [model]="currentObs| async"
+                   [readonly]="!isEdit"
+                   (submitChange)="update($event)"
+                   (dirtyChange)="updateCanDeactivate($event)"
+    ></dlcm-job-form>
+  </div>
+
+  <dlcm-job-execution-container *ngIf="!isEdit"
+                                #jobExecutionList
+  >
+  </dlcm-job-execution-container>
+</ng-template>
 
-<dlcm-job-execution-container *ngIf="!isEdit"
-                              #jobExecutionList
->
-</dlcm-job-execution-container>
diff --git a/src/app/features/preservation/job/components/routables/job-detail-edit/job-detail-edit.routable.ts b/src/app/features/preservation/job/components/routables/job-detail-edit/job-detail-edit.routable.ts
index dfb9124ec..79e8136ab 100644
--- a/src/app/features/preservation/job/components/routables/job-detail-edit/job-detail-edit.routable.ts
+++ b/src/app/features/preservation/job/components/routables/job-detail-edit/job-detail-edit.routable.ts
@@ -1,10 +1,15 @@
 import {
   ChangeDetectorRef,
   Component,
+  OnInit,
   ViewChild,
 } from "@angular/core";
 import {MatDialog} from "@angular/material";
-import {ActivatedRoute} from "@angular/router";
+import {
+  ActivatedRoute,
+  Router,
+  RouterStateSnapshot,
+} from "@angular/router";
 import {JobExecutionListContainer} from "@app/features/preservation/job/components/containers/job-execution-list/job-execution-list.container";
 import {
   PreservationJobAction,
@@ -23,9 +28,18 @@ import {
 } from "@ngxs/store";
 import {SharedAbstractDetailEditCommonRoutable} from "@shared/components/routables/shared-abstract-detail-edit-common/shared-abstract-detail-edit-common.routable";
 import {LocalStateEnum} from "@shared/enums/local-state.enum";
+import {
+  PreservationPlanningRoutesEnum,
+} from "@shared/enums/routes.enum";
 import {JobRecurrence} from "@shared/models/business/job-recurrence.model";
 import {ExtraButtonToolbar} from "@shared/models/extra-button-toolbar.model";
-import {Observable} from "rxjs";
+import {LocalStateModel} from "@shared/models/local-state.model";
+import {
+  Observable,
+} from "rxjs";
+import {
+  tap,
+} from "rxjs/operators";
 import {TRANSLATE} from "solidify-frontend";
 import JobRecurrenceEnum = JobRecurrence.JobRecurrenceEnum;
 
@@ -34,21 +48,26 @@ import JobRecurrenceEnum = JobRecurrence.JobRecurrenceEnum;
   templateUrl: "./job-detail-edit.routable.html",
   styleUrls: ["./job-detail-edit.routable.scss"],
 })
-export class JobDetailEditRoutable extends SharedAbstractDetailEditCommonRoutable<PreservationJob, PreservationJobStateModel> {
+export class JobDetailEditRoutable extends SharedAbstractDetailEditCommonRoutable<PreservationJob, PreservationJobStateModel> implements OnInit{
   @Select(PreservationJobState.isLoadingWithDependency) isLoadingWithDependencyObs: Observable<boolean>;
   @Select(PreservationJobState.isReadyToBeDisplayed) isReadyToBeDisplayedObs: Observable<boolean>;
+  @Select((state: LocalStateModel) => state.router.state) urlStateObs: Observable<RouterStateSnapshot>;
+
 
   @ViewChild("jobExecutionList", {static: false})
   readonly jobExecutionList: JobExecutionListContainer;
 
   readonly KEY_PARAM_NAME: keyof PreservationJob & string = "name";
+  preservationJob: boolean | undefined = undefined;
 
   get jobRecurrenceEnum(): typeof JobRecurrenceEnum {
     return JobRecurrenceEnum;
   }
 
-  constructor(protected _store: Store,
+  constructor(
+              protected _store: Store,
               protected _route: ActivatedRoute,
+              protected _router: Router,
               protected readonly _actions$: Actions,
               protected readonly _changeDetector: ChangeDetectorRef,
               public _dialog: MatDialog) {
@@ -58,6 +77,25 @@ export class JobDetailEditRoutable extends SharedAbstractDetailEditCommonRoutabl
   getSubResourceWithParentId(id: string): void {
   }
 
+  ngOnInit(): void {
+    super.ngOnInit();
+    this.subscribe(this.urlStateObs
+      .pipe(
+        tap( urLState => {
+          if (urLState) {
+            const url = urLState.url;
+            console.error(url);
+            if (url.includes(PreservationPlanningRoutesEnum.preservationPlanningExecution)) {
+              this.preservationJob = false;
+            }
+            else {
+              this.preservationJob = true;
+            }
+          }
+        })
+      ));
+  }
+
   start(): void {
     this.subscribe(this._actions$.pipe(ofActionCompleted(PreservationJobAction.StartSuccess)),
       result => {
diff --git a/src/app/features/preservation/job/components/routables/job-execution-detail/job-execution-detail.routable.html b/src/app/features/preservation/job/components/routables/job-execution-detail/job-execution-detail.routable.html
new file mode 100644
index 000000000..91b94762b
--- /dev/null
+++ b/src/app/features/preservation/job/components/routables/job-execution-detail/job-execution-detail.routable.html
@@ -0,0 +1,30 @@
+<dlcm-shared-button-id [resource]="currentObs | async"></dlcm-shared-button-id>
+
+<dlcm-button-toolbar-detail [mode]="'detail'"
+                            [editAvailable]="false"
+                            [deleteAvailable]="false"
+                            [currentModel]="currentObs | async"
+                            (backToListChange)="backToList()"
+                            [listExtraButtons]="listExtraButtons()"
+>
+</dlcm-button-toolbar-detail>
+
+<div class="wrapper"
+     [dlcmSpinner]="isLoadingObs | async"
+>
+  <dlcm-job-execution-form #formPresentational
+                 *ngIf="isReadyToBeDisplayedObs | async"
+                 [model]="currentObs| async"
+                 [readonly]="true"
+  ></dlcm-job-execution-form>
+
+  <h1>{{'preservation.jobExecution.report.title' | translate}}</h1>
+
+  <dlcm-shared-data-table [columns]="columns"
+                          [datas]="listReportObs | async"
+                          (selectChange)="showExecutionDetail($event)"
+                          >
+  </dlcm-shared-data-table>
+</div>
+
+
diff --git a/src/app/features/preservation/job/components/routables/job-execution-detail/job-execution-detail.routable.scss b/src/app/features/preservation/job/components/routables/job-execution-detail/job-execution-detail.routable.scss
new file mode 100644
index 000000000..6c4bb3918
--- /dev/null
+++ b/src/app/features/preservation/job/components/routables/job-execution-detail/job-execution-detail.routable.scss
@@ -0,0 +1,7 @@
+@import "../../../../../../shared/components/routables/shared-abstract-detail-edit-common/shared-abstract-detail-edit-common.routable.scss";
+
+:host {
+  .wrapper {
+    min-height: 100px;
+  }
+}
diff --git a/src/app/features/preservation/job/components/routables/job-execution-detail/job-execution-detail.routable.ts b/src/app/features/preservation/job/components/routables/job-execution-detail/job-execution-detail.routable.ts
new file mode 100644
index 000000000..0534c27cc
--- /dev/null
+++ b/src/app/features/preservation/job/components/routables/job-execution-detail/job-execution-detail.routable.ts
@@ -0,0 +1,153 @@
+import {
+  Component,
+  OnInit,
+} from "@angular/core";
+import {ActivatedRoute} from "@angular/router";
+import {Navigate} from "@ngxs/router-plugin";
+import {
+  Actions,
+  ofActionCompleted,
+  Select,
+  Store,
+} from "@ngxs/store";
+import {PreservationJobExecutionAction} from "@preservation/job/stores/preservation-job-execution/preservation-job-execution.action";
+import {PreservationJobExecutionState} from "@preservation/job/stores/preservation-job-execution/preservation-job-execution.state";
+import {SharedAbstractRoutable} from "@shared/components/routables/shared-abstract/shared-abstract.routable";
+import {JobStatusEnum} from "@shared/enums/business/job-status.enum";
+import {FieldTypeEnum} from "@shared/enums/field-type.enum";
+import {
+  AppRoutesEnum,
+  PreservationPlanningRoutesEnum,
+  RoutesEnum,
+} from "@shared/enums/routes.enum";
+import {JobExecutionReport} from "@shared/models/business/job-execution-report.model";
+import {JobExecution} from "@shared/models/business/job-execution.model";
+import {DataTableColumns} from "@shared/models/data-table-columns.model";
+import {ExtraButtonToolbar} from "@shared/models/extra-button-toolbar.model";
+import {LocalStateModel} from "@shared/models/local-state.model";
+import {Observable} from "rxjs";
+import {tap} from "rxjs/operators";
+import {
+  BaseResource,
+  CompositionState,
+  OrderEnum,
+  TRANSLATE,
+} from "solidify-frontend";
+
+@Component({
+  selector: "dlcm-job-execution-detail-routable",
+  templateUrl: "./job-execution-detail.routable.html",
+  styleUrls: ["./job-execution-detail.routable.scss"],
+})
+export class JobExecutionDetailRoutable extends SharedAbstractRoutable implements OnInit {
+
+  @Select((state: LocalStateModel) => state.preservation.preservation_job.preservation_job_execution.current) currentObs: Observable<JobExecution>;
+  @Select(PreservationJobExecutionState.isReadyToBeDisplayed) isReadyToBeDisplayedObs: Observable<boolean>;
+  @Select(PreservationJobExecutionState.isLoading) isLoadingObs: Observable<boolean>;
+  @Select(PreservationJobExecutionState.listReport) listReportObs: Observable<JobExecutionReport[]>;
+
+  columns: DataTableColumns<BaseResource & JobExecutionReport>[] = [
+    {
+      field: "executionNumber",
+      header: TRANSLATE("preservation.jobExecution.report.table.header.executionNumber"),
+      type: FieldTypeEnum.string,
+      order: OrderEnum.descending,
+      isFilterable: false,
+      isSortable: true,
+    },
+    {
+      field: "processedItems",
+      header: TRANSLATE("preservation.jobExecution.report.table.header.processedItems"),
+      type: FieldTypeEnum.string,
+      order: OrderEnum.none,
+      isFilterable: false,
+      isSortable: false,
+    },
+    {
+      field: "ignoredItems",
+      header: TRANSLATE("preservation.jobExecution.report.table.header.ignoredItems"),
+      type: FieldTypeEnum.string,
+      order: OrderEnum.none,
+      isFilterable: false,
+      isSortable: false,
+    },
+    {
+      field: "inErrorItems",
+      header: TRANSLATE("preservation.jobExecution.report.table.header.inErrorItems"),
+      type: FieldTypeEnum.string,
+      order: OrderEnum.none,
+      isFilterable: false,
+      isSortable: false,
+    },
+  ];
+
+  private _preservationJobId: string;
+  private _resId: string;
+
+  constructor(private readonly _store: Store,
+              private readonly _route: ActivatedRoute,
+              private readonly _actions$: Actions) {
+    super();
+    this.retrieveCurrentModelWithUrl();
+  }
+
+  protected retrieveCurrentModelWithUrl(): void {
+    this.retrieveResIdFromUrl();
+    this._store.dispatch(new PreservationJobExecutionAction.GetById(this._preservationJobId, this._resId));
+  }
+
+  protected retrieveResIdFromUrl(): void {
+    this._resId = this._route.snapshot.paramMap.get(AppRoutesEnum.paramIdExecutionWithoutPrefixParam);
+    this._preservationJobId = this._route.snapshot.parent.paramMap.get(AppRoutesEnum.paramIdWithoutPrefixParam);
+  }
+
+  ngOnInit(): void {
+    super.ngOnInit();
+  }
+
+  backToList(): void {
+    const pathExecution = RoutesEnum.preservation + AppRoutesEnum.separator + PreservationPlanningRoutesEnum.job + AppRoutesEnum.separator + PreservationPlanningRoutesEnum.jobDetail ;
+    const path = [pathExecution, this._preservationJobId];
+    this._store.dispatch(new Navigate(path));
+  }
+
+  listExtraButtons(): ExtraButtonToolbar<JobExecution>[] {
+    return [
+      {
+        color: "primary",
+        icon: "play_arrow",
+        labelToTranslate: TRANSLATE("preservation.jobExecution.button.resume"),
+        callback: () => this.resume(),
+        displayCondition: (resource) => resource && (resource.status === JobStatusEnum.IN_ERROR),
+        order: 31,
+      },
+      {
+        color: "accent",
+        icon: "refresh",
+        labelToTranslate: TRANSLATE("preservation.jobExecution.button.refresh"),
+        callback: () => this.refresh(),
+        order: 41,
+      },
+    ];
+  }
+
+  private resume(): void {
+    this._store.dispatch(new PreservationJobExecutionAction.Resume(this._preservationJobId, this._resId));
+    this.subscribe(this._actions$.pipe(ofActionCompleted(PreservationJobExecutionAction.ResumeSuccess))
+      .pipe(
+        tap(result => {
+          if (result.result.successful) {
+            this.refresh();
+          }
+        }),
+      ));
+  }
+
+  showExecutionDetail($event: JobExecutionReport): void {
+    console.error("DIALOG OPEN HERE", $event);
+  }
+
+  private refresh(): void {
+    this._store.dispatch(new PreservationJobExecutionAction.GetById(this._preservationJobId, this._resId));
+  }
+}
diff --git a/src/app/features/preservation/job/helper/job.helper.ts b/src/app/features/preservation/job/helper/job.helper.ts
index 9a830e941..0b5a5ceef 100644
--- a/src/app/features/preservation/job/helper/job.helper.ts
+++ b/src/app/features/preservation/job/helper/job.helper.ts
@@ -1,4 +1,5 @@
 import {PreservationJob} from "@app/generated-api";
+import {JobStatusEnum} from "@shared/enums/business/job-status.enum";
 import {
   KeyValue,
   TRANSLATE,
@@ -157,4 +158,29 @@ export class JobHelper {
       },
     ];
   }
+
+  static getExecutionStatus(): KeyValue[] {
+    return[
+      {
+        key: JobStatusEnum.IN_PROGRESS,
+        value: TRANSLATE("preservation.jobExecution.jobStatusEnum.inProgress"),
+      },
+      {
+        key: JobStatusEnum.COMPLETED,
+        value: TRANSLATE("preservation.jobExecution.jobStatusEnum.completed"),
+      },
+      {
+        key: JobStatusEnum.READY,
+        value: TRANSLATE("preservation.jobExecution.jobStatusEnum.ready"),
+      },
+      {
+        key: JobStatusEnum.PAUSED,
+        value: TRANSLATE("preservation.jobExecution.jobStatusEnum.paused"),
+      },
+      {
+        key: JobStatusEnum.IN_ERROR,
+        value: TRANSLATE("preservation.jobExecution.jobStatusEnum.inError"),
+      }
+    ];
+  }
 }
diff --git a/src/app/features/preservation/job/preservation-job-routing.module.ts b/src/app/features/preservation/job/preservation-job-routing.module.ts
index 866549ffe..daddb9f90 100644
--- a/src/app/features/preservation/job/preservation-job-routing.module.ts
+++ b/src/app/features/preservation/job/preservation-job-routing.module.ts
@@ -5,6 +5,7 @@ import {JobDetailEditRoutable} from "@app/features/preservation/job/components/r
 import {JobListRoutable} from "@app/features/preservation/job/components/routables/job-list/job-list.routable";
 import {PreservationJobState} from "@app/features/preservation/job/stores/preservation-job.state";
 import {DlcmRoutes} from "@app/shared/models/dlcm-route.model";
+import {JobExecutionDetailRoutable} from "@preservation/job/components/routables/job-execution-detail/job-execution-detail.routable";
 import {
   AppRoutesEnum,
   PreservationPlanningRoutesEnum,
@@ -34,6 +35,13 @@ const routes: DlcmRoutes = [
       breadcrumbMemoizedSelector: PreservationJobState.currentTitle,
     },
     children: [
+      {
+        path: PreservationPlanningRoutesEnum.preservationPlanningExecution + AppRoutesEnum.separator + AppRoutesEnum.paramIdExecution,
+        component: JobExecutionDetailRoutable,
+        data: {
+          breadcrumb: TRANSLATE("breadcrumb.preservation.job.execution"),
+        },
+      },
       {
         path: PreservationPlanningRoutesEnum.jobEdit,
         data: {
@@ -43,6 +51,7 @@ const routes: DlcmRoutes = [
       },
     ],
   },
+
 ];
 
 @NgModule({
diff --git a/src/app/features/preservation/job/preservation-job.module.ts b/src/app/features/preservation/job/preservation-job.module.ts
index efd8ca744..6a062c3e9 100644
--- a/src/app/features/preservation/job/preservation-job.module.ts
+++ b/src/app/features/preservation/job/preservation-job.module.ts
@@ -12,11 +12,14 @@ import {PreservationJobState} from "@app/features/preservation/job/stores/preser
 import {SharedModule} from "@app/shared/shared.module";
 import {TranslateModule} from "@ngx-translate/core";
 import {NgxsModule} from "@ngxs/store";
+import {JobExecutionFormPresentational} from "@preservation/job/components/presentationals/job-execution-form/job-execution-form.presentational";
+import {JobExecutionDetailRoutable} from "@preservation/job/components/routables/job-execution-detail/job-execution-detail.routable";
 
 const routables = [
   JobListRoutable,
   JobDetailEditRoutable,
   JobCreateRoutable,
+  JobExecutionDetailRoutable
 ];
 const containers = [
   JobExecutionListContainer,
@@ -27,6 +30,7 @@ const dialogs = [
 ];
 const presentationals = [
   JobFormPresentational,
+  JobExecutionFormPresentational
 ];
 
 @NgModule({
diff --git a/src/app/features/preservation/job/stores/preservation-job-execution/preservation-job-execution.action.ts b/src/app/features/preservation/job/stores/preservation-job-execution/preservation-job-execution.action.ts
index 3363d90bc..c09c81fa0 100644
--- a/src/app/features/preservation/job/stores/preservation-job-execution/preservation-job-execution.action.ts
+++ b/src/app/features/preservation/job/stores/preservation-job-execution/preservation-job-execution.action.ts
@@ -1,8 +1,10 @@
 import {LocalStateEnum} from "@shared/enums/local-state.enum";
+import {JobExecutionReport} from "@shared/models/business/job-execution-report.model";
 import {JobExecution} from "@shared/models/business/job-execution.model";
 import {
   BaseAction,
   BaseSubAction,
+  CollectionTyped,
   CompositionAction,
   CompositionNameSpace,
   QueryParameters,
@@ -75,7 +77,7 @@ export namespace PreservationJobExecutionAction {
   export class Resume extends BaseAction {
     static readonly type: string = `[${state}] Resume`;
 
-    constructor(public parentId: string, public jobExecution: JobExecution) {
+    constructor(public parentId: string, public jobExecutionId: string) {
       super();
     }
   }
@@ -111,6 +113,26 @@ export namespace PreservationJobExecutionAction {
       super();
     }
   }
+
+  export class GetListReport extends BaseAction {
+    static readonly type: string = `[${state}] Get List Reports`;
+
+    constructor(public parentId: string, public jobExecutionId: string) {
+      super();
+    }
+  }
+
+  export class GetListReportSuccess extends BaseSubAction<GetListReport> {
+    static readonly type: string = `[${state}] Get List Report Success`;
+
+    constructor(public parentAction: GetListReport, public list: CollectionTyped<JobExecutionReport>) {
+      super(parentAction);
+    }
+  }
+
+  export class GetListReportFail extends BaseSubAction<GetListReport> {
+    static readonly type: string = `[${state}] Get List Report Fail`;
+  }
 }
 
 export const preservationJobExecutionActionNameSpace: CompositionNameSpace = PreservationJobExecutionAction;
diff --git a/src/app/features/preservation/job/stores/preservation-job-execution/preservation-job-execution.state.ts b/src/app/features/preservation/job/stores/preservation-job-execution/preservation-job-execution.state.ts
index c87b7c742..84b8079fa 100644
--- a/src/app/features/preservation/job/stores/preservation-job-execution/preservation-job-execution.state.ts
+++ b/src/app/features/preservation/job/stores/preservation-job-execution/preservation-job-execution.state.ts
@@ -2,6 +2,7 @@ import {
   PreservationJobExecutionAction,
   preservationJobExecutionActionNameSpace,
 } from "@app/features/preservation/job/stores/preservation-job-execution/preservation-job-execution.action";
+import {Collection} from "@app/generated-api";
 import {LocalStateEnum} from "@app/shared/enums/local-state.enum";
 import {
   Action,
@@ -11,10 +12,15 @@ import {
   StateContext,
   Store,
 } from "@ngxs/store";
+import {PreservationJobStateModel} from "@preservation/job/stores/preservation-job.state";
+import {SipDataFileStateModel} from "@preservation/sip/stores/data-file/sip-data-file.state";
 import {ApiActionEnum} from "@shared/enums/api-action.enum";
 import {ApiResourceNameEnum} from "@shared/enums/api-resource-name.enum";
 import {PreservationPlanningResourceApiEnum} from "@shared/enums/api.enum";
+import {JobExecutionReport} from "@shared/models/business/job-execution-report.model";
 import {JobExecution} from "@shared/models/business/job-execution.model";
+import {defaultStatusHistoryInitValue} from "@shared/stores/status-history/status-history.state";
+import {SelectorType} from "codelyzer/selectorPropertyBase";
 import {Observable} from "rxjs";
 import {
   catchError,
@@ -22,23 +28,39 @@ import {
 } from "rxjs/operators";
 import {
   ApiService,
+  BaseResourceType,
+  CollectionTyped,
   CompositionState,
   CompositionStateModel,
+  defaultCompositionStateInitValue,
   defaultResourceStateInitValue,
   isNullOrUndefined,
   NotificationService,
+  OverrideDefaultAction,
+  QueryParameters,
+  ResourceStateModel,
   SolidifyStateError,
+  StoreUtil,
   TRANSLATE,
   urlSeparator,
 } from "solidify-frontend";
 
+
+export const defaultJobExecutionInitValue: () => PreservationJobExecutionStateModel = () =>
+({
+    ...defaultResourceStateInitValue(),
+    listReports: undefined,
+});
+
 export interface PreservationJobExecutionStateModel extends CompositionStateModel<JobExecution> {
+  listReports: JobExecutionReport[] | undefined;
 }
 
 @State<PreservationJobExecutionStateModel>({
   name: LocalStateEnum.preservation_job_execution,
   defaults: {
     ...defaultResourceStateInitValue(),
+    listReports: undefined,
   },
 })
 export class PreservationJobExecutionState extends CompositionState<PreservationJobExecutionStateModel, JobExecution> {
@@ -69,8 +91,10 @@ export class PreservationJobExecutionState extends CompositionState<Preservation
     ctx.patchState({
       isLoadingCounter: ctx.getState().isLoadingCounter + 1,
     });
+    console.error(action.parentId);
+    console.error(action);
 
-    return this.apiService.post<string>(this._urlResource + urlSeparator + action.parentId + urlSeparator + ApiResourceNameEnum.PRES_JOB_EXECUTION + urlSeparator + action.jobExecution.resId + urlSeparator + ApiActionEnum.RESUME)
+    return this.apiService.post<string>(this._urlResource + urlSeparator + action.parentId + urlSeparator + ApiResourceNameEnum.PRES_JOB_EXECUTION + urlSeparator + action.jobExecutionId + urlSeparator + ApiActionEnum.RESUME)
       .pipe(
         tap(result => {
           ctx.dispatch(new PreservationJobExecutionAction.ResumeSuccess(action));
@@ -131,4 +155,63 @@ export class PreservationJobExecutionState extends CompositionState<Preservation
     });
     this.notificationService.showError(TRANSLATE("preservation.jobExecution.notification.start.fail"), true);
   }
+
+  @Selector()
+  static isReadyToBeDisplayed(state: PreservationJobStateModel): boolean {
+    return !isNullOrUndefined(state.current);
+  }
+
+  @Selector()
+  static isLoading(state: PreservationJobStateModel): boolean {
+    return StoreUtil.isLoadingState(state);
+  }
+
+  @Selector()
+  static listReport(state: PreservationJobExecutionStateModel): JobExecutionReport[] {
+    return state.listReports;
+  }
+
+  @OverrideDefaultAction()
+  @Action(PreservationJobExecutionAction.GetByIdSuccess)
+  getByIdSuccess(ctx: StateContext<PreservationJobExecutionStateModel>, action: PreservationJobExecutionAction.GetByIdSuccess): void {
+    ctx.patchState({
+      current: action.model,
+      isLoadingCounter: ctx.getState().isLoadingCounter - 1,
+    });
+    ctx.dispatch(new PreservationJobExecutionAction.GetListReport(action.model.jobId, action.model.resId));
+  }
+
+  @Action(PreservationJobExecutionAction.GetListReport)
+  getListReport(ctx: StateContext<PreservationJobExecutionStateModel>, action: PreservationJobExecutionAction.GetListReport): Observable<CollectionTyped<JobExecutionReport>> {
+    ctx.patchState({
+      isLoadingCounter: ctx.getState().isLoadingCounter + 1,
+    });
+
+    return this.apiService.get<JobExecutionReport>(this._urlResource + urlSeparator + action.parentId + urlSeparator + ApiResourceNameEnum.PRES_JOB_EXECUTION + urlSeparator + action.jobExecutionId + urlSeparator + ApiActionEnum.REPORT, new QueryParameters())
+      .pipe(
+        tap((collection: CollectionTyped<JobExecutionReport>) => {
+          ctx.dispatch(new PreservationJobExecutionAction.GetListReportSuccess(action, collection));
+        }),
+        catchError(error => {
+          ctx.dispatch(new PreservationJobExecutionAction.GetListReportFail(action));
+          throw new SolidifyStateError(this, error);
+        }),
+      );
+  }
+
+  @Action(PreservationJobExecutionAction.GetListReportSuccess)
+  getListReportSuccess(ctx: StateContext<PreservationJobExecutionStateModel>, action: PreservationJobExecutionAction.GetListReportSuccess): void {
+    ctx.patchState({
+      listReports: action.list._data,
+      isLoadingCounter: ctx.getState().isLoadingCounter - 1,
+    });
+
+  }
+
+  @Action(PreservationJobExecutionAction.GetListReportFail)
+  getListReportFail(ctx: StateContext<PreservationJobExecutionStateModel>, action: PreservationJobExecutionAction.GetListReportFail): void {
+    ctx.patchState({
+      isLoadingCounter: ctx.getState().isLoadingCounter - 1,
+    });
+  }
 }
diff --git a/src/app/features/preservation/job/stores/preservation-job.state.ts b/src/app/features/preservation/job/stores/preservation-job.state.ts
index dd2423557..cd745ffc2 100644
--- a/src/app/features/preservation/job/stores/preservation-job.state.ts
+++ b/src/app/features/preservation/job/stores/preservation-job.state.ts
@@ -1,4 +1,5 @@
 import {
+  defaultJobExecutionInitValue,
   PreservationJobExecutionState,
   PreservationJobExecutionStateModel,
 } from "@app/features/preservation/job/stores/preservation-job-execution/preservation-job-execution.state";
@@ -38,7 +39,6 @@ import {
   TRANSLATE,
   urlSeparator,
 } from "solidify-frontend";
-
 export interface PreservationJobStateModel extends ResourceStateModel<PreservationJob> {
   listJobTypes: JobType[] | undefined;
   listJobRecurrences: JobRecurrence[] | undefined;
@@ -51,7 +51,7 @@ export interface PreservationJobStateModel extends ResourceStateModel<Preservati
     ...defaultResourceStateInitValue(),
     listJobTypes: undefined,
     listJobRecurrences: undefined,
-    preservation_job_execution: {...defaultResourceStateInitValue()},
+    preservation_job_execution: {...defaultJobExecutionInitValue()},
   },
   children: [
     PreservationJobExecutionState,
diff --git a/src/app/shared/enums/api-action.enum.ts b/src/app/shared/enums/api-action.enum.ts
index 9788e9441..c57662f97 100644
--- a/src/app/shared/enums/api-action.enum.ts
+++ b/src/app/shared/enums/api-action.enum.ts
@@ -83,6 +83,6 @@ export class ApiActionEnum {
   public static REJECT: string = "reject";
   public static ENABLE_REVISION: string = "enable-revision";
   public static INIT: string = "initialize";
-  public static REPORT: string = "report";
+  public static REPORT: string = "reports";
   public static VALIDATE: string = "validate";
 }
diff --git a/src/app/shared/enums/api-resource-name.enum.ts b/src/app/shared/enums/api-resource-name.enum.ts
index 77eeaccb1..ef1717b65 100644
--- a/src/app/shared/enums/api-resource-name.enum.ts
+++ b/src/app/shared/enums/api-resource-name.enum.ts
@@ -30,6 +30,7 @@ export class ApiResourceNameEnum implements ApiResourceNameEnum {
   public static MONITOR: string = "monitor";
   public static PRES_JOB: string = "preservation-jobs";
   public static PRES_JOB_EXECUTION: string = "executions";
+  public static PRES_JOB_EXECUTION_REPORT: string = "reports";
   public static PRES_POLICY: string = "preservation-policies";
   public static SUB_POLICY: string = "submission-policies";
   public static DISSEMINATION_POLICY: string = "dissemination-policies";
diff --git a/src/app/shared/enums/business/job-report-aip-status.enum.ts b/src/app/shared/enums/business/job-report-aip-status.enum.ts
new file mode 100644
index 000000000..838d9ba84
--- /dev/null
+++ b/src/app/shared/enums/business/job-report-aip-status.enum.ts
@@ -0,0 +1,5 @@
+export enum JobReportAipStatus {
+  PROCESSED = "PROCESSED",
+  IGNORED = "IGNORED",
+  ERROR = "ERROR"
+}
diff --git a/src/app/shared/enums/local-state.enum.ts b/src/app/shared/enums/local-state.enum.ts
index 406ee130e..b9f39f0cb 100644
--- a/src/app/shared/enums/local-state.enum.ts
+++ b/src/app/shared/enums/local-state.enum.ts
@@ -90,6 +90,9 @@ export enum LocalStateEnum {
   preservation_monitoring = "preservation_monitoring",
   preservation_aipStatus = "preservation_aipStatus",
   preservation_job = "preservation_job",
+  preservation_job_execution = "preservation_job_execution",
+  preservation_job_execution_report = "preservation_job_execution_report",
+
 
   preservation_aip = "preservation_aip",
   preservation_aip_organizationalUnit = "preservation_aip_organizationalUnit",
@@ -97,8 +100,6 @@ export enum LocalStateEnum {
   preservation_aip_statusHistory = "preservation_aip_statusHistory",
   preservation_aip_aip_statusHistory = "preservation_aip_aip_statusHistory",
 
-  preservation_job_execution = "preservation_job_execution",
-
   preservation_sip = "preservation_sip",
   preservation_sip_statusHistory = "preservation_sip_statusHistory",
   preservation_sip_dataFile = "preservation_sip_dataFile",
diff --git a/src/app/shared/enums/routes.enum.ts b/src/app/shared/enums/routes.enum.ts
index c501aa552..328a9e4a5 100644
--- a/src/app/shared/enums/routes.enum.ts
+++ b/src/app/shared/enums/routes.enum.ts
@@ -16,6 +16,8 @@ export enum AppRoutesEnum {
   paramIdOrgUnit = ":idOrgUnit",
   paramIdWithoutPrefixParam = "id",
   paramIdOrgUnitWithoutPrefixParam = "idOrgUnit",
+  paramIdExecution = ":idExecution",
+  paramIdExecutionWithoutPrefixParam = "idExecution",
   edit = "edit",
 }
 
@@ -126,6 +128,7 @@ export enum PreservationPlanningRoutesEnum {
   preservationPlanningCreate = "create",
   preservationPlanningDetail = "detail",
   preservationPlanningEdit = "edit",
+  preservationPlanningExecution= "execution",
 
   monitoring = "monitoring",
 
diff --git a/src/app/shared/models/business/job-execution-report-line.model.ts b/src/app/shared/models/business/job-execution-report-line.model.ts
new file mode 100644
index 000000000..18366c34a
--- /dev/null
+++ b/src/app/shared/models/business/job-execution-report-line.model.ts
@@ -0,0 +1,10 @@
+import {JobReportAipStatus} from "@shared/enums/business/job-report-aip-status.enum";
+
+export interface JobExecutionReportLine {
+  seq: number;
+  reportId: string;
+  errorMessage?: string;
+  storageUrl?: string;
+  changeTime?: Date;
+  status: JobReportAipStatus;
+}
diff --git a/src/app/shared/models/business/job-execution-report.model.ts b/src/app/shared/models/business/job-execution-report.model.ts
new file mode 100644
index 000000000..703037a6c
--- /dev/null
+++ b/src/app/shared/models/business/job-execution-report.model.ts
@@ -0,0 +1,10 @@
+import {JobExecutionReportLine} from "@shared/models/business/job-execution-report-line.model";
+
+export interface JobExecutionReport {
+  jobExecutionId: string;
+  executionNumber: number;
+  listAip?: JobExecutionReportLine[];
+  processedItems: number;
+  ignoredItems: number;
+  inErrorItems: number;
+}
diff --git a/src/app/shared/models/business/job-execution.model.ts b/src/app/shared/models/business/job-execution.model.ts
index 360eefd78..e65c3bc4a 100644
--- a/src/app/shared/models/business/job-execution.model.ts
+++ b/src/app/shared/models/business/job-execution.model.ts
@@ -1,6 +1,6 @@
 import {ChangeInfo} from "@app/generated-api";
 import {JobStatusEnum} from "@shared/enums/business/job-status.enum";
-
+import {JobExecutionReport} from "@shared/models/business/job-execution-report.model";
 export interface JobExecution {
   resId: string;
   jobId?: string;
@@ -16,4 +16,5 @@ export interface JobExecution {
   totalItems?: number;
   creation?: ChangeInfo;
   lastUpdate?: ChangeInfo;
+  executionReports?: JobExecutionReport[];
 }
diff --git a/src/app/shared/stores/report/report.action.ts b/src/app/shared/stores/report/report.action.ts
new file mode 100644
index 000000000..e69de29bb
diff --git a/src/app/shared/stores/report/report.state.ts b/src/app/shared/stores/report/report.state.ts
new file mode 100644
index 000000000..e69de29bb
diff --git a/src/assets/i18n/de.json b/src/assets/i18n/de.json
index 25f3b3ed5..3aa3afc9d 100644
--- a/src/assets/i18n/de.json
+++ b/src/assets/i18n/de.json
@@ -989,7 +989,8 @@
       "job": {
         "create": "Create",
         "edit": "Edit",
-        "root": "Job"
+        "root": "Job",
+        "execution": "Execution"
       },
       "monitoring": {
         "root": "Monitoring"
@@ -1952,9 +1953,17 @@
       }
     },
     "jobExecution": {
+      "inError": "Aips in error from last report",
+      "ignored":  "Aips ignore from last report",
+      "processed":  "Aips Processed from last report",
+      "total": "Aips total from last report",
+      "startDate": "Start Date",
+      "endDate": "End Date",
+      "statusMessage": "Status Message",
       "button": {
         "refresh": "Refresh",
-        "start": "Run"
+        "start": "Run",
+        "resume": "Resume"
       },
       "home": {
         "title": "Job executions : {{name}}"
@@ -1984,6 +1993,27 @@
           "startDate": "Start date",
           "status": "Status"
         }
+      },
+      "form": {
+        "status": "Status",
+        "statusMessage": "Status Message",
+        "startDate": "Start Date",
+        "endDate": "End Date",
+        "ignored": "Aips ignored from last report",
+        "processed": "Aips processed from last report",
+        "inError": "Aips in error from last report",
+        "total": "Total Aips considered from last report"
+      },
+      "report": {
+        "title": "Reports",
+        "table": {
+          "header": {
+            "executionNumber": "Report number",
+            "processedItems": "Items processed",
+            "ignoredItems": "Items ignored",
+            "inErrorItems": "Items in error"
+          }
+        }
       }
     },
     "jobExecutionDetail": {
@@ -1997,7 +2027,10 @@
       "runNumber": "Run number",
       "status": "Status",
       "title": "Job execution detail",
-      "totalItems": "Total items"
+      "totalItems": "Total items",
+      "form": {
+        "status": "Status"
+      }
     },
     "jobs": {
       "home": {
diff --git a/src/assets/i18n/en.json b/src/assets/i18n/en.json
index 25f3b3ed5..0d5b93124 100644
--- a/src/assets/i18n/en.json
+++ b/src/assets/i18n/en.json
@@ -989,7 +989,8 @@
       "job": {
         "create": "Create",
         "edit": "Edit",
-        "root": "Job"
+        "root": "Job",
+        "execution": "Execution"
       },
       "monitoring": {
         "root": "Monitoring"
@@ -1952,9 +1953,17 @@
       }
     },
     "jobExecution": {
+      "inError": "Aips in error from last report",
+      "ignored":  "Aips ignore from last report",
+      "processed":  "Aips Processed from last report",
+      "total": "Aips total from last report",
+      "startDate": "Start Date",
+      "endDate": "End Date",
+      "statusMessage": "Status Message",
       "button": {
         "refresh": "Refresh",
-        "start": "Run"
+        "start": "Run",
+        "resume": "Resume"
       },
       "home": {
         "title": "Job executions : {{name}}"
@@ -1984,6 +1993,27 @@
           "startDate": "Start date",
           "status": "Status"
         }
+      },
+      "form": {
+        "status": "Status",
+        "statusMessage": "Status Message",
+        "startDate": "Start Date",
+        "endDate": "End Date",
+        "ignored": "Aips ignored from last report",
+        "processed": "Aips processed from last report",
+        "inError": "Aips in error from last report",
+        "total": "Total Aips considered from last report"
+      },
+      "report": {
+        "title": "Reports",
+        "table": {
+          "header": {
+            "executionNumber": "Report number",
+            "processedItems": "Items processed",
+            "ignoredItems": "Items ignored",
+            "inErrorItems": "Items in error"
+          }
+        }
       }
     },
     "jobExecutionDetail": {
diff --git a/src/assets/i18n/fr.json b/src/assets/i18n/fr.json
index a6bdb24be..6a5729817 100644
--- a/src/assets/i18n/fr.json
+++ b/src/assets/i18n/fr.json
@@ -989,7 +989,8 @@
       "job": {
         "create": "Créer",
         "edit": "Modifier",
-        "root": "Job"
+        "root": "Job",
+        "execution": "Exécution"
       },
       "monitoring": {
         "root": "Surveillance"
@@ -1952,9 +1953,17 @@
       }
     },
     "jobExecution": {
+      "ignored": "Aips ignorés du dernière rapport",
+      "processed": "Aips traités du dernière rapport",
+      "inError": "Aips en erreurs  du dernière rapport",
+      "total": "Total Aips  du dernière rapport",
+      "startDate": "Start Date",
+      "endDate": "End Date",
+      "statusMessage": "Détail de l'exécution du job",
       "button": {
         "refresh": "Rafraichir",
-        "start": "Lancer"
+        "start": "Lancer",
+        "resume": "Resumé"
       },
       "home": {
         "title": "Exécutions du job : {{name}}"
@@ -1984,6 +1993,27 @@
           "startDate": "Date de début",
           "status": "Statut"
         }
+      },
+      "form": {
+        "status": "Statut",
+        "statusMessage": "Détail de l'exécution du job",
+        "startDate": "Start Date",
+        "endDate": "End Date",
+        "ignored": "Aips ignorés du dernière rapport",
+        "processed": "Aips traités du dernière rapport",
+        "inError": "Aips en erreurs  du dernière rapport",
+        "total": "Total Aips  du dernière rapport"
+      },
+      "report": {
+        "title": "Rapports",
+        "table": {
+          "header": {
+            "executionNumber": "Numero du rapport",
+            "processedItems": "Items traités",
+            "ignoredItems": "Items ignorés",
+            "inErrorItems": "Items en erreur"
+          }
+        }
       }
     },
     "jobExecutionDetail": {
-- 
GitLab