Commit a3d1a1c3 authored by Florent Poittevin's avatar Florent Poittevin Committed by Alicia.DeDiosFuente
Browse files

feat: [DLCM-1955] allow root to remove sip dip and datafile

parent 84677107
......@@ -46,15 +46,15 @@
<ng-template [ngIf]="getFormControl(formDefinition.dataType).value === dataTypeEnum.CustomMetadata">
<solidify-searchable-single-select *ngIf="getFormControl(formDefinition.metadataType) as fd"
[formControl]="fd"
[labelCallback]="metadataTypeLabelCallback"
[labelKey]="'name'"
[placeholder]="labelTranslateEnum.metadataType | translate"
[required]="formValidationHelper.hasRequiredField(fd)"
[resourceNameSpace]="depositDataFileMetadataTypeActionNameSpace"
[state]="depositDataFileMetadataTypeState"
[valueKey]="'resId'"
solidifyValidation
[formControl]="fd"
[labelCallback]="metadataTypeLabelCallback"
[labelKey]="'name'"
[placeholder]="labelTranslateEnum.metadataType | translate"
[required]="formValidationHelper.hasRequiredField(fd)"
[resourceNameSpace]="depositDataFileMetadataTypeActionNameSpace"
[state]="depositDataFileMetadataTypeState"
[valueKey]="'resId'"
solidifyValidation
>
</solidify-searchable-single-select>
</ng-template>
......
<dlcm-shared-file-and-aip-information-container #sharedFileAndAipInformationContainer
(deleteChange)="delete()"
*ngIf="data"
[canEdit]="canEditObs | async"
[canDelete]="canEditObs | async"
[data]="data"
[solidifySpinner]="data | isNullOrUndefined"
(deleteChange)="delete()"
></dlcm-shared-file-and-aip-information-container>
......@@ -16,6 +16,7 @@ import {
Store,
} from "@ngxs/store";
import {SharedAbstractFileAipDetailRoutable} from "@shared/components/routables/shared-abstract-file-aip-detail/shared-abstract-file-aip-detail.routable";
import {StoreDialogService} from "@shared/services/store-dialog.service";
import {Observable} from "rxjs";
import {
ExtraButtonToolbar,
......@@ -36,7 +37,8 @@ export class DepositCollectionDetailRoutable extends SharedAbstractFileAipDetail
protected readonly _route: ActivatedRoute,
protected readonly _actions$: Actions,
protected readonly _dialog: MatDialog,
protected readonly _changeDetector: ChangeDetectorRef) {
protected readonly _changeDetector: ChangeDetectorRef,
protected readonly _storeDialogService: StoreDialogService) {
super(_store,
_route,
_actions$,
......@@ -45,6 +47,7 @@ export class DepositCollectionDetailRoutable extends SharedAbstractFileAipDetail
DepositCollectionState as any,
depositCollectionActionNameSpace,
DepositCollectionStatusHistoryState,
depositCollectionStatusHistoryNamespace);
depositCollectionStatusHistoryNamespace,
_storeDialogService);
}
}
<dlcm-shared-file-and-aip-information-container #sharedFileAndAipInformationContainer
(dataCategoryTypeChange)="changeDataCategoryWithDialog()"
(deleteChange)="delete()"
(locationChange)="moveDataFileWithDialog()"
*ngIf="data"
[canEdit]="canEditObs | async"
[canDelete]="canEditObs | async"
[data]="data"
[solidifySpinner]="data | isNullOrUndefined"
(dataCategoryTypeChange)="changeDataCategoryWithDialog()"
(deleteChange)="delete()"
(locationChange)="moveDataFileWithDialog()"
></dlcm-shared-file-and-aip-information-container>
......@@ -24,6 +24,7 @@ import {
import {SharedAbstractFileAipDetailRoutable} from "@shared/components/routables/shared-abstract-file-aip-detail/shared-abstract-file-aip-detail.routable";
import {IconNameEnum} from "@shared/enums/icon-name.enum";
import {LabelTranslateEnum} from "@shared/enums/label-translate.enum";
import {StoreDialogService} from "@shared/services/store-dialog.service";
import {Observable} from "rxjs";
import {
DialogUtil,
......@@ -55,7 +56,8 @@ export class DepositFileDetailRoutable extends SharedAbstractFileAipDetailRoutab
protected readonly _route: ActivatedRoute,
protected readonly _actions$: Actions,
protected readonly _dialog: MatDialog,
protected readonly _changeDetector: ChangeDetectorRef) {
protected readonly _changeDetector: ChangeDetectorRef,
protected readonly _storeDialogService: StoreDialogService) {
super(_store,
_route,
_actions$,
......@@ -64,7 +66,8 @@ export class DepositFileDetailRoutable extends SharedAbstractFileAipDetailRoutab
DepositDataFileState,
depositDataFileActionNameSpace,
DepositDataFileStatusHistoryState,
depositDataFileStatusHistoryNamespace);
depositDataFileStatusHistoryNamespace,
_storeDialogService);
}
changeDataCategoryWithDialog(): void {
......
<dlcm-shared-file-and-aip-information-container #sharedFileAndAipInformationContainer
*ngIf="data"
[canEdit]="false"
[canDelete]="false"
[data]="data"
[solidifySpinner]="data | isNullOrUndefined"
></dlcm-shared-file-and-aip-information-container>
......@@ -39,6 +39,7 @@ import {
BreakpointService,
DateUtil,
EnumUtil,
isNotNullNorUndefined,
isNullOrUndefined,
KeyValue,
ObservableUtil,
......@@ -143,6 +144,13 @@ export class PreservationPlanningDipFormPresentational extends AbstractFormPrese
this.form.get(this.formDefinition.complianceLevel).disable();
}
protected override _modelUpdated(oldValue: Dip | undefined, newValue: Dip): void {
super._modelUpdated(oldValue, newValue);
if (isNotNullNorUndefined(newValue) && isNotNullNorUndefined(this.form) && isNotNullNorUndefined(this.form.get(this.formDefinition.status))) {
this.form.get(this.formDefinition.status).setValue(newValue.info.status);
}
}
goToAip(storagion: Storage, aipId: string): void {
this._navigateBS.next([AppRoutesEnum.preservationPlanning, PreservationPlanningRoutesEnum.aip, String(storagion.index), SharedAipRoutesEnum.aipDetail, aipId]);
}
......
<solidify-button-toolbar-detail (backToListChange)="backToList()"
(showHistoryChange)="showHistory()"
[currentModel]="currentObs | async"
[deleteAvailable]="deleteAvailable"
[editAvailable]="editAvailable"
[formPresentational]="formPresentational"
[historyAvailable]="true"
[listExtraButtons]="listExtraButtons"
[mode]="'detail'"
<solidify-empty-container (keydown.escape)="backToList()"
(onEscape)="backToList()"
[solidifyFocusFirstElement]="true"
solidifyShortCuts
>
</solidify-button-toolbar-detail>
<solidify-button-toolbar-detail (backToListChange)="backToList()"
(showHistoryChange)="showHistory()"
[currentModel]="currentObs | async"
[deleteAvailable]="deleteAvailable"
[editAvailable]="editAvailable"
[formPresentational]="formPresentational"
[historyAvailable]="true"
[listExtraButtons]="listExtraButtons"
[mode]="'detail'"
class="toolbar"
>
</solidify-button-toolbar-detail>
<solidify-tabs-container (tabChange)="setCurrentTab($event)"
[isLoading]="isLoadingObs | async"
[tabs]="listTabs"
>
<router-outlet></router-outlet>
</solidify-tabs-container>
<solidify-tabs-container (tabChange)="setCurrentTab($event)"
[isLoading]="isLoadingObs | async"
[tabs]="listTabs"
>
<router-outlet></router-outlet>
</solidify-tabs-container>
</solidify-empty-container>
@import "~solidify-frontend/lib/components/routables/abstract-detail-edit-common/abstract-detail-edit-common.routable";
@import "src/sass/abstracts/abstracts";
@import "abstracts/abstracts";
:host {
.toolbar {
margin-bottom: 2px;
}
}
......@@ -25,7 +25,10 @@ import {
PreservationPlanningDipAction,
preservationPlanningDipActionNameSpace,
} from "@preservation-planning/dip/stores/preservation-planning-dip.action";
import {PreservationPlanningDipStateModel} from "@preservation-planning/dip/stores/preservation-planning-dip.state";
import {
PreservationPlanningDipState,
PreservationPlanningDipStateModel,
} from "@preservation-planning/dip/stores/preservation-planning-dip.state";
import {PreservationPlanningDipStatusHistoryAction} from "@preservation-planning/dip/stores/status-history/preservation-planning-dip-status-history.action";
import {PreservationPlanningDipStatusHistoryState} from "@preservation-planning/dip/stores/status-history/preservation-planning-dip-status-history.state";
import {IconNameEnum} from "@shared/enums/icon-name.enum";
......@@ -43,6 +46,7 @@ import {
ExtraButtonToolbar,
isNotNullNorUndefined,
MemoizedUtil,
PollingHelper,
QueryParameters,
StatusHistory,
StatusHistoryDialog,
......@@ -128,6 +132,7 @@ export class PreservationPlanningDipDetailEditRoutable
ngOnInit(): void {
super.ngOnInit();
this.retrieveCurrentModelWithUrl();
this._createPollingListenerCompletedStatus();
}
ngOnDestroy(): void {
......@@ -212,6 +217,42 @@ export class PreservationPlanningDipDetailEditRoutable
putInError(): void {
this._store.dispatch(new PreservationPlanningDipAction.PutInError(this._resId));
}
private _createPollingListenerCompletedStatus(): void {
this.subscribe(PollingHelper.startPollingObs({
initialIntervalRefreshInSecond: environment.refreshDepositSubmittedIntervalInSecond,
incrementInterval: true,
maximumIntervalRefreshInSecond: 60,
stopRefreshAfterMaximumIntervalReached: true,
resetIntervalWhenUserMouseEvent: true,
filter: () => this._shouldContinuePollingWaitCompletedStatus(),
actionToDo: () => {
this._store.dispatch(new PreservationPlanningDipAction.GetById(this._resId, true));
},
}));
}
private _shouldContinuePollingWaitCompletedStatus(): boolean {
const status = MemoizedUtil.selectSnapshot(this._store, PreservationPlanningDipState, state => state.current?.info?.status);
return isNotNullNorUndefined(status) && (
status === Enums.Package.StatusEnum.IN_PROGRESS
|| status === Enums.Package.StatusEnum.IN_PREPARATION
|| status === Enums.Package.StatusEnum.CHECKING
|| status === Enums.Package.StatusEnum.CHECKED
|| status === Enums.Package.StatusEnum.STORED
|| status === Enums.Package.StatusEnum.INDEXING
|| status === Enums.Package.StatusEnum.REINDEXING
|| status === Enums.Package.StatusEnum.DOWNLOADING
|| status === Enums.Package.StatusEnum.RELOADED
|| status === Enums.Package.StatusEnum.CLEANING
|| status === Enums.Package.StatusEnum.DISPOSABLE
|| status === Enums.Package.StatusEnum.DISPOSAL_APPROVED_BY_ORGUNIT
|| status === Enums.Package.StatusEnum.DISPOSAL_APPROVED
|| status === Enums.Package.StatusEnum.REPLICATING_TOMBSTONE
|| status === Enums.Package.StatusEnum.REPLICATING_PACKAGE
|| status === Enums.Package.StatusEnum.UPDATING_RETENTION
);
}
}
enum TabEnum {
......
......@@ -15,6 +15,9 @@ import {PreservationPlanningDipDataFileState} from "@preservation-planning/dip/s
import {preservationPlanningDipDataFileStatusHistoryNamespace} from "@preservation-planning/dip/stores/data-file/status-history/preservation-planning-dip-data-file-status-history.action";
import {PreservationPlanningDipDataFileStatusHistoryState} from "@preservation-planning/dip/stores/data-file/status-history/preservation-planning-dip-data-file-status-history.state";
import {SharedAbstractFileAipDetailRoutable} from "@shared/components/routables/shared-abstract-file-aip-detail/shared-abstract-file-aip-detail.routable";
import {SecurityService} from "@shared/services/security.service";
import {StoreDialogService} from "@shared/services/store-dialog.service";
import {isTrue} from "solidify-frontend";
@Component({
selector: "dlcm-preservation-planning-dip-file-detail",
......@@ -26,7 +29,9 @@ export class PreservationPlanningDipFileDetailRoutable extends SharedAbstractFil
protected readonly _route: ActivatedRoute,
protected readonly _actions$: Actions,
protected readonly _dialog: MatDialog,
protected readonly _changeDetector: ChangeDetectorRef) {
protected readonly _changeDetector: ChangeDetectorRef,
protected readonly _storeDialogService: StoreDialogService,
private readonly _securityService: SecurityService) {
super(_store,
_route,
_actions$,
......@@ -35,6 +40,14 @@ export class PreservationPlanningDipFileDetailRoutable extends SharedAbstractFil
PreservationPlanningDipDataFileState,
preservationPlanningDipDataFileActionNameSpace,
PreservationPlanningDipDataFileStatusHistoryState,
preservationPlanningDipDataFileStatusHistoryNamespace);
preservationPlanningDipDataFileStatusHistoryNamespace,
_storeDialogService);
}
protected override _computeCanDelete(): void {
super._computeCanDelete();
if (isTrue(this.canDelete)) {
this.canDelete = this._securityService.isRoot();
}
}
}
......@@ -31,13 +31,17 @@ import {
} from "@shared/enums/routes.enum";
import {StateEnum} from "@shared/enums/state.enum";
import {DataTableComponentHelper} from "@shared/helpers/data-table-component.helper";
import {SecurityService} from "@shared/services/security.service";
import {Observable} from "rxjs";
import {
AbstractDetailEditRoutable,
DataTableActions,
DataTableColumns,
DataTableFieldTypeEnum,
DeleteDialog,
DialogUtil,
isNullOrUndefined,
isTrue,
MemoizedUtil,
OrderEnum,
QueryParameters,
......@@ -73,7 +77,8 @@ export class PreservationPlanningDipFileRoutable extends AbstractDetailEditRouta
protected readonly _actions$: Actions,
protected readonly _changeDetector: ChangeDetectorRef,
protected readonly _dialog: MatDialog,
protected readonly _injector: Injector) {
protected readonly _injector: Injector,
private readonly _securityService: SecurityService) {
super(_store, _route, _actions$, _changeDetector, _dialog, StateEnum.preservationPlanning_dip, _injector, preservationPlanningDipActionNameSpace, StateEnum.preservationPlanning);
this.columns = [
......@@ -142,6 +147,12 @@ export class PreservationPlanningDipFileRoutable extends AbstractDetailEditRouta
placeholder: current => LabelTranslateEnum.download,
displayOnCondition: (current: DipDataFile) => current.status === Enums.DataFile.StatusEnum.PROCESSED || current.status === Enums.DataFile.StatusEnum.READY || current.status === Enums.DataFile.StatusEnum.VIRUS_CHECKED,
},
{
logo: IconNameEnum.delete,
callback: (dipDataFile: DipDataFile) => this._deleteDatafile(dipDataFile),
placeholder: current => LabelTranslateEnum.delete,
displayOnCondition: (current: DipDataFile) => this._securityService.isRoot() && (isNullOrUndefined(current) || current.status === Enums.DataFile.StatusEnum.IN_ERROR),
},
];
}
......@@ -191,4 +202,18 @@ export class PreservationPlanningDipFileRoutable extends AbstractDetailEditRouta
private resumeDataFile(parentId: string, dataFile: DipDataFile): void {
this._store.dispatch(new PreservationPlanningDipDataFileAction.Resume(parentId, dataFile));
}
private _deleteDatafile(dipDataFile: DipDataFile): void {
const deleteData = this._storeDialogService.deleteData(StateEnum.preservationPlanning_dip_dataFile);
deleteData.name = dipDataFile.fileName;
this.subscribe(DialogUtil.open(this._dialog, DeleteDialog, deleteData,
{
width: "400px",
},
isConfirmed => {
if (isTrue(isConfirmed)) {
this._store.dispatch(new PreservationPlanningDipDataFileAction.Delete(this._resId, dipDataFile.resId));
}
}));
}
}
......@@ -2,13 +2,13 @@
class="wrapper"
>
<dlcm-preservation-planning-dip-form #formPresentational
(dirtyChange)="updateCanDeactivate($event)"
(navigate)="navigate($event)"
(submitChange)="update($event)"
*ngIf="isReadyToBeDisplayedObs | async"
[listAip]="listAipObs | async"
[model]="currentObs| async"
[readonly]="!isEdit"
(dirtyChange)="updateCanDeactivate($event)"
(navigate)="navigate($event)"
(submitChange)="update($event)"
>
</dlcm-preservation-planning-dip-form>
</div>
......@@ -174,6 +174,7 @@ export class PreservationPlanningDipState extends ResourceState<PreservationPlan
isLoadingCounter: ctx.getState().isLoadingCounter - 1,
});
this.notificationService.showInformation(MARK_AS_TRANSLATABLE("notification.dip.action.resume.success"));
ctx.dispatch(new PreservationPlanningDipAction.GetById(action.parentAction.id, true));
}
@Action(PreservationPlanningDipAction.ResumeFail)
......@@ -211,6 +212,7 @@ export class PreservationPlanningDipState extends ResourceState<PreservationPlan
isLoadingCounter: ctx.getState().isLoadingCounter - 1,
});
this.notificationService.showInformation(MARK_AS_TRANSLATABLE("notification.dip.action.put-in-error.success"));
ctx.dispatch(new PreservationPlanningDipAction.GetById(action.parentAction.id, true));
}
@Action(PreservationPlanningDipAction.PutInErrorFail)
......
......@@ -38,6 +38,7 @@ import {
BreakpointService,
DateUtil,
EnumUtil,
isNotNullNorUndefined,
isNullOrUndefined,
KeyValue,
ObservableUtil,
......@@ -118,6 +119,13 @@ export class PreservationPlanningSipFormPresentational extends AbstractFormPrese
this.isValidWhenDisable = this.form.valid;
}
protected override _modelUpdated(oldValue: Sip | undefined, newValue: Sip): void {
super._modelUpdated(oldValue, newValue);
if (isNotNullNorUndefined(newValue) && isNotNullNorUndefined(this.form) && isNotNullNorUndefined(this.form.get(this.formDefinition.status))) {
this.form.get(this.formDefinition.status).setValue(newValue.info.status);
}
}
protected treatmentBeforeSubmit(sip: Sip): Sip {
return sip;
}
......
......@@ -15,6 +15,7 @@ import {PreservationPlanningSipCollectionState} from "@preservation-planning/sip
import {preservationPlanningSipCollectionStatusHistoryNamespace} from "@preservation-planning/sip/stores/collection/status-history/preservation-planning-sip-collection-status-history.action";
import {PreservationPlanningSipCollectionStatusHistoryState} from "@preservation-planning/sip/stores/collection/status-history/preservation-planning-sip-collection-status-history.state";
import {SharedAbstractFileAipDetailRoutable} from "@shared/components/routables/shared-abstract-file-aip-detail/shared-abstract-file-aip-detail.routable";
import {StoreDialogService} from "@shared/services/store-dialog.service";
@Component({
selector: "dlcm-preservation-planning-sip-collection-detail",
......@@ -26,7 +27,8 @@ export class PreservationPlanningSipCollectionDetailRoutable extends SharedAbstr
protected readonly _route: ActivatedRoute,
protected readonly _actions$: Actions,
protected readonly _dialog: MatDialog,
protected readonly _changeDetector: ChangeDetectorRef) {
protected readonly _changeDetector: ChangeDetectorRef,
protected readonly _storeDialogService: StoreDialogService) {
super(_store,
_route,
_actions$,
......@@ -35,6 +37,7 @@ export class PreservationPlanningSipCollectionDetailRoutable extends SharedAbstr
PreservationPlanningSipCollectionState,
preservationPlanningSipCollectionActionNameSpace,
PreservationPlanningSipCollectionStatusHistoryState,
preservationPlanningSipCollectionStatusHistoryNamespace);
preservationPlanningSipCollectionStatusHistoryNamespace,
_storeDialogService);
}
}
<solidify-empty-container (keydown.escape)="backToList()"
(onEscape)="backToList()"
[solidifyFocusFirstElement]="true"
solidifyShortCuts
(onEscape)="backToList()"
[solidifyFocusFirstElement]="true"
solidifyShortCuts
>
<solidify-button-toolbar-detail (backToListChange)="backToList()"
(showHistoryChange)="showHistory()"
[currentModel]="currentObs | async"
[deleteAvailable]="deleteAvailable"
[editAvailable]="editAvailable"
[formPresentational]="formPresentational"
[historyAvailable]="true"
[listExtraButtons]="listExtraButtons"
[mode]="'detail'"
(showHistoryChange)="showHistory()"
[currentModel]="currentObs | async"
[deleteAvailable]="deleteAvailable"
[editAvailable]="editAvailable"
[formPresentational]="formPresentational"
[historyAvailable]="true"
[listExtraButtons]="listExtraButtons"
[mode]="'detail'"
class="toolbar"
>
</solidify-button-toolbar-detail>
<solidify-tabs-container (tabChange)="setCurrentTab($event)"
[isLoading]="isLoadingObs | async"
[tabs]="listTabs"
[isLoading]="isLoadingObs | async"
[tabs]="listTabs"
>
<router-outlet></router-outlet>
</solidify-tabs-container>
......
@import "~solidify-frontend/lib/components/routables/abstract-detail-edit-common/abstract-detail-edit-common.routable";
@import "src/sass/abstracts/abstracts";
@import "abstracts/abstracts";
:host {
.toolbar {
margin-bottom: 2px;
}
}
......@@ -24,7 +24,10 @@ import {
PreservationPlanningSipAction,
preservationPlanningSipActionNameSpace,
} from "@preservation-planning/sip/stores/preservation-planning-sip.action";
import {PreservationPlanningSipStateModel} from "@preservation-planning/sip/stores/preservation-planning-sip.state";
import {
PreservationPlanningSipState,
PreservationPlanningSipStateModel,
} from "@preservation-planning/sip/stores/preservation-planning-sip.state";
import {PreservationPlanningSipStatusHistoryAction} from "@preservation-planning/sip/stores/status-history/preservation-planning-sip-status-history.action";
import {PreservationPlanningSipStatusHistoryState} from "@preservation-planning/sip/stores/status-history/preservation-planning-sip-status-history.state";
import {IconNameEnum} from "@shared/enums/icon-name.enum";
......@@ -40,11 +43,13 @@ import {Observable} from "rxjs";
import {map} from "rxjs/operators";
import {
AbstractDetailEditRoutable,
ButtonColorEnum,
DialogUtil,
ExtraButtonToolbar,
isNotNullNorUndefined,
MARK_AS_TRANSLATABLE,
MemoizedUtil,
PollingHelper,
QueryParameters,
StatusHistory,
StatusHistoryDialog,
......@@ -75,7 +80,7 @@ export class PreservationPlanningSipDetailEditRoutable extends AbstractDetailEdi
override readonly deleteAvailable: boolean = false;
readonly KEY_PARAM_NAME: keyof Sip & string = undefined;
readonly KEY_PARAM_NAME: keyof Sip & string = "resId";
readonly KEY_DELETE_BUTTON: string = undefined;
readonly KEY_EDIT_BUTTON: string = undefined;
readonly KEY_BACK_BUTTON: string = MARK_AS_TRANSLATABLE("preservation.sip.button.goBackToList");
......@@ -89,7 +94,7 @@ export class PreservationPlanningSipDetailEditRoutable extends AbstractDetailEdi
listExtraButtons: ExtraButtonToolbar<Sip>[] = [
{
color: "primary",
color: ButtonColorEnum.primary,
icon: IconNameEnum.download,
displayCondition: current => isNotNullNorUndefined(current?.info)
&& current.info.status === Enums.Package.StatusEnum.COMPLETED,
......@@ -98,7 +103,7 @@ export class PreservationPlanningSipDetailEditRoutable extends AbstractDetailEdi
order: 40,
},
{
color: "primary",
color: ButtonColorEnum.primary,
icon: IconNameEnum.resume,
displayCondition: current => isNotNullNorUndefined(current?.info)
&& current.info.status === Enums.Package.StatusEnum.IN_ERROR,
......@@ -107,7 +112,7 @@ export class PreservationPlanningSipDetailEditRoutable extends AbstractDetailEdi
order: 40,