diff --git a/src/app/features/deposit/components/dialogs/deposit-aip-upload/deposit-aip-upload.dialog.html b/src/app/features/deposit/components/dialogs/deposit-aip-upload/deposit-aip-upload.dialog.html new file mode 100644 index 0000000000000000000000000000000000000000..a8913a117db47063c81c6d2247bc4f9221abfb1c --- /dev/null +++ b/src/app/features/deposit/components/dialogs/deposit-aip-upload/deposit-aip-upload.dialog.html @@ -0,0 +1,50 @@ +<dlcm-shared-base-action-dialog [titleToTranslate]="'deposit.aip.modal.title.main' | translate"> + <h2>{{'deposit.aip.modal.title.search' | translate }}</h2> + <dlcm-shared-search class="search-bar" + (valueChange)="search($event)" + [value]="searchObs | async" + > + </dlcm-shared-search> + + <div [dlcmSpinner]="(isLoadingObs | async)" + class="wrapper" + > + <ng-container *ngIf="getListAipToDisplay(listAipObs | async) as listAip"> + <ng-template [ngIf]="listAip?.length > 0" + [ngIfElse]="noAip" + > + <ul> + <li class="aip-item" + *ngFor="let aip of listAip" + [class.selected]="checkIfSelected(aip.resId)" + > + <div (click)="addRemoveSelection(aip.resId)"> + {{aip.info.name}} + </div> + </li> + </ul> + </ng-template> + <ng-template #noAip> + {{'deposit.aip.modal.noAipFound' | translate}} + </ng-template> + </ng-container> + </div> + + <div mat-dialog-actions + class="footer" + > + <button mat-button + [mat-dialog-close]="" + cdkFocusInitial + >{{'deposit.aip.modal.button.close' | translate}} + </button> + <button mat-flat-button + color="primary" + [disabled]="!form.valid || aipsToUpload.length === 0" + (click)="onSubmit()" + >{{'deposit.aip.modal.button.confirmUpload' | translate}} + </button> + </div> +</dlcm-shared-base-action-dialog> + + diff --git a/src/app/features/deposit/components/dialogs/deposit-aip-upload/deposit-aip-upload.dialog.scss b/src/app/features/deposit/components/dialogs/deposit-aip-upload/deposit-aip-upload.dialog.scss new file mode 100644 index 0000000000000000000000000000000000000000..6f3f0f6bd3f91aa94f67b67ede20789b8093f481 --- /dev/null +++ b/src/app/features/deposit/components/dialogs/deposit-aip-upload/deposit-aip-upload.dialog.scss @@ -0,0 +1,19 @@ +@import "../../../../../../sass/abstracts/variables"; + +li { + &.aip-item { + background-color: $extra-light-grey; + margin: 0; + padding: 8px 10px; + cursor: pointer; + } + + &:nth-child(odd) { + background-color: $extra-ultra-light-grey; + } + + &.selected { + background-color: $primary-color; + color: $white; + } +} diff --git a/src/app/features/deposit/components/dialogs/deposit-aip-upload/deposit-aip-upload.dialog.ts b/src/app/features/deposit/components/dialogs/deposit-aip-upload/deposit-aip-upload.dialog.ts new file mode 100644 index 0000000000000000000000000000000000000000..a62275e1b0d9eafb2991fe6a50698f68e531a804 --- /dev/null +++ b/src/app/features/deposit/components/dialogs/deposit-aip-upload/deposit-aip-upload.dialog.ts @@ -0,0 +1,127 @@ +import { + ChangeDetectionStrategy, + Component, + Inject, + OnInit, +} from "@angular/core"; +import { + FormBuilder, + FormGroup, +} from "@angular/forms"; +import {MatDialogRef} from "@angular/material"; +import {MAT_DIALOG_DATA} from "@angular/material/dialog"; +import {DepositAipAction} from "@deposit/stores/aip/deposit-aip.action"; +import {DepositAipState} from "@deposit/stores/aip/deposit-aip.state"; +import {Store} from "@ngxs/store"; +import {AipExtended} from "@preservation/aip/models/aip-extended.model"; +import {SharedAbstractContainer} from "@shared/components/containers/shared-abstract/shared-abstract.container"; +import {FieldTypeEnum} from "@shared/enums/field-type.enum"; +import {AppRoutesEnum} from "@shared/enums/routes.enum"; +import {BaseFormDefinition} from "@shared/models/base-form-definition.model"; +import {DataTableColumns} from "@shared/models/data-table-columns.model"; +import {Observable} from "rxjs"; +import { + isEmptyArray, + isNullOrUndefined, + MemoizedUtil, + OrderEnum, + PropertyName, + QueryParameters, + ResourceState, + TRANSLATE, +} from "solidify-frontend"; + +@Component({ + selector: "dlcm-aip-file-upload-dialog", + templateUrl: "./deposit-aip-upload.dialog.html", + styleUrls: ["./deposit-aip-upload.dialog.scss"], + changeDetection: ChangeDetectionStrategy.OnPush, +}) +export class DepositAipUploadDialog extends SharedAbstractContainer implements OnInit { + form: FormGroup; + formDefinition: DepositAipUploadFormComponentFormDefinition = new DepositAipUploadFormComponentFormDefinition(); + + listAipObs: Observable<AipExtended[]> = ResourceState.list(this._store, DepositAipState); + isLoadingObs: Observable<boolean> = MemoizedUtil.isLoading(this._store, DepositAipState); + + aipsToUpload: string[] = []; + + columns: DataTableColumns[]; + searchObs: Observable<string>; + + constructor(protected readonly _store: Store, + protected readonly _dialogRef: MatDialogRef<DepositAipUploadDialog>, + @Inject(MAT_DIALOG_DATA) public data: DepositAipUploadDialogData, + protected _fb: FormBuilder) { + super(); + } + + ngOnInit(): void { + super.ngOnInit(); + this.form = this._fb.group({ + [this.formDefinition.search]: [""], + }); + + this._store.dispatch(new DepositAipAction.Clean(false, undefined)); + + this.columns = [ + { + field: "info.name", + header: TRANSLATE("access.table.header.organizationalUnit"), + type: FieldTypeEnum.string, + order: OrderEnum.none, + isSortable: false, + isFilterable: false, + }, + ]; + } + + search(searchTerm: string, queryParameters?: QueryParameters): void { + if (searchTerm !== "") { + const map = new Map<string, string>(); + map.set("info.name", searchTerm); + const orgUnitId = this._store.selectSnapshot(state => state.router.state.root.children[0].children[0].params[AppRoutesEnum.paramIdOrgUnitWithoutPrefixParam]); + map.set("info.organizationalUnitId", orgUnitId); + const newQueryParameters = new QueryParameters(); + newQueryParameters.search = { + searchItems: map, + }; + this._store.dispatch(new DepositAipAction.ChangeQueryParameters(newQueryParameters, true)); + } else { + this._store.dispatch(new DepositAipAction.Clean(false, undefined)); + } + } + + onSubmit(): void { + this._dialogRef.close(this.aipsToUpload); + } + + checkIfSelected(aipId: string): boolean { + return this.aipsToUpload.includes(aipId); + } + + addRemoveSelection(aipId: string): void { + if (this.aipsToUpload.includes(aipId)) { + const index: number = this.aipsToUpload.indexOf(aipId); + this.aipsToUpload.splice(index, 1); + } else { + this.aipsToUpload.push(aipId); + } + } + + getListAipToDisplay(list: AipExtended[]): AipExtended[] { + const listIdAipAlreadyLinked = this.data.listIdAipAlreadyLinked; + if (isNullOrUndefined(list) || isEmptyArray(list) || isNullOrUndefined(listIdAipAlreadyLinked) || isEmptyArray(listIdAipAlreadyLinked)) { + return list; + } + return list.filter(aip => !listIdAipAlreadyLinked.includes(aip.resId)); + } +} + +export class DepositAipUploadFormComponentFormDefinition extends BaseFormDefinition { + @PropertyName() search: string; +} + +export interface DepositAipUploadDialogData { + listIdAipAlreadyLinked: string[]; +} diff --git a/src/app/features/deposit/components/dialogs/deposit-file-upload-archive/deposit-file-upload-archive.dialog.ts b/src/app/features/deposit/components/dialogs/deposit-file-upload-archive/deposit-file-upload-archive.dialog.ts index 110bebb894b3e11802c27e33f723555493e2c485..3570c98e6d2803ded16862e0da4f68e680e61b54 100644 --- a/src/app/features/deposit/components/dialogs/deposit-file-upload-archive/deposit-file-upload-archive.dialog.ts +++ b/src/app/features/deposit/components/dialogs/deposit-file-upload-archive/deposit-file-upload-archive.dialog.ts @@ -17,9 +17,6 @@ import {isNullOrUndefined} from "solidify-frontend"; changeDetection: ChangeDetectionStrategy.OnPush, }) export class DepositFileUploadArchiveDialog extends AbstractDepositFileUploadDialog implements OnInit { - // TODO USE THIS FOLLOWING MESSAGE AS TOOLTIP WHEN REFACTO TO MERGE THE BOTH MODEL - // Uploading a wip file in this manner will decompress its contents while retaining its folder structure - archiveToUpload: File; get dataCategoryHelper(): typeof DataCategoryHelper { @@ -42,14 +39,6 @@ export class DepositFileUploadArchiveDialog extends AbstractDepositFileUploadDia } } - convertFileListToArray(files: FileList): File[] { - const arrayFile: File[] = []; - for (let i = 0; i < files.length; i++) { - arrayFile.push(files.item(i)); - } - return arrayFile; - } - onSubmit(): void { const base = this.form.value as FileUploadWrapper; const fileUploadWrapper = {} as FileUploadWrapper; diff --git a/src/app/features/deposit/components/presentationals/deposit-banner/deposit-banner.presentational.ts b/src/app/features/deposit/components/presentationals/deposit-banner/deposit-banner.presentational.ts index f6410b9fda3e6248b51a5468739c8d15a4d2b657..2b4cc98bd89314f91a26cdb8b63833edf8be768d 100644 --- a/src/app/features/deposit/components/presentationals/deposit-banner/deposit-banner.presentational.ts +++ b/src/app/features/deposit/components/presentationals/deposit-banner/deposit-banner.presentational.ts @@ -20,6 +20,7 @@ import { export class DepositBannerPresentational extends SharedAbstractPresentational { private _depositStatus: Deposit.StatusEnum; private _canSubmitAction: boolean; + private _messageReasonUnableSubmit: string; @Input() set depositStatus(value: Deposit.StatusEnum) { @@ -42,7 +43,14 @@ export class DepositBannerPresentational extends SharedAbstractPresentational { } @Input() - messageReasonUnableSubmit: string; + set messageReasonUnableSubmit(value: string) { + this._messageReasonUnableSubmit = value; + this.computeDisplayInfo(); + } + + get messageReasonUnableSubmit(): string { + return this._messageReasonUnableSubmit; + } display: boolean; message: string; diff --git a/src/app/features/deposit/components/routables/deposit-collection/deposit-collection.routable.html b/src/app/features/deposit/components/routables/deposit-collection/deposit-collection.routable.html new file mode 100644 index 0000000000000000000000000000000000000000..9aba39f724a73f06e56bb155238baf023fdad8d5 --- /dev/null +++ b/src/app/features/deposit/components/routables/deposit-collection/deposit-collection.routable.html @@ -0,0 +1,52 @@ +<div class="file-uploaded"> + <div class="header"> + <div class="left-part"> + <h1 class="title">{{'deposit.aip.title.collection' | translate}}</h1> + <button mat-button + class="button-add-to-collection" + color="accent" + type="button" + (click)="openModalUpload()" + [matTooltip]="'deposit.collection.button.addAip.tooltip' | translate" + > + <mat-icon>publish</mat-icon> + {{'deposit.collection.button.addAip.label' | translate}} + </button> + </div> + <div class="right-part"> + <button class="button-refresh" + mat-icon-button + mat-button + type="button" + (click)="refresh()" + [matTooltip]="'deposit.file.tree.refresh' | translate" + [matTooltipPosition]="'left'" + [class.spinning]="isLoadingCollectionObs | async" + [disabled]="isLoadingCollectionObs | async" + > + <mat-icon>refresh</mat-icon> + </button> + </div> + </div> + + <div class="file-viewer"> + <div class="file-list-wrapper" + [dlcmSpinner]="isLoadingCollectionObs | async" + > + <dlcm-shared-data-table *ngIf="columns" + [columns]="columns" + [actions]="actions" + [isLoading]="isLoadingCollectionObs | async" + [datas]="listCollectionObs | async" + [queryParameters]="queryParametersObs | async" + (queryParametersChange)="onQueryParametersEvent($event)" + (selectChange)="showDetail($event)" + > + </dlcm-shared-data-table> + </div> + + <ng-template #noFile> + <label>{{'deposit.file.tree.noFile' | translate}}</label> + </ng-template> + </div> +</div> diff --git a/src/app/features/deposit/components/routables/deposit-collection/deposit-collection.routable.scss b/src/app/features/deposit/components/routables/deposit-collection/deposit-collection.routable.scss new file mode 100644 index 0000000000000000000000000000000000000000..297ec44ff718db357fa54685187842b6facc1943 --- /dev/null +++ b/src/app/features/deposit/components/routables/deposit-collection/deposit-collection.routable.scss @@ -0,0 +1,68 @@ +@import "../../../../../../sass/abstracts/variables"; +@import "../../../../../../sass/abstracts/mixins"; +@import "../../../../../shared/components/routables/shared-abstract-detail-edit-common/shared-abstract-detail-edit-common.routable"; + +:host { + padding: 0; + + .header { + display: flex; + justify-content: space-between; + padding-bottom: 20px; + + .left-part, + .right-part { + display: flex; + } + + .left-part { + align-items: center; + + .title { + margin: 0; + } + + .button-add-to-collection { + margin-left: 20px; + } + + @include respond-to-smaller-than-breakpoint('sm') { + flex-direction: column; + align-items: self-start; + + .button-add-to-collection { + margin-left: 0; + } + } + } + + .right-part { + .button-refresh { + transition-property: transform; + transition-duration: 1s; + + fa-icon { + font-size: 20px; + } + + &.spinning { + animation-name: rotate; + animation-duration: 2s; + animation-iteration-count: infinite; + animation-timing-function: linear; + } + + @keyframes rotate { + from { + transform: rotate(0deg); + } + to { + transform: rotate(360deg); + } + } + } + } + } + +} + diff --git a/src/app/features/deposit/components/routables/deposit-collection/deposit-collection.routable.ts b/src/app/features/deposit/components/routables/deposit-collection/deposit-collection.routable.ts new file mode 100644 index 0000000000000000000000000000000000000000..d250dc95a049f161d2cbf3d09b96abbf620c3828 --- /dev/null +++ b/src/app/features/deposit/components/routables/deposit-collection/deposit-collection.routable.ts @@ -0,0 +1,220 @@ +import { + ChangeDetectorRef, + Component, + OnInit, +} from "@angular/core"; +import {MatDialog} from "@angular/material"; +import {ActivatedRoute} from "@angular/router"; +import { + DepositAipUploadDialog, + DepositAipUploadDialogData, +} from "@deposit/components/dialogs/deposit-aip-upload/deposit-aip-upload.dialog"; +import {DepositExtended} from "@deposit/models/deposits-extended.model"; +import {DepositCollectionAction} from "@deposit/stores/collection/deposit-collection.action"; +import {DepositCollectionState} from "@deposit/stores/collection/deposit-collection.state"; +import {depositActionNameSpace} from "@deposit/stores/deposit.action"; +import { + DepositState, + DepositStateModel, +} from "@deposit/stores/deposit.state"; +import {environment} from "@environments/environment"; +import { + Actions, + ofActionCompleted, + Store, +} from "@ngxs/store"; +import {AipExtended} from "@preservation/aip/models/aip-extended.model"; +import { + SharedAipDetailDialog, + SharedAipDetailDialogData, +} from "@shared/components/dialogs/shared-aip-detail/shared-aip-detail.dialog"; +import {SharedAbstractDetailEditRoutable} from "@shared/components/routables/shared-abstract-detail-edit/shared-abstract-detail-edit.routable"; +import {ComplianceLevelEnumHelper} from "@shared/enums/business/compliance-level.enum"; +import {DataFileStatusEnumHelper} from "@shared/enums/business/data-file-status.enum"; +import {DataTableComponentEnum} from "@shared/enums/data-table-component.enum"; +import {FieldTypeEnum} from "@shared/enums/field-type.enum"; +import {LocalStateEnum} from "@shared/enums/local-state.enum"; +import {AppRoutesEnum} from "@shared/enums/routes.enum"; +import {DataTableActions} from "@shared/models/data-table-actions.model"; +import {DataTableColumns} from "@shared/models/data-table-columns.model"; +import {Observable} from "rxjs"; +import { + distinctUntilChanged, + filter, + tap, +} from "rxjs/operators"; +import { + AssociationRemoteState, + isNonEmptyArray, + MemoizedUtil, + OrderEnum, + QueryParameters, + ResourceActionHelper, + TRANSLATE, +} from "solidify-frontend"; + +@Component({ + selector: "dlcm-deposit-collection-routable", + templateUrl: "./deposit-collection.routable.html", + styleUrls: ["./deposit-collection.routable.scss"], +}) +export class DepositCollectionRoutable extends SharedAbstractDetailEditRoutable<DepositExtended, DepositStateModel> implements OnInit { + readonly KEY_PARAM_NAME: keyof DepositExtended & string = undefined; + + isLoadingCollectionObs: Observable<boolean> = MemoizedUtil.isLoading(this._store, DepositCollectionState); + listCollectionObs: Observable<AipExtended[]> = AssociationRemoteState.selected(this._store, DepositCollectionState); + queryParametersObs: Observable<QueryParameters> = AssociationRemoteState.queryParameters(this._store, DepositCollectionState); + + canEditObs: Observable<boolean> = MemoizedUtil.select(this._store, DepositState, state => state.canEdit); + + columns: DataTableColumns<AipExtended>[]; + actions: DataTableActions<AipExtended>[]; + + readonly actionDelete: DataTableActions = { + logo: "delete", + callback: (aip: AipExtended) => this.deleteAip(this._resId, aip), + placeholder: TRANSLATE("crud.list.action.delete"), + displayOnCondition: (aip: AipExtended) => true, + }; + + readonly actionRedirect: DataTableActions = { + logo: "forward", + callback: (aipExtended: AipExtended) => this.goToAip(aipExtended), + placeholder: TRANSLATE("crud.list.action.goToAip"), + displayOnCondition: (aipExtended: AipExtended) => true, + }; + + constructor(protected readonly _store: Store, + protected readonly _route: ActivatedRoute, + protected readonly _actions$: Actions, + protected readonly _changeDetector: ChangeDetectorRef, + protected readonly _dialog: MatDialog) { + super(_store, _route, _actions$, _changeDetector, _dialog, LocalStateEnum.deposit, depositActionNameSpace); + } + + ngOnInit(): void { + super.ngOnInit(); + this.getCurrentModelOnParent(); + + this.columns = [ + { + field: "info.name" as any, + header: TRANSLATE("deposit.aip.table.aipName"), + type: FieldTypeEnum.string, + order: OrderEnum.none, + isSortable: true, + isFilterable: false, + }, + { + field: "info.status" as any, + header: TRANSLATE("deposit.aip.table.status"), + type: FieldTypeEnum.singleSelect, + order: OrderEnum.none, + isSortable: false, + isFilterable: false, + translate: true, + filterEnum: DataFileStatusEnumHelper.getListKeyValue(), + }, + { + field: "info.complianceLevel" as any, + header: TRANSLATE("deposit.aip.table.complianceLevel"), + type: FieldTypeEnum.singleSelect, + order: OrderEnum.none, + isSortable: false, + isFilterable: false, + translate: true, + component: DataTableComponentEnum.conformityLevelStar, + filterEnum: ComplianceLevelEnumHelper.getListKeyValue(), + }, + ]; + this.actions = []; + + this.subscribe(this.canEditObs.pipe(distinctUntilChanged()), (canEdit: boolean) => { + if (canEdit) { + this.actions = [ + this.actionDelete, + ]; + } else { + this.actions = [this.actionRedirect]; + } + }); + } + + private getCurrentModelOnParent(): void { + this._resId = this._route.snapshot.parent.paramMap.get(AppRoutesEnum.paramIdWithoutPrefixParam); + this.getDepositById(this._resId); + } + + private getDepositById(id: string): void { + this._store.dispatch(ResourceActionHelper.getById(depositActionNameSpace, id, true)); + this.getSubResourceWithParentId(id); + } + + getSubResourceWithParentId(id: string): void { + this._store.dispatch(new DepositCollectionAction.GetAll(id, null, true)); + } + + refresh(): void { + this._store.dispatch(new DepositCollectionAction.Refresh(this._resId)); + } + + onQueryParametersEvent(queryParameters: QueryParameters): void { + this._store.dispatch(new DepositCollectionAction.ChangeQueryParameters(this._resId, queryParameters, true)); + } + + showDetail(aip: AipExtended): void { + const dialogRef = this._dialog.open(SharedAipDetailDialog, { + data: { + aip: aip, + parentId: this._resId, + isReadonly: true, + isLoading: null, + statusHistory: null, + queryParametersObs: null, + state: null, + name: LocalStateEnum.deposit_collection, + } as SharedAipDetailDialogData<AipExtended>, + width: environment.modalWidth, + }); + } + + private goToAip(aip: AipExtended): void { + this._store.dispatch(new DepositCollectionAction.GoToAip(aip)); + } + + openModalUpload(): void { + const selected = AssociationRemoteState.selectedSnapshot(this._store, DepositCollectionState); + const dialogRef = this._dialog.open(DepositAipUploadDialog, { + width: "90%", + data: { + listIdAipAlreadyLinked: selected.map(aip => aip.resId), + } as DepositAipUploadDialogData, + }); + this.subscribe(dialogRef.afterClosed().pipe( + filter((listAipIds: string[]) => isNonEmptyArray(listAipIds)), + tap(((listAipIds: string[]) => { + this.addAip(listAipIds); + }), + ))); + } + + addAip(aipIds: string[]): void { + this._store.dispatch(new DepositCollectionAction.Create(this._resId, aipIds)); + this.subscribe(this._actions$.pipe( + ofActionCompleted(DepositCollectionAction.CreateSuccess), + tap(() => { + this._store.dispatch(new DepositCollectionAction.Refresh(this._resId)); + }), + )); + } + + deleteAip(_resId: string, aip: AipExtended): void { + this._store.dispatch(new DepositCollectionAction.Delete(this._resId, aip.resId)); + this.subscribe(this._actions$.pipe( + ofActionCompleted(DepositCollectionAction.DeleteSuccess), + tap(() => { + this._store.dispatch(new DepositCollectionAction.Refresh(this._resId)); + }), + )); + } +} diff --git a/src/app/features/deposit/components/routables/deposit-detail-edit/deposit-detail-edit.routable.html b/src/app/features/deposit/components/routables/deposit-detail-edit/deposit-detail-edit.routable.html index 8a4b266c4222b810e88141eeeed9e20652e4ed81..4028e7f225ddc2419d432bcde7d3f836174dfb1c 100644 --- a/src/app/features/deposit/components/routables/deposit-detail-edit/deposit-detail-edit.routable.html +++ b/src/app/features/deposit/components/routables/deposit-detail-edit/deposit-detail-edit.routable.html @@ -116,6 +116,12 @@ <span class="tab-header-label">{{'deposit.tab.datafiles' | translate}}</span> </ng-template> </mat-tab> + <mat-tab> + <ng-template mat-tab-label> + <mat-icon class="tab-header-icon">insert_drive_file</mat-icon> + <span class="tab-header-label">{{'deposit.tab.collection' | translate}}</span> + </ng-template> + </mat-tab> <mat-tab *ngIf="canDoAlterationActions"> <ng-template mat-tab-label> <mat-icon class="tab-header-icon">publish</mat-icon> diff --git a/src/app/features/deposit/components/routables/deposit-detail-edit/deposit-detail-edit.routable.ts b/src/app/features/deposit/components/routables/deposit-detail-edit/deposit-detail-edit.routable.ts index 9d252ffc2dfd40ff906a25d17505ae9237a74c87..63afb325ec6abe1c582ff5454ff5d57515e35f6e 100644 --- a/src/app/features/deposit/components/routables/deposit-detail-edit/deposit-detail-edit.routable.ts +++ b/src/app/features/deposit/components/routables/deposit-detail-edit/deposit-detail-edit.routable.ts @@ -50,6 +50,7 @@ import {StatusHistoryDialog} from "@shared/models/status-history-dialog.model"; import {StatusHistory} from "@shared/models/status-history.model"; import {SecurityService} from "@shared/services/security.service"; import { + BehaviorSubject, combineLatest, Observable, } from "rxjs"; @@ -65,6 +66,7 @@ import { isNullOrUndefined, isTrue, MemoizedUtil, + ObservableUtil, QueryParameters, TRANSLATE, } from "solidify-frontend"; @@ -97,6 +99,9 @@ export class DepositDetailEditRoutable extends SharedAbstractDetailEditRoutable< canSubmitAction: boolean = false; canReserveDoiAction: boolean = false; + canDoAlterationActionsBS: BehaviorSubject<boolean | undefined> = new BehaviorSubject(undefined); + readonly canDoAlterationActionsObs: Observable<boolean | undefined> = ObservableUtil.asObservable(this.canDoAlterationActionsBS); + private _orgUnitResId: string | undefined = undefined; readonly KEY_PARAM_NAME: keyof DepositExtended & string = "title"; @@ -141,6 +146,7 @@ export class DepositDetailEditRoutable extends SharedAbstractDetailEditRoutable< ); this._computeCurrentUserRight(); + this._computeEditableField(); } ngOnDestroy(): void { @@ -158,6 +164,15 @@ export class DepositDetailEditRoutable extends SharedAbstractDetailEditRoutable< this.tabSelected = DepositHelper.getTabSelectedIndexWithRoute(tabRouteSelected); } + private _computeEditableField(): void { + this.subscribe(this.canDoAlterationActionsObs.pipe( + distinctUntilChanged(), + tap(isEdit => { + this._store.dispatch(new DepositAction.ChangeEditProperty(isEdit)); + }), + )); + } + private _computeCurrentUserRight(): void { this.subscribe(this.currentObs.pipe( filter(deposit => !isNullOrUndefined(deposit) && deposit.resId === this._resId && isFalse(this.isEdit) && deposit.status === Deposit.StatusEnum.INPROGRESS), @@ -169,17 +184,17 @@ export class DepositDetailEditRoutable extends SharedAbstractDetailEditRoutable< this.subscribe(this.currentObs.pipe( distinctUntilChanged(), filter(deposit => !isNullOrUndefined(deposit) && deposit.resId === this._resId), - // take(1), tap(deposit => { const canDoValidatorActions = this._securityService.depositInValidationStep(deposit); const canDoAlterationActions = this._securityService.depositInEditionStep(deposit); + const collectionSize = this._store.selectSnapshot((state: LocalStateModel) => state.deposit.current.collectionSize); this.subscribe(combineLatest(this.numberFilesObs, this.numberFilesInErrorObs).pipe( distinctUntilChanged(), filter(([numberFiles, numberFilesInError]) => !isNullOrUndefined(numberFiles) && !isNullOrUndefined(numberFilesInError)), tap(([numberFiles, numberFilesInError]) => { let canSubmitAction = deposit.status === Deposit.StatusEnum.INPROGRESS; - if (numberFiles === 0) { + if (numberFiles === 0 && collectionSize === 0) { this.messageReasonUnableSubmit = TRANSLATE("deposit.error.noFile"); canSubmitAction = false; } @@ -195,6 +210,7 @@ export class DepositDetailEditRoutable extends SharedAbstractDetailEditRoutable< if (this._securityService.isRootOrAdmin()) { this.canDoValidatorActions = canDoValidatorActions; this.canDoAlterationActions = canDoAlterationActions; + this.canDoAlterationActionsBS.next(this.canDoAlterationActions); return; } @@ -241,6 +257,7 @@ export class DepositDetailEditRoutable extends SharedAbstractDetailEditRoutable< // console.info("deposit", deposit); // console.info("this.canDoAlterationActions", this.canDoAlterationActions); // console.info("this.canDoValidatorActions", this.canDoValidatorActions); + this.canDoAlterationActionsBS.next(this.canDoAlterationActions); this._changeDetector.detectChanges(); } diff --git a/src/app/features/deposit/components/routables/deposit-file/deposit-file.routable.ts b/src/app/features/deposit/components/routables/deposit-file/deposit-file.routable.ts index ece1dbbdec21b1a30f7aaa7133daad510f27046d..505e59536ad53b245ba9ed04cefe464b4f539520 100644 --- a/src/app/features/deposit/components/routables/deposit-file/deposit-file.routable.ts +++ b/src/app/features/deposit/components/routables/deposit-file/deposit-file.routable.ts @@ -32,7 +32,7 @@ import { } from "@shared/components/dialogs/shared-file-detail/shared-file-detail.dialog"; 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 {ComplianceLevelEnum} from "@shared/enums/business/compliance-level.enum"; +import {ComplianceLevelEnumHelper} from "@shared/enums/business/compliance-level.enum"; import { DataFileStatusEnum, DataFileStatusEnumHelper, @@ -200,28 +200,7 @@ export class DepositFileRoutable extends SharedAbstractDetailEditRoutable<Deposi isFilterable: false, translate: true, component: DataTableComponentEnum.conformityLevelStar, - filterEnum: [ - { - key: ComplianceLevelEnum.FULL_COMPLIANCE, - value: TRANSLATE("FULL_COMPLIANCE"), - }, - { - key: ComplianceLevelEnum.AVERAGE_COMPLIANCE, - value: TRANSLATE("AVERAGE_COMPLIANCE"), - }, - { - key: ComplianceLevelEnum.WEAK_COMPLIANCE, - value: TRANSLATE("WEAK_COMPLIANCE"), - }, - { - key: ComplianceLevelEnum.NO_COMPLIANCE, - value: TRANSLATE("NO_COMPLIANCE"), - }, - { - key: ComplianceLevelEnum.NOT_ASSESSED, - value: TRANSLATE("NOT_ASSESSED"), - }, - ], + filterEnum: ComplianceLevelEnumHelper.getListKeyValue(), }, ]; } diff --git a/src/app/features/deposit/components/routables/deposit-upload/deposit-upload.routable.html b/src/app/features/deposit/components/routables/deposit-upload/deposit-upload.routable.html index d0309ac1a500020a7a81c6fcd51b89ec114572dd..633a0100bf48b7f36f7238af34feea75bc3d6cda 100644 --- a/src/app/features/deposit/components/routables/deposit-upload/deposit-upload.routable.html +++ b/src/app/features/deposit/components/routables/deposit-upload/deposit-upload.routable.html @@ -11,10 +11,11 @@ <button mat-button color="accent" type="button" + [matTooltip]="'deposit.file.button.uploadArchive.tooltip' | translate" (click)="openModalUploadArchive()" > <mat-icon>unarchive</mat-icon> - {{'deposit.file.button.uploadArchive' | translate}} + {{'deposit.file.button.uploadArchive.label' | translate}} </button> </div> diff --git a/src/app/features/deposit/deposit-routing.module.ts b/src/app/features/deposit/deposit-routing.module.ts index 561f03a97ff5d385e814160f6c8beb4beef8117f..bcda3544d6e7b7c65341a4dade6b7a5427d3f26b 100644 --- a/src/app/features/deposit/deposit-routing.module.ts +++ b/src/app/features/deposit/deposit-routing.module.ts @@ -10,6 +10,7 @@ import { DepositRoutesEnum, } from "@app/shared/enums/routes.enum"; import {DlcmRoutes} from "@app/shared/models/dlcm-route.model"; +import {DepositCollectionRoutable} from "@deposit/components/routables/deposit-collection/deposit-collection.routable"; import {DepositDetailEditRoutable} from "@deposit/components/routables/deposit-detail-edit/deposit-detail-edit.routable"; import {DepositFileRoutable} from "@deposit/components/routables/deposit-file/deposit-file.routable"; import {DepositHomeRoutable} from "@deposit/components/routables/deposit-home/deposit-home.routable"; @@ -127,6 +128,24 @@ const routes: DlcmRoutes = [ noBreadcrumbLink: true, }, }, + { + path: DepositRoutesEnum.collection, + component: DepositCollectionRoutable, + data : { + breadcrumb: TRANSLATE("breadcrumb.deposit.collection"), + noBreadcrumbLink: true, + }, + children: [ + { + path: DepositRoutesEnum.edit, + data: { + breadcrumb: TRANSLATE("breadcrumb.deposit.edit"), + }, + canActivate: [DepositRoleGuardEditService], + canDeactivate: [CanDeactivateGuard], + }, + ], + }, { path: DepositRoutesEnum.upload, component: DepositUploadRoutable, diff --git a/src/app/features/deposit/deposit.module.ts b/src/app/features/deposit/deposit.module.ts index bf6a76f51b541cb528021aa586a24012411fda90..a8d30fb89d843c0f2cc64ea41c6bf2de01c70c8e 100644 --- a/src/app/features/deposit/deposit.module.ts +++ b/src/app/features/deposit/deposit.module.ts @@ -9,17 +9,21 @@ import {DepositDataFileState} from "@app/features/deposit/stores/data-file/depos import {DepositState} from "@app/features/deposit/stores/deposit.state"; import {DepositPeopleState} from "@app/features/deposit/stores/people/deposit-people.state"; import {SharedModule} from "@app/shared/shared.module"; +import {DepositAipUploadDialog} from "@deposit/components/dialogs/deposit-aip-upload/deposit-aip-upload.dialog"; import {DepositFileUploadArchiveDialog} from "@deposit/components/dialogs/deposit-file-upload-archive/deposit-file-upload-archive.dialog"; import {DepositOrderAuthorDialog} from "@deposit/components/dialogs/deposit-order-author/deposit-order-author.dialog"; import {DepositPersonAlternativeDialog} from "@deposit/components/dialogs/deposit-person-alternative/deposit-person-alternative.dialog"; import {DepositPersonDialog} from "@deposit/components/dialogs/deposit-person/deposit-person.dialog"; import {DepositBannerPresentational} from "@deposit/components/presentationals/deposit-banner/deposit-banner.presentational"; import {DepositFolderTreePresentational} from "@deposit/components/presentationals/deposit-folder-tree/deposit-folder-tree.presentational"; +import {DepositCollectionRoutable} from "@deposit/components/routables/deposit-collection/deposit-collection.routable"; import {DepositFileRoutable} from "@deposit/components/routables/deposit-file/deposit-file.routable"; import {DepositHomeRoutable} from "@deposit/components/routables/deposit-home/deposit-home.routable"; import {DepositMetadataRoutable} from "@deposit/components/routables/deposit-metadata/deposit-metadata.routable"; import {DepositRootRoutable} from "@deposit/components/routables/deposit-root/deposit-root.routable"; import {DepositUploadRoutable} from "@deposit/components/routables/deposit-upload/deposit-upload.routable"; +import {DepositAipState} from "@deposit/stores/aip/deposit-aip.state"; +import {DepositCollectionState} from "@deposit/stores/collection/deposit-collection.state"; import {DepositDataFileStatusHistoryState} from "@deposit/stores/data-file/status-history/deposit-data-file-status-history.state"; import {DepositOrganizationalUnitState} from "@deposit/stores/organizational-unit/deposit-organizational-unit.state"; import {DepositStatusHistoryState} from "@deposit/stores/status-history/deposit-status-history.state"; @@ -38,6 +42,7 @@ const routables = [ DepositFileRoutable, DepositUploadRoutable, DepositMetadataRoutable, + DepositCollectionRoutable ]; const containers = []; const dialogs = [ @@ -47,6 +52,7 @@ const dialogs = [ DepositPersonDialog, DepositOrderAuthorDialog, DepositPersonAlternativeDialog, + DepositAipUploadDialog ]; const presentationals = [ DepositFormPresentational, @@ -74,6 +80,8 @@ const presentationals = [ DepositStatusHistoryState, DepositDataFileStatusHistoryState, DepositOrganizationalUnitState, + DepositCollectionState, + DepositAipState ]), ], entryComponents: [ diff --git a/src/app/features/deposit/enums/deposit-tab.enum.ts b/src/app/features/deposit/enums/deposit-tab.enum.ts index 6ba699f7ca1eb55c05090f8a6a53bbbc2a8ff210..32cd495d7bab092aa42aecd55c2ee10158d5943f 100644 --- a/src/app/features/deposit/enums/deposit-tab.enum.ts +++ b/src/app/features/deposit/enums/deposit-tab.enum.ts @@ -1,5 +1,6 @@ export enum DepositTabEnum { metadata = 0, file = 1, - upload = 2, + collection = 2, + upload = 3, } diff --git a/src/app/features/deposit/helpers/deposit.helper.ts b/src/app/features/deposit/helpers/deposit.helper.ts index 5c828545b804d43d4c64429322e3d051d6ae4101..d1073820a783926d8b3f38b8528730597e44b605 100644 --- a/src/app/features/deposit/helpers/deposit.helper.ts +++ b/src/app/features/deposit/helpers/deposit.helper.ts @@ -34,6 +34,9 @@ export class DepositHelper { if (tabRouteSelected === DepositRoutesEnum.upload) { return DepositTabEnum.upload; } + if (tabRouteSelected === DepositRoutesEnum.collection) { + return DepositTabEnum.collection; + } return undefined; } @@ -47,6 +50,9 @@ export class DepositHelper { if (tabIndexSelected === DepositTabEnum.upload) { return DepositRoutesEnum.upload; } + if (tabIndexSelected === DepositTabEnum.collection) { + return DepositRoutesEnum.collection; + } return undefined; } diff --git a/src/app/features/deposit/stores/aip/deposit-aip.action.ts b/src/app/features/deposit/stores/aip/deposit-aip.action.ts new file mode 100644 index 0000000000000000000000000000000000000000..e627dc53c446e3c7e2f3d32de78f5b6abeac9c6f --- /dev/null +++ b/src/app/features/deposit/stores/aip/deposit-aip.action.ts @@ -0,0 +1,105 @@ +import {LocalStateEnum} from "@app/shared/enums/local-state.enum"; +import {AipExtended} from "@preservation/aip/models/aip-extended.model"; +import { + ResourceAction, + ResourceNameSpace, + TypeDefaultAction, +} from "solidify-frontend"; + +const state = LocalStateEnum.deposit_aip; + +export namespace DepositAipAction { + @TypeDefaultAction(state) + export class LoadResource extends ResourceAction.LoadResource { + } + + @TypeDefaultAction(state) + export class LoadResourceSuccess extends ResourceAction.LoadResourceSuccess { + } + + @TypeDefaultAction(state) + export class LoadResourceFail extends ResourceAction.LoadResourceFail { + } + + @TypeDefaultAction(state) + export class ChangeQueryParameters extends ResourceAction.ChangeQueryParameters { + } + + @TypeDefaultAction(state) + export class GetAll extends ResourceAction.GetAll { + } + + @TypeDefaultAction(state) + export class GetAllSuccess extends ResourceAction.GetAllSuccess<AipExtended> { + } + + @TypeDefaultAction(state) + export class GetAllFail extends ResourceAction.GetAllFail<AipExtended> { + } + + @TypeDefaultAction(state) + export class GetByListId extends ResourceAction.GetByListId { + } + + @TypeDefaultAction(state) + export class GetByListIdSuccess extends ResourceAction.GetByListIdSuccess { + } + + @TypeDefaultAction(state) + export class GetByListIdFail extends ResourceAction.GetByListIdFail { + } + + @TypeDefaultAction(state) + export class GetById extends ResourceAction.GetById { + } + + @TypeDefaultAction(state) + export class GetByIdSuccess extends ResourceAction.GetByIdSuccess<AipExtended> { + } + + @TypeDefaultAction(state) + export class GetByIdFail extends ResourceAction.GetByIdFail<AipExtended> { + } + + @TypeDefaultAction(state) + export class Create extends ResourceAction.Create<AipExtended> { + } + + @TypeDefaultAction(state) + export class CreateSuccess extends ResourceAction.CreateSuccess<AipExtended> { + } + + @TypeDefaultAction(state) + export class CreateFail extends ResourceAction.CreateFail<AipExtended> { + } + + @TypeDefaultAction(state) + export class Update extends ResourceAction.Update<AipExtended> { + } + + @TypeDefaultAction(state) + export class UpdateSuccess extends ResourceAction.UpdateSuccess<AipExtended> { + } + + @TypeDefaultAction(state) + export class UpdateFail extends ResourceAction.UpdateFail<AipExtended> { + } + + @TypeDefaultAction(state) + export class Delete extends ResourceAction.Delete { + } + + @TypeDefaultAction(state) + export class DeleteSuccess extends ResourceAction.DeleteSuccess { + } + + @TypeDefaultAction(state) + export class DeleteFail extends ResourceAction.DeleteFail { + } + + @TypeDefaultAction(state) + export class Clean extends ResourceAction.Clean { + } +} + +export const depositAipActionNameSpace: ResourceNameSpace = DepositAipAction; diff --git a/src/app/features/deposit/stores/aip/deposit-aip.state.ts b/src/app/features/deposit/stores/aip/deposit-aip.state.ts new file mode 100644 index 0000000000000000000000000000000000000000..818bf30bc6bc5d210f0e45c3624999259efe303f --- /dev/null +++ b/src/app/features/deposit/stores/aip/deposit-aip.state.ts @@ -0,0 +1,41 @@ +import {depositAipActionNameSpace} from "@deposit/stores/aip/deposit-aip.action"; +import { + Actions, + State, + Store, +} from "@ngxs/store"; +import {AipExtended} from "@preservation/aip/models/aip-extended.model"; +import {ArchivalStorageResourceApiEnum} from "@shared/enums/api.enum"; +import {LocalStateEnum} from "@shared/enums/local-state.enum"; +import { + ApiService, + defaultResourceStateInitValue, + NotificationService, + ResourceState, + ResourceStateModel, +} from "solidify-frontend"; + +export interface DepositAipStateModel extends ResourceStateModel<AipExtended> { +} + +@State<DepositAipStateModel>({ + name: LocalStateEnum.deposit_aip, + defaults: { + ...defaultResourceStateInitValue(), + }, +}) +export class DepositAipState extends ResourceState<DepositAipStateModel, AipExtended> { + + constructor(protected apiService: ApiService, + protected store: Store, + protected notificationService: NotificationService, + protected actions$: Actions) { + super(apiService, store, notificationService, actions$, { + nameSpace: depositAipActionNameSpace, + }); + } + + protected get _urlResource(): string { + return ArchivalStorageResourceApiEnum.aip; + } +} diff --git a/src/app/features/deposit/stores/collection/deposit-collection.action.ts b/src/app/features/deposit/stores/collection/deposit-collection.action.ts new file mode 100644 index 0000000000000000000000000000000000000000..c9e430244c44bac9746e8dee609bd934457aa212 --- /dev/null +++ b/src/app/features/deposit/stores/collection/deposit-collection.action.ts @@ -0,0 +1,115 @@ +import {LocalStateEnum} from "@app/shared/enums/local-state.enum"; +import {AipExtended} from "@preservation/aip/models/aip-extended.model"; +import { + AssociationRemoteAction, + AssociationRemoteNameSpace, + QueryParameters, + TypeDefaultAction, +} from "solidify-frontend"; + +const state = LocalStateEnum.deposit_collection; + +export namespace DepositCollectionAction { + + @TypeDefaultAction(state) + export class GetAll extends AssociationRemoteAction.GetAll { + } + + @TypeDefaultAction(state) + export class GetAllSuccess extends AssociationRemoteAction.GetAllSuccess<AipExtended> { + } + + @TypeDefaultAction(state) + export class GetAllFail extends AssociationRemoteAction.GetAllFail { + } + + @TypeDefaultAction(state) + export class GetById extends AssociationRemoteAction.GetById { + } + + @TypeDefaultAction(state) + export class GetByIdSuccess extends AssociationRemoteAction.GetByIdSuccess<AipExtended> { + } + + @TypeDefaultAction(state) + export class GetByIdFail extends AssociationRemoteAction.GetByIdFail { + } + + @TypeDefaultAction(state) + export class Update extends AssociationRemoteAction.Update { + } + + @TypeDefaultAction(state) + export class UpdateSuccess extends AssociationRemoteAction.UpdateSuccess { + } + + @TypeDefaultAction(state) + export class UpdateFail extends AssociationRemoteAction.UpdateFail { + } + + @TypeDefaultAction(state) + export class Create extends AssociationRemoteAction.Create { + } + + @TypeDefaultAction(state) + export class CreateSuccess extends AssociationRemoteAction.CreateSuccess { + } + + @TypeDefaultAction(state) + export class CreateFail extends AssociationRemoteAction.CreateFail { + } + + @TypeDefaultAction(state) + export class Delete extends AssociationRemoteAction.Delete { + } + + @TypeDefaultAction(state) + export class DeleteSuccess extends AssociationRemoteAction.DeleteSuccess { + } + + @TypeDefaultAction(state) + export class DeleteFail extends AssociationRemoteAction.DeleteFail { + } + + @TypeDefaultAction(state) + export class DeleteList extends AssociationRemoteAction.DeleteList { + } + + @TypeDefaultAction(state) + export class DeleteListSuccess extends AssociationRemoteAction.DeleteListSuccess { + } + + @TypeDefaultAction(state) + export class DeleteListFail extends AssociationRemoteAction.DeleteListFail { + } + + export class ChangeQueryParameters { + static readonly type: string = `[${state}] Change Query Parameters`; + + constructor(public parentId: string, public queryParameters: QueryParameters, public keepCurrentContext: boolean = false) { + } + } + + export class GoToAip { + static readonly type: string = `[${state}] Go To Aip`; + + constructor(public aip: AipExtended) { + } + } + + export class Refresh { + static readonly type: string = `[${state}] Refresh`; + + constructor(public parentId: string) { + } + } + + export class AddAip { + static readonly type: string = `[${state}] Add Aip`; + + constructor(public parentId: string, public aipIds: string[]) { + } + } +} + +export const depositCollectionActionNameSpace: AssociationRemoteNameSpace = DepositCollectionAction; diff --git a/src/app/features/deposit/stores/collection/deposit-collection.state.ts b/src/app/features/deposit/stores/collection/deposit-collection.state.ts new file mode 100644 index 0000000000000000000000000000000000000000..2595f4cc289cc4188bed35977b9e456b2e7bf922 --- /dev/null +++ b/src/app/features/deposit/stores/collection/deposit-collection.state.ts @@ -0,0 +1,91 @@ +import { + DepositCollectionAction, + depositCollectionActionNameSpace, +} from "@deposit/stores/collection/deposit-collection.action"; +import {Navigate} from "@ngxs/router-plugin"; +import { + Action, + Actions, + State, + StateContext, + Store, +} from "@ngxs/store"; +import {AipExtended} from "@preservation/aip/models/aip-extended.model"; +import {ApiResourceNameEnum} from "@shared/enums/api-resource-name.enum"; +import {PreIngestResourceApiEnum} from "@shared/enums/api.enum"; +import {LocalStateEnum} from "@shared/enums/local-state.enum"; +import { + AppRoutesEnum, + PreservationPlanningRoutesEnum, + RoutesEnum, + urlSeparator, +} from "@shared/enums/routes.enum"; +import { + ApiService, + AssociationRemoteState, + AssociationRemoteStateModel, + defaultAssociationRemoteStateInitValue, + NotificationService, + QueryParameters, +} from "solidify-frontend"; + +export const defaultDepositCollectionValue: () => DepositCollectionStateModel = () => + ({ + ...defaultAssociationRemoteStateInitValue(), + listAips: [], + queryParameters: new QueryParameters(), + }); + +export interface DepositCollectionStateModel extends AssociationRemoteStateModel<AipExtended> { + listAips: string[]; + queryParameters: QueryParameters; +} + +@State<DepositCollectionStateModel>({ + name: LocalStateEnum.deposit_collection, + defaults: { + ...defaultDepositCollectionValue(), + }, +}) +export class DepositCollectionState extends AssociationRemoteState<DepositCollectionStateModel, AipExtended> { + constructor(protected apiService: ApiService, + protected store: Store, + protected notificationService: NotificationService, + protected actions$: Actions) { + super(apiService, store, notificationService, actions$, { + nameSpace: depositCollectionActionNameSpace, + resourceName: ApiResourceNameEnum.AIP, + }); + } + + protected get _urlResource(): string { + return PreIngestResourceApiEnum.deposits; + } + + @Action(DepositCollectionAction.ChangeQueryParameters) + changeQueryParameters(ctx: StateContext<DepositCollectionStateModel>, action: DepositCollectionAction.ChangeQueryParameters): void { + ctx.patchState({ + queryParameters: action.queryParameters, + }); + ctx.dispatch(new DepositCollectionAction.GetAll(action.parentId, undefined, action.keepCurrentContext)); + } + + @Action(DepositCollectionAction.Refresh) + refresh(ctx: StateContext<DepositCollectionStateModel>, action: DepositCollectionAction.Refresh): void { + ctx.dispatch(new DepositCollectionAction.GetAll(action.parentId, undefined, true)); + } + + @Action(DepositCollectionAction.GoToAip) + goToAip(ctx: StateContext<DepositCollectionStateModel>, action: DepositCollectionAction.GoToAip): void { + const pathAipDetail = RoutesEnum.preservationAip + urlSeparator + 1 + urlSeparator + PreservationPlanningRoutesEnum.aipDetail + AppRoutesEnum.separator; + const path = [pathAipDetail, action.aip.resId]; + ctx.dispatch(new Navigate(path)); + } + + @Action(DepositCollectionAction.AddAip) + addAip(ctx: StateContext<DepositCollectionStateModel>, action: DepositCollectionAction.AddAip): void { + ctx.dispatch(new DepositCollectionAction.Create(action.parentId, action.aipIds)); + ctx.dispatch(new DepositCollectionAction.Refresh(action.parentId)); + } + +} diff --git a/src/app/features/deposit/stores/deposit.action.ts b/src/app/features/deposit/stores/deposit.action.ts index 8816d1da6a5a677bc11fc6254af4eed67caf9f6e..ff56dc756d1d4ac37470dbc665f862a0db008a94 100644 --- a/src/app/features/deposit/stores/deposit.action.ts +++ b/src/app/features/deposit/stores/deposit.action.ts @@ -1,3 +1,4 @@ +import {readNgcCommandLineAndConfiguration} from "@angular/compiler-cli/src/main"; import {DepositDataFile} from "@app/features/deposit/models/deposit-data-file.model"; import {DepositExtended} from "@app/features/deposit/models/deposits-extended.model"; import {FileUploadWrapper} from "@app/features/deposit/models/file-upload-wrapper.model"; @@ -5,6 +6,7 @@ import {UploadFileStatus} from "@app/features/deposit/models/upload-file-status. import {Deposit} from "@app/generated-api/model/deposit.model"; import {LocalStateEnum} from "@app/shared/enums/local-state.enum"; import { + associationNoSqlReadOnlyActionNameSpace, BaseAction, BaseSubAction, ErrorDto, @@ -297,6 +299,13 @@ export namespace DepositAction { export class RefreshCounterStatusTabFail extends BaseSubAction<RefreshCounterStatusTab> { static readonly type: string = `[${state}] Refresh Counter Status Tab Fail`; } + + export class ChangeEditProperty { + static readonly type: string = `[${state}] Change Edit Property`; + + constructor(public isEditable: boolean) { + } + } } export const depositActionNameSpace: ResourceNameSpace = DepositAction; diff --git a/src/app/features/deposit/stores/deposit.state.ts b/src/app/features/deposit/stores/deposit.state.ts index cc14197eaa1d484d57d4427fcc75cfe3ca682fa3..e0afc65cf3b51eb64a308488df4d585159df53b2 100644 --- a/src/app/features/deposit/stores/deposit.state.ts +++ b/src/app/features/deposit/stores/deposit.state.ts @@ -39,6 +39,15 @@ import {SharedPreservationPolicyAction} from "@app/shared/stores/preservation-po import {SharedSubmissionPolicyAction} from "@app/shared/stores/submission-policy/shared-submission-policy.action"; import {AppAction} from "@app/stores/app.action"; import {AppAuthorizedOrganizationalUnitState} from "@app/stores/authorized-organizational-unit/app-authorized-organizational-unit.state"; +import { + DepositAipState, + DepositAipStateModel, +} from "@deposit/stores/aip/deposit-aip.state"; +import { + defaultDepositCollectionValue, + DepositCollectionState, + DepositCollectionStateModel, +} from "@deposit/stores/collection/deposit-collection.state"; import {DepositOrganizationalUnitState} from "@deposit/stores/organizational-unit/deposit-organizational-unit.state"; import { DepositStatusHistoryState, @@ -91,6 +100,8 @@ import { export interface DepositStateModel extends ResourceStateModel<DepositExtended> { deposit_dataFile: DepositDataFileStateModel; deposit_person: DepositPersonStateModel; + deposit_collection: DepositCollectionStateModel; + deposit_aip: DepositAipStateModel; isLoadingDataFile: boolean; uploadStatus: UploadFileStatus[]; deposit_statusHistory: DepositStatusHistoryStateModel; @@ -102,6 +113,7 @@ export interface DepositStateModel extends ResourceStateModel<DepositExtended> { counterTabRejected: number | undefined; counterTabInError: number | undefined; counterTabAll: number | undefined; + canEdit: boolean; } @State<DepositStateModel>({ @@ -110,6 +122,8 @@ export interface DepositStateModel extends ResourceStateModel<DepositExtended> { ...defaultResourceStateInitValue(), deposit_dataFile: defaultDepositDataFileValue(), deposit_person: {...defaultAssociationRemoteStateInitValue()}, + deposit_collection: defaultDepositCollectionValue(), + deposit_aip: {...defaultResourceStateInitValue()}, isLoadingDataFile: false, uploadStatus: [], deposit_statusHistory: {...defaultStatusHistoryInitValue()}, @@ -121,12 +135,15 @@ export interface DepositStateModel extends ResourceStateModel<DepositExtended> { counterTabRejected: undefined, counterTabInError: undefined, counterTabAll: undefined, + canEdit: false, }, children: [ DepositDataFileState, DepositPeopleState, DepositStatusHistoryState, DepositOrganizationalUnitState, + DepositCollectionState, + DepositAipState ], }) export class DepositState extends ResourceState<DepositStateModel, DepositExtended> { @@ -691,4 +708,11 @@ export class DepositState extends ResourceState<DepositStateModel, DepositExtend ctx.dispatch(new Navigate([RoutesEnum.deposit, ctx.getState().organizationalUnit.resId, DepositRoutesEnum.detail, depositId])); ctx.dispatch(new DepositAction.GetById(depositId)); } + + @Action(DepositAction.ChangeEditProperty) + changeEditProperty(ctx: StateContext<DepositStateModel>, action: DepositAction.ChangeEditProperty): void { + ctx.patchState({ + canEdit: action.isEditable, + }); + } } diff --git a/src/app/features/preservation/aip/components/routables/aip-aip/aip-aip.routable.ts b/src/app/features/preservation/aip/components/routables/aip-aip/aip-aip.routable.ts index 9c68bce2eeff11772c331ab8cbdab8927ada8f1a..dab20a0d0fedbc882a7188bf9cc9835ceef22878 100644 --- a/src/app/features/preservation/aip/components/routables/aip-aip/aip-aip.routable.ts +++ b/src/app/features/preservation/aip/components/routables/aip-aip/aip-aip.routable.ts @@ -27,8 +27,8 @@ import { SharedAipDetailDialogData, } from "@shared/components/dialogs/shared-aip-detail/shared-aip-detail.dialog"; import {SharedAbstractDetailEditRoutable} from "@shared/components/routables/shared-abstract-detail-edit/shared-abstract-detail-edit.routable"; -import {ComplianceLevelEnum} from "@shared/enums/business/compliance-level.enum"; -import {DataFileStatusEnum} from "@shared/enums/business/data-file-status.enum"; +import {ComplianceLevelEnumHelper} from "@shared/enums/business/compliance-level.enum"; +import {DataFileStatusEnumHelper} from "@shared/enums/business/data-file-status.enum"; import {DataTableComponentEnum} from "@shared/enums/data-table-component.enum"; import {FieldTypeEnum} from "@shared/enums/field-type.enum"; import {LocalStateEnum} from "@shared/enums/local-state.enum"; @@ -108,52 +108,7 @@ export class AipAipRoutable extends SharedAbstractDetailEditRoutable<AipExtended isSortable: false, isFilterable: false, translate: true, - filterEnum: [ - { - key: DataFileStatusEnum.IN_ERROR, - value: TRANSLATE("IN_ERROR"), - }, - { - key: DataFileStatusEnum.READY, - value: TRANSLATE("READY"), - }, - { - key: DataFileStatusEnum.RECEIVED, - value: TRANSLATE("RECEIVED"), - }, - { - key: DataFileStatusEnum.CHANGE_RELATIVE_LOCATION, - value: TRANSLATE("CHANGE_RELATIVE_LOCATION"), - }, - { - key: DataFileStatusEnum.TO_PROCESS, - value: TRANSLATE("TO_PROCESS"), - }, - { - key: DataFileStatusEnum.PROCESSED, - value: TRANSLATE("PROCESSED"), - }, - { - key: DataFileStatusEnum.FILE_FORMAT_IDENTIFIED, - value: TRANSLATE("FILE_FORMAT_IDENTIFIED"), - }, - { - key: DataFileStatusEnum.FILE_FORMAT_UNKNOWN, - value: TRANSLATE("FILE_FORMAT_UNKNOWN"), - }, - { - key: DataFileStatusEnum.VIRUS_CHECKED, - value: TRANSLATE("VIRUS_CHECKED"), - }, - { - key: DataFileStatusEnum.CLEANING, - value: TRANSLATE("CLEANING"), - }, - { - key: DataFileStatusEnum.CLEANED, - value: TRANSLATE("CLEANED"), - }, - ], + filterEnum: DataFileStatusEnumHelper.getListKeyValue(), }, { field: "info.complianceLevel" as any, @@ -164,28 +119,7 @@ export class AipAipRoutable extends SharedAbstractDetailEditRoutable<AipExtended isFilterable: false, translate: true, component: DataTableComponentEnum.conformityLevelStar, - filterEnum: [ - { - key: ComplianceLevelEnum.FULL_COMPLIANCE, - value: TRANSLATE("FULL_COMPLIANCE"), - }, - { - key: ComplianceLevelEnum.AVERAGE_COMPLIANCE, - value: TRANSLATE("AVERAGE_COMPLIANCE"), - }, - { - key: ComplianceLevelEnum.WEAK_COMPLIANCE, - value: TRANSLATE("WEAK_COMPLIANCE"), - }, - { - key: ComplianceLevelEnum.NO_COMPLIANCE, - value: TRANSLATE("NO_COMPLIANCE"), - }, - { - key: ComplianceLevelEnum.NOT_ASSESSED, - value: TRANSLATE("NOT_ASSESSED"), - }, - ], + filterEnum: ComplianceLevelEnumHelper.getListKeyValue(), }, ]; diff --git a/src/app/features/preservation/aip/components/routables/aip-tabs/aip-tabs.routable.ts b/src/app/features/preservation/aip/components/routables/aip-tabs/aip-tabs.routable.ts index d4b543a298efa159747eb566be64812548dd0303..9cdc55db5e61629d1c36bf03c20efbf834d01f05 100644 --- a/src/app/features/preservation/aip/components/routables/aip-tabs/aip-tabs.routable.ts +++ b/src/app/features/preservation/aip/components/routables/aip-tabs/aip-tabs.routable.ts @@ -94,5 +94,4 @@ export class AipTabsRoutable extends SharedAbstractRoutable implements OnInit { this._store.dispatch(new Navigate([AppRoutesEnum.preservation, PreservationPlanningRoutesEnum.aip, this.storagionNode, PreservationPlanningRoutesEnum.aipList, tab])); } - } diff --git a/src/app/features/preservation/dip/components/routables/dip-file/dip-file.routable.ts b/src/app/features/preservation/dip/components/routables/dip-file/dip-file.routable.ts index a5331efd99dd5948a7f8dd8305208cb75086571d..3221f0927745ad0d25f5cf72aae1b1cc9fe755d1 100644 --- a/src/app/features/preservation/dip/components/routables/dip-file/dip-file.routable.ts +++ b/src/app/features/preservation/dip/components/routables/dip-file/dip-file.routable.ts @@ -26,8 +26,11 @@ import { SharedFileDetailDialogData, } from "@shared/components/dialogs/shared-file-detail/shared-file-detail.dialog"; import {SharedAbstractDetailEditRoutable} from "@shared/components/routables/shared-abstract-detail-edit/shared-abstract-detail-edit.routable"; -import {ComplianceLevelEnum} from "@shared/enums/business/compliance-level.enum"; -import {DataFileStatusEnum} from "@shared/enums/business/data-file-status.enum"; +import {ComplianceLevelEnumHelper} from "@shared/enums/business/compliance-level.enum"; +import { + DataFileStatusEnum, + DataFileStatusEnumHelper, +} from "@shared/enums/business/data-file-status.enum"; import {DataTableComponentEnum} from "@shared/enums/data-table-component.enum"; import {FieldTypeEnum} from "@shared/enums/field-type.enum"; import {LocalStateEnum} from "@shared/enums/local-state.enum"; @@ -105,52 +108,7 @@ export class DipFileRoutable extends SharedAbstractDetailEditRoutable<Dip, DipSt isSortable: false, isFilterable: false, translate: true, - filterEnum: [ - { - key: DataFileStatusEnum.IN_ERROR, - value: TRANSLATE("IN_ERROR"), - }, - { - key: DataFileStatusEnum.READY, - value: TRANSLATE("READY"), - }, - { - key: DataFileStatusEnum.RECEIVED, - value: TRANSLATE("RECEIVED"), - }, - { - key: DataFileStatusEnum.CHANGE_RELATIVE_LOCATION, - value: TRANSLATE("CHANGE_RELATIVE_LOCATION"), - }, - { - key: DataFileStatusEnum.TO_PROCESS, - value: TRANSLATE("TO_PROCESS"), - }, - { - key: DataFileStatusEnum.PROCESSED, - value: TRANSLATE("PROCESSED"), - }, - { - key: DataFileStatusEnum.FILE_FORMAT_IDENTIFIED, - value: TRANSLATE("FILE_FORMAT_IDENTIFIED"), - }, - { - key: DataFileStatusEnum.FILE_FORMAT_UNKNOWN, - value: TRANSLATE("FILE_FORMAT_UNKNOWN"), - }, - { - key: DataFileStatusEnum.VIRUS_CHECKED, - value: TRANSLATE("VIRUS_CHECKED"), - }, - { - key: DataFileStatusEnum.CLEANING, - value: TRANSLATE("CLEANING"), - }, - { - key: DataFileStatusEnum.CLEANED, - value: TRANSLATE("CLEANED"), - }, - ], + filterEnum: DataFileStatusEnumHelper.getListKeyValue(), }, { field: "complianceLevel", @@ -161,28 +119,7 @@ export class DipFileRoutable extends SharedAbstractDetailEditRoutable<Dip, DipSt isFilterable: false, translate: true, component: DataTableComponentEnum.conformityLevelStar, - filterEnum: [ - { - key: ComplianceLevelEnum.FULL_COMPLIANCE, - value: TRANSLATE("FULL_COMPLIANCE"), - }, - { - key: ComplianceLevelEnum.AVERAGE_COMPLIANCE, - value: TRANSLATE("AVERAGE_COMPLIANCE"), - }, - { - key: ComplianceLevelEnum.WEAK_COMPLIANCE, - value: TRANSLATE("WEAK_COMPLIANCE"), - }, - { - key: ComplianceLevelEnum.NO_COMPLIANCE, - value: TRANSLATE("NO_COMPLIANCE"), - }, - { - key: ComplianceLevelEnum.NOT_ASSESSED, - value: TRANSLATE("NOT_ASSESSED"), - }, - ], + filterEnum: ComplianceLevelEnumHelper.getListKeyValue(), }, ]; diff --git a/src/app/features/preservation/sip/components/routables/sip-file/sip-file.routable.ts b/src/app/features/preservation/sip/components/routables/sip-file/sip-file.routable.ts index 3c97eff44be560a8ee59891241dba2ca8d3e0c6b..0eb5981fd1cf9979b53f248397369191fae5b15f 100644 --- a/src/app/features/preservation/sip/components/routables/sip-file/sip-file.routable.ts +++ b/src/app/features/preservation/sip/components/routables/sip-file/sip-file.routable.ts @@ -26,8 +26,11 @@ import { SharedFileDetailDialogData, } from "@shared/components/dialogs/shared-file-detail/shared-file-detail.dialog"; import {SharedAbstractDetailEditRoutable} from "@shared/components/routables/shared-abstract-detail-edit/shared-abstract-detail-edit.routable"; -import {ComplianceLevelEnum} from "@shared/enums/business/compliance-level.enum"; -import {DataFileStatusEnum} from "@shared/enums/business/data-file-status.enum"; +import {ComplianceLevelEnumHelper} from "@shared/enums/business/compliance-level.enum"; +import { + DataFileStatusEnum, + DataFileStatusEnumHelper, +} from "@shared/enums/business/data-file-status.enum"; import {DataTableComponentEnum} from "@shared/enums/data-table-component.enum"; import {FieldTypeEnum} from "@shared/enums/field-type.enum"; import {LocalStateEnum} from "@shared/enums/local-state.enum"; @@ -105,52 +108,7 @@ export class SipFileRoutable extends SharedAbstractDetailEditRoutable<Sip, SipSt isSortable: false, isFilterable: false, translate: true, - filterEnum: [ - { - key: DataFileStatusEnum.IN_ERROR, - value: TRANSLATE("IN_ERROR"), - }, - { - key: DataFileStatusEnum.READY, - value: TRANSLATE("READY"), - }, - { - key: DataFileStatusEnum.RECEIVED, - value: TRANSLATE("RECEIVED"), - }, - { - key: DataFileStatusEnum.CHANGE_RELATIVE_LOCATION, - value: TRANSLATE("CHANGE_RELATIVE_LOCATION"), - }, - { - key: DataFileStatusEnum.TO_PROCESS, - value: TRANSLATE("TO_PROCESS"), - }, - { - key: DataFileStatusEnum.PROCESSED, - value: TRANSLATE("PROCESSED"), - }, - { - key: DataFileStatusEnum.FILE_FORMAT_IDENTIFIED, - value: TRANSLATE("FILE_FORMAT_IDENTIFIED"), - }, - { - key: DataFileStatusEnum.FILE_FORMAT_UNKNOWN, - value: TRANSLATE("FILE_FORMAT_UNKNOWN"), - }, - { - key: DataFileStatusEnum.VIRUS_CHECKED, - value: TRANSLATE("VIRUS_CHECKED"), - }, - { - key: DataFileStatusEnum.CLEANING, - value: TRANSLATE("CLEANING"), - }, - { - key: DataFileStatusEnum.CLEANED, - value: TRANSLATE("CLEANED"), - }, - ], + filterEnum: DataFileStatusEnumHelper.getListKeyValue(), }, { field: "complianceLevel", @@ -161,28 +119,7 @@ export class SipFileRoutable extends SharedAbstractDetailEditRoutable<Sip, SipSt isFilterable: false, translate: true, component: DataTableComponentEnum.conformityLevelStar, - filterEnum: [ - { - key: ComplianceLevelEnum.FULL_COMPLIANCE, - value: TRANSLATE("FULL_COMPLIANCE"), - }, - { - key: ComplianceLevelEnum.AVERAGE_COMPLIANCE, - value: TRANSLATE("AVERAGE_COMPLIANCE"), - }, - { - key: ComplianceLevelEnum.WEAK_COMPLIANCE, - value: TRANSLATE("WEAK_COMPLIANCE"), - }, - { - key: ComplianceLevelEnum.NO_COMPLIANCE, - value: TRANSLATE("NO_COMPLIANCE"), - }, - { - key: ComplianceLevelEnum.NOT_ASSESSED, - value: TRANSLATE("NOT_ASSESSED"), - }, - ], + filterEnum: ComplianceLevelEnumHelper.getListKeyValue(), }, ]; diff --git a/src/app/shared/components/dialogs/shared-aip-detail/shared-aip-detail.dialog.html b/src/app/shared/components/dialogs/shared-aip-detail/shared-aip-detail.dialog.html index 8a422dc153cc1deafecd00bcc2ee2fb97bbe078d..f3e8940cb1a69ad18a56f392788d9d0ade5b8fca 100644 --- a/src/app/shared/components/dialogs/shared-aip-detail/shared-aip-detail.dialog.html +++ b/src/app/shared/components/dialogs/shared-aip-detail/shared-aip-detail.dialog.html @@ -15,6 +15,7 @@ </ng-container> <button mat-button + *ngIf="data.isLoading !== null" color="accent" (click)="showHistory()" > diff --git a/src/app/shared/enums/business/compliance-level.enum.ts b/src/app/shared/enums/business/compliance-level.enum.ts index 475c34230a961424875fc16912ce80143d674f5f..e62ac5c81fea8d239c75fc2f013f33bdd8aff0e8 100644 --- a/src/app/shared/enums/business/compliance-level.enum.ts +++ b/src/app/shared/enums/business/compliance-level.enum.ts @@ -1,3 +1,8 @@ +import { + KeyValue, + TRANSLATE, +} from "solidify-frontend"; + export enum ComplianceLevelEnum { NOT_ASSESSED = "NOT_ASSESSED", NO_COMPLIANCE = "NO_COMPLIANCE", @@ -13,3 +18,30 @@ export enum ComplianceLevelNumberEnum { AVERAGE_COMPLIANCE = 2, FULL_COMPLIANCE = 3, } + +export class ComplianceLevelEnumHelper { + static getListKeyValue(): KeyValue[] { + return [ + { + key: ComplianceLevelEnum.FULL_COMPLIANCE, + value: TRANSLATE("FULL_COMPLIANCE"), + }, + { + key: ComplianceLevelEnum.AVERAGE_COMPLIANCE, + value: TRANSLATE("AVERAGE_COMPLIANCE"), + }, + { + key: ComplianceLevelEnum.WEAK_COMPLIANCE, + value: TRANSLATE("WEAK_COMPLIANCE"), + }, + { + key: ComplianceLevelEnum.NO_COMPLIANCE, + value: TRANSLATE("NO_COMPLIANCE"), + }, + { + key: ComplianceLevelEnum.NOT_ASSESSED, + value: TRANSLATE("NOT_ASSESSED"), + }, + ]; + } +} diff --git a/src/app/shared/enums/local-state.enum.ts b/src/app/shared/enums/local-state.enum.ts index 2053bf25bafd6de71423682d755305ca0fcd29b3..8e7d3cf2ea260891eabb92e52d0edca95c9fd64d 100644 --- a/src/app/shared/enums/local-state.enum.ts +++ b/src/app/shared/enums/local-state.enum.ts @@ -15,8 +15,10 @@ export enum LocalStateEnum { deposit_person = "deposit_person", deposit_organizationalUnit = "deposit_organizationalUnit", deposit_dataFile = "deposit_dataFile", + deposit_collection = "deposit_collection", deposit_statusHistory = "deposit_statusHistory", deposit_dataFile_statusHistory = "deposit_dataFile_statusHistory", + deposit_aip = "deposit_aip", organizationalUnit = "organizationalUnit", organizationalUnit_personRole = "organizationalUnit_personRole", diff --git a/src/app/shared/enums/routes.enum.ts b/src/app/shared/enums/routes.enum.ts index beb64cd1a4488e3792bcbb36e330d6133a68c5b3..567a2a7294922ac9e2e40191ce92590a2a1b3102 100644 --- a/src/app/shared/enums/routes.enum.ts +++ b/src/app/shared/enums/routes.enum.ts @@ -30,6 +30,7 @@ export enum DepositRoutesEnum { metadata = "metadata", files = "files", upload = "upload", + collection = "collection", paramTab = ":tab", paramTabWithoutPrefix = "tab", } diff --git a/src/assets/i18n/de.json b/src/assets/i18n/de.json index bd2e5b34ac5e4d28e6e7944c5fec5b986b278c5e..41272367547603d081782b91a09ec5a8052ee059 100644 --- a/src/assets/i18n/de.json +++ b/src/assets/i18n/de.json @@ -842,6 +842,7 @@ } }, "deposit": { + "collection": "Collection", "create": "Create", "edit": "Edit", "file": "Data files", @@ -901,6 +902,27 @@ "deposit": { "accessLevel": "Access Level", "addMeAsAuthor": "add me as author", + "aip": { + "modal": { + "button": { + "close": "Close", + "confirmUpload": "Confirm" + }, + "noAipFound": "No archive found", + "title": { + "main": "Add existing archives to collection", + "search": "Search for archives" + } + }, + "table": { + "aipName": "Aip Name", + "complianceLevel": "Compliance Level", + "status": "Status" + }, + "title": { + "collection": "Collection" + } + }, "alert": { "status": { "completed": "The submission of the deposit has been completed", @@ -916,6 +938,14 @@ "title": "Authors" }, "backToEdit": "Return to editing", + "collection": { + "button": { + "addAip": { + "label": "Add archives", + "tooltip": "Add existing archives to collection" + } + } + }, "collectionBegin": "Data Collection Start Date", "collectionEnd": "Data Collection End Date", "datafile": { @@ -954,7 +984,10 @@ "showHistory": "Show history", "showTree": "Folder view", "upload": "Upload files", - "uploadArchive": "Stuctured upload" + "uploadArchive": { + "label": "Stuctured upload", + "tooltip": "Uploading a zip file in this manner will decompress its contents while retaining its folder structure" + } }, "detail": { "data": { @@ -1089,10 +1122,10 @@ "popup": { "orderAuthors": { "button": { - "close": "deposit.popup.orderAuthors.button.close", - "validate": "deposit.popup.orderAuthors.button.validate" + "close": "Close", + "validate": "Validate" }, - "title": "deposit.popup.orderAuthors.title" + "title": "Ordering the authors" }, "person": { "alternative": { @@ -1124,6 +1157,7 @@ "submissionPolicy": "Submission Policy", "submit": "Submit", "tab": { + "collection": "Collection", "datafiles": "Files", "details": "Metadata", "upload": "Uploads" @@ -1739,4 +1773,4 @@ } } } -} \ No newline at end of file +} diff --git a/src/assets/i18n/en.json b/src/assets/i18n/en.json index b2ee1e550ed23ce8759263919ed997a01a1d3cbe..41272367547603d081782b91a09ec5a8052ee059 100644 --- a/src/assets/i18n/en.json +++ b/src/assets/i18n/en.json @@ -842,6 +842,7 @@ } }, "deposit": { + "collection": "Collection", "create": "Create", "edit": "Edit", "file": "Data files", @@ -901,6 +902,27 @@ "deposit": { "accessLevel": "Access Level", "addMeAsAuthor": "add me as author", + "aip": { + "modal": { + "button": { + "close": "Close", + "confirmUpload": "Confirm" + }, + "noAipFound": "No archive found", + "title": { + "main": "Add existing archives to collection", + "search": "Search for archives" + } + }, + "table": { + "aipName": "Aip Name", + "complianceLevel": "Compliance Level", + "status": "Status" + }, + "title": { + "collection": "Collection" + } + }, "alert": { "status": { "completed": "The submission of the deposit has been completed", @@ -916,6 +938,14 @@ "title": "Authors" }, "backToEdit": "Return to editing", + "collection": { + "button": { + "addAip": { + "label": "Add archives", + "tooltip": "Add existing archives to collection" + } + } + }, "collectionBegin": "Data Collection Start Date", "collectionEnd": "Data Collection End Date", "datafile": { @@ -954,7 +984,10 @@ "showHistory": "Show history", "showTree": "Folder view", "upload": "Upload files", - "uploadArchive": "Stuctured upload" + "uploadArchive": { + "label": "Stuctured upload", + "tooltip": "Uploading a zip file in this manner will decompress its contents while retaining its folder structure" + } }, "detail": { "data": { @@ -1124,6 +1157,7 @@ "submissionPolicy": "Submission Policy", "submit": "Submit", "tab": { + "collection": "Collection", "datafiles": "Files", "details": "Metadata", "upload": "Uploads" diff --git a/src/assets/i18n/fr.json b/src/assets/i18n/fr.json index 987cf3e878e540facf0905cb206df1c0e1e07cf7..4e18fa6c2e1992b98446c1f4f578b540a0a81db8 100644 --- a/src/assets/i18n/fr.json +++ b/src/assets/i18n/fr.json @@ -842,6 +842,7 @@ } }, "deposit": { + "collection": "Collection", "create": "Créer", "edit": "Modifier", "file": "Fichiers", @@ -901,6 +902,27 @@ "deposit": { "accessLevel": "Niveau d'accès", "addMeAsAuthor": "m'ajouter en tant qu'auteur", + "aip": { + "modal": { + "button": { + "close": "Fermer", + "confirmUpload": "Confirmer" + }, + "noAipFound": "Aucune archive trouvée", + "title": { + "main": "Ajouter des archives existantes à la collection", + "search": "Recherche d'archives" + } + }, + "table": { + "aipName": "Nom d'Aip", + "complianceLevel": "Niveau de conformité", + "status": "Statut" + }, + "title": { + "collection": "Collection" + } + }, "alert": { "status": { "completed": "La soumission du dépôt a été complétée", @@ -916,6 +938,14 @@ "title": "Auteurs" }, "backToEdit": "Retour en édition", + "collection": { + "button": { + "addAip": { + "label": "Ajouter archive", + "tooltip": "Ajouter une archive existante à la collection" + } + } + }, "collectionBegin": "Début de la collecte des données", "collectionEnd": "Fin de la collecte des données", "datafile": { @@ -954,7 +984,10 @@ "showHistory": "Voir l'historique", "showTree": "Voir l'arborescence", "upload": "Envoyer fichiers", - "uploadArchive": "Envoyer fichiers en lot" + "uploadArchive": { + "label": "Envoyer fichiers en lot", + "tooltip": "Le téléchargement d'un fichier zip de cette manière décompressera son contenu tout en conservant sa structure de dossiers" + } }, "detail": { "data": { @@ -1124,6 +1157,7 @@ "submissionPolicy": "Politique de soumission", "submit": "Enregistrer", "tab": { + "collection": "Collection", "datafiles": "Fichiers", "details": "Métadonnées", "upload": "Envois"