diff --git a/src/app/features/preservation/aip/stores/aip.state.ts b/src/app/features/preservation/aip/stores/aip.state.ts index aa9b4cd7ce4a271862b9e1ef091d7fe4a9e6f380..4d86ff1bbcd48d5cfada163f57c3126269bb2143 100644 --- a/src/app/features/preservation/aip/stores/aip.state.ts +++ b/src/app/features/preservation/aip/stores/aip.state.ts @@ -135,6 +135,11 @@ export class PreservationAipState extends ResourceState<PreservationAipStateMode this.notificationService.showInformation(TRANSLATE("notification.aip.file.download"), true); } + saveFile(blobContent: Blob, fileName: string): void { + const blob = new Blob([blobContent], {type: "application/octet-stream"}); + saveAs(blob, fileName); + } + @Action(PreservationAipAction.Reindex) reindex(ctx: StateContext<PreservationAipStateModel>, action: PreservationAipAction.Reindex): Observable<string> { ctx.patchState({ @@ -269,9 +274,4 @@ export class PreservationAipState extends ResourceState<PreservationAipStateMode }); this.notificationService.showError(TRANSLATE("notification.aip.action.resume.fail"), true); } - - saveFile(blobContent: Blob, fileName: string): void { - const blob = new Blob([blobContent], {type: "application/octet-stream"}); - saveAs(blob, fileName); - } } diff --git a/src/app/features/preservation/sip/components/routables/sip-detail-edit/sip-detail-edit.routable.html b/src/app/features/preservation/sip/components/routables/sip-detail-edit/sip-detail-edit.routable.html index b187a8aa01ecf5687fce8719822b6140aad78590..16fa282484b21edd99a69f143ebdd2fc568485bd 100644 --- a/src/app/features/preservation/sip/components/routables/sip-detail-edit/sip-detail-edit.routable.html +++ b/src/app/features/preservation/sip/components/routables/sip-detail-edit/sip-detail-edit.routable.html @@ -18,6 +18,13 @@ <mat-icon>file_download</mat-icon> {{'preservation.sip.button.download' | translate}} </button> + + <button *ngIf="(currentObs | async) && (currentObs | async).info.status === packageStatusEnum.IN_ERROR" mat-button + color="primary" + (click)="resume()"> + <mat-icon>play_circle_filled</mat-icon> + {{'preservation.sip.button.resume' | translate}} + </button> </div> <mat-tab-group #matTabGroup diff --git a/src/app/features/preservation/sip/components/routables/sip-detail-edit/sip-detail-edit.routable.ts b/src/app/features/preservation/sip/components/routables/sip-detail-edit/sip-detail-edit.routable.ts index 3c7274c73f62cabdbb81053685e9b9bea991465e..b67a2344195b0de671568ff8e0eaa4817699c060 100644 --- a/src/app/features/preservation/sip/components/routables/sip-detail-edit/sip-detail-edit.routable.ts +++ b/src/app/features/preservation/sip/components/routables/sip-detail-edit/sip-detail-edit.routable.ts @@ -21,6 +21,7 @@ import { Actions, Store, } from "@ngxs/store"; +import {PreservationAipAction} from "@preservation/aip/stores/aip.action"; import {SipFormPresentational} from "@preservation/sip/components/presentationals/sip-form/sip-form.presentational"; import {SipTabEnum} from "@preservation/sip/enums/sip-tab.enum"; import {SipHelper} from "@preservation/sip/helpers/sip.helper"; @@ -32,6 +33,7 @@ import {PreservationSipStatusHistoryAction} from "@preservation/sip/stores/statu import {SipStatusHistoryState} from "@preservation/sip/stores/status-history/sip-status-history.state"; import {SharedHistoryDialog} from "@shared/components/dialogs/shared-history/shared-history.dialog"; import {SharedAbstractDetailEditRoutable} from "@shared/components/routables/shared-abstract-detail-edit/shared-abstract-detail-edit.routable"; +import {PackageStatusEnum} from "@shared/enums/business/package-status.enum"; import {RoutesEnum} from "@shared/enums/routes.enum"; import {StatusHistoryDialog} from "@shared/models/status-history-dialog.model"; import {StatusHistory} from "@shared/models/status-history.model"; @@ -67,6 +69,10 @@ export class SipDetailEditRoutable extends SharedAbstractDetailEditRoutable<Sip, message: string; tabSelected: SipTabEnum; + get packageStatusEnum(): typeof PackageStatusEnum { + return PackageStatusEnum; + } + readonly KEY_PARAM_NAME: keyof Sip & string = undefined; readonly KEY_DELETE_BUTTON: string = undefined; readonly KEY_EDIT_BUTTON: string = undefined; @@ -138,4 +144,8 @@ export class SipDetailEditRoutable extends SharedAbstractDetailEditRoutable<Sip, download(): void { this._store.dispatch(new PreservationSipAction.Download(this._resId)); } + + resume(): void { + this._store.dispatch(new PreservationSipAction.Resume(this._resId)); + } } diff --git a/src/app/features/preservation/sip/stores/sip.action.ts b/src/app/features/preservation/sip/stores/sip.action.ts index 2fceda7d6beccaf2a2e80ae7bfbb01ef542ee546..f0b60f834c6a9c8a703c20e8c4f39ee87185563f 100644 --- a/src/app/features/preservation/sip/stores/sip.action.ts +++ b/src/app/features/preservation/sip/stores/sip.action.ts @@ -1,6 +1,8 @@ import {Sip} from "@app/generated-api"; import {LocalStateEnum} from "@app/shared/enums/local-state.enum"; import { + BaseAction, + BaseSubAction, ResourceAction, ResourceNameSpace, TypeDefaultAction, @@ -107,6 +109,22 @@ export namespace PreservationSipAction { constructor(public id: string) { } } + + export class Resume extends BaseAction { + static readonly type: string = `[${state}] Resume`; + + constructor(public id: string) { + super(); + } + } + + export class ResumeSuccess extends BaseSubAction<Resume> { + static readonly type: string = `[${state}] Resume Success`; + } + + export class ResumeFail extends BaseSubAction<Resume> { + static readonly type: string = `[${state}] Resume Fail`; + } } export const preservationSipActionNameSpace: ResourceNameSpace = PreservationSipAction; diff --git a/src/app/features/preservation/sip/stores/sip.state.ts b/src/app/features/preservation/sip/stores/sip.state.ts index ea31ee1c3a89003e25fe3da49127e7d1b393b345..d545007a5c9731103d55af5c051fe11aee64e439 100644 --- a/src/app/features/preservation/sip/stores/sip.state.ts +++ b/src/app/features/preservation/sip/stores/sip.state.ts @@ -26,9 +26,16 @@ import { StateContext, Store, } from "@ngxs/store"; +import {PreservationAipAction} from "@preservation/aip/stores/aip.action"; +import {PreservationAipStateModel} from "@preservation/aip/stores/aip.state"; import {ApiActionEnum} from "@shared/enums/api-action.enum"; import {defaultStatusHistoryInitValue} from "@shared/stores/status-history/status-history.state"; import {saveAs} from "file-saver"; +import {Observable} from "rxjs"; +import { + catchError, + tap, +} from "rxjs/operators"; import { ApiService, defaultResourceStateInitValue, @@ -123,4 +130,37 @@ export class SipState extends ResourceState<SipStateModel, Sip> { const blob = new Blob([blobContent], {type: "application/octet-stream"}); saveAs(blob, fileName); } + + @Action(PreservationSipAction.Resume) + resume(ctx: StateContext<PreservationAipStateModel>, action: PreservationSipAction.Resume): Observable<string> { + ctx.patchState({ + isLoadingCounter: ctx.getState().isLoadingCounter + 1, + }); + return this.httpClient.post<string>(`${this._urlResource}/${action.id}/${ApiActionEnum.RESUME}`, null) + .pipe( + tap(result => { + ctx.dispatch(new PreservationSipAction.ResumeSuccess(action)); + }), + catchError(error => { + ctx.dispatch(new PreservationSipAction.ResumeFail(action)); + throw error; + }), + ); + } + + @Action(PreservationSipAction.ResumeSuccess) + resumeSuccess(ctx: StateContext<PreservationAipStateModel>, action: PreservationSipAction.ResumeSuccess): void { + ctx.patchState({ + isLoadingCounter: ctx.getState().isLoadingCounter - 1, + }); + this.notificationService.showInformation(TRANSLATE("notification.sip.action.resume.success"), true); + } + + @Action(PreservationSipAction.ResumeFail) + resumeFail(ctx: StateContext<PreservationAipStateModel>, action: PreservationSipAction.ResumeFail): void { + ctx.patchState({ + isLoadingCounter: ctx.getState().isLoadingCounter - 1, + }); + this.notificationService.showError(TRANSLATE("notification.sip.action.resume.fail"), true); + } } diff --git a/src/assets/i18n/de.json b/src/assets/i18n/de.json index 67de98053df60f02fd4b9ce4df7b62bd10e4bc5e..5f25aedf44a5e992e8450d4643e4721a631d72d6 100644 --- a/src/assets/i18n/de.json +++ b/src/assets/i18n/de.json @@ -1236,6 +1236,14 @@ "resumed": "Resource resumed successfully" } }, + "sip": { + "action": { + "resume": { + "fail": "notification.sip.action.resume.fail", + "success": "notification.sip.action.resume.success" + } + } + }, "unsavedChanges": "You have unsaved changes! If you leave, your changes will be lost.", "uploadInProgress": "You have file upload in progress! If you leave, the upload will be potentially interrupted." }, @@ -1451,7 +1459,8 @@ "back": "Back", "button": { "download": "Download", - "goBackToList": "Back" + "goBackToList": "Back", + "resume": "preservation.sip.button.resume" }, "form": { "access": "Access", @@ -1556,4 +1565,4 @@ } } } -} +} \ No newline at end of file diff --git a/src/assets/i18n/en.json b/src/assets/i18n/en.json index 67de98053df60f02fd4b9ce4df7b62bd10e4bc5e..41ad4079dfcf14fd2ebc57239966bc211a99cc8b 100644 --- a/src/assets/i18n/en.json +++ b/src/assets/i18n/en.json @@ -1236,6 +1236,14 @@ "resumed": "Resource resumed successfully" } }, + "sip": { + "action": { + "resume": { + "fail": "Impossible to restart SIP processing", + "success": "SIP processing has been restarted" + } + } + }, "unsavedChanges": "You have unsaved changes! If you leave, your changes will be lost.", "uploadInProgress": "You have file upload in progress! If you leave, the upload will be potentially interrupted." }, @@ -1451,7 +1459,8 @@ "back": "Back", "button": { "download": "Download", - "goBackToList": "Back" + "goBackToList": "Back", + "resume": "Resume" }, "form": { "access": "Access", diff --git a/src/assets/i18n/fr.json b/src/assets/i18n/fr.json index 134b4d082a7fb7fbec235f96b9da2e57bf9260c7..788467570456b5cff9c656abed9669fe60b70e0a 100644 --- a/src/assets/i18n/fr.json +++ b/src/assets/i18n/fr.json @@ -1236,6 +1236,14 @@ "resumed": "Processus d'ingestion relancé avec succès" } }, + "sip": { + "action": { + "resume": { + "fail": "Impossible de relancer le traitement du SIP", + "success": "Le traitement du SIP a été relancé" + } + } + }, "unsavedChanges": "Vous avez des changements non sauvegardés ! Si vous partez, vos changements seront perdus.", "uploadInProgress": "Vous avez des envois de fichier en cours ! Si vous partez, l'envoi sera potentiellement interrompu." }, @@ -1451,7 +1459,8 @@ "back": "Retour", "button": { "download": "Télécharger", - "goBackToList": "Retour" + "goBackToList": "Retour", + "resume": "Relancer" }, "form": { "access": "Accès",