Commit c806c163 authored by Quentin Torck's avatar Quentin Torck
Browse files

Merge branch 'master' into qto-manage-shortcuts

parents 6f5404f7 abb8cb76
......@@ -27,6 +27,16 @@ const routes: DlcmRoutes = [
},
canActivate: [ApplicationRoleGuardService],
},
{
path: AppRoutesEnum.preservationSpace,
// @ts-ignore Dynamic import
loadChildren: () => import("./features/preservation-space/preservation-space.module").then(m => m.PreservationSpaceModule),
data: {
breadcrumb: TRANSLATE("breadcrumb.preservation-space.root"),
permission: ApplicationRolePermissionEnum.userPermission,
},
canActivate: [ApplicationRoleGuardService],
},
{
path: AppRoutesEnum.organizationalUnit,
// @ts-ignore Dynamic import
......
......@@ -124,8 +124,8 @@ export abstract class AbstractMainToolbarPresentational extends SharedAbstractPr
},
{
click: (menu) => this.navigate(menu.path),
path: RoutesEnum.organizationalUnit,
labelToTranslate: TRANSLATE("app.toolbar.organizationalUnit"),
path: RoutesEnum.preservationSpace,
labelToTranslate: TRANSLATE("app.toolbar.preservation-space"),
isVisible: () => PermissionUtil.isUserHavePermission(this.logged, ApplicationRolePermissionEnum.userPermission, this.userRoles),
icon: "users",
},
......
......@@ -35,7 +35,8 @@ import {
export class AdminMetadataTypeFormPresentational extends SharedAbstractFormPresentational<MetadataType> {
formDefinition: FormComponentFormDefinition = new FormComponentFormDefinition();
readonly files: string = "files";
readonly filesAccepted: string = ".xml, .json, .xsd, .txt";
readonly filesAccepted: string[] = [".xml", ".json", ".xsd", ".txt"];
readonly maxSizeFile: number = 25000000;
metadataFormatEnum: KeyValue[] = MetadataTypeFormatEnumHelper.getListKeyValue();
......@@ -80,8 +81,12 @@ export class AdminMetadataTypeFormPresentational extends SharedAbstractFormPrese
return;
}
const file: File = event.target.files[0];
if (!file.type.startsWith("text") && file.type !== "application/json" && file.type !== "") {
this._notificationService.showWarning(TRANSLATE("admin.metadataType.unableReadUploadedFile"));
if (!this.isFileAccepted(file)) {
this._notificationService.showWarning(TRANSLATE("admin.metadataType.fileNotSupported"));
return;
}
if (file.size > this.maxSizeFile) {
this._notificationService.showWarning(TRANSLATE("admin.metadataType.maximumSize"));
return;
}
const fileReader = new FileReader();
......@@ -99,6 +104,14 @@ export class AdminMetadataTypeFormPresentational extends SharedAbstractFormPrese
const file: File = event.target.files[0];
this._fileUploadBS.next(file);
}
isFileAccepted(file: File): boolean {
if (file.type.startsWith("text") || file.type === "application/json" || file.name.endsWith(".xsd")) {
return true;
}
return false;
}
}
class FormComponentFormDefinition extends BaseFormDefinition {
......
......@@ -49,19 +49,6 @@ export class OrgunitDetailEditRoutable extends SharedAbstractDetailEditCommonRou
readonly KEY_PARAM_NAME: keyof OrganizationalUnit & string = "name";
// private _isManager: boolean = false;
//
// set isManager(value: boolean) {
// if (isTrue(value) && isFalse(this._isManager)) {
// console.error("TEST", this._resId);
// this.store.dispatch(new OrgUnitPersonRoleAction.GetAll(this._resId));
// }
// this._isManager = value;
// }
//
// get isManager(): boolean {
// return this._isManager;
// }
constructor(protected _store: Store,
protected _route: ActivatedRoute,
......
<h1>{{'preservation.space.home.title' | translate}}</h1>
<div class="cards-container">
<mat-card *ngFor="let resource of getPreservationSpaceResources()"
class="card"
(click)="navigate(resource.path)"
>
<mat-card-header class="card-header">
<div class="avatar"
mat-card-avatar
>
<fa-icon [icon]="resource.avatarIcon"></fa-icon>
</div>
<mat-card-title>{{resource.titleToTranslate | translate}}</mat-card-title>
<mat-card-subtitle>{{resource.subtitleToTranslate | translate}}</mat-card-subtitle>
</mat-card-header>
</mat-card>
</div>
import {HttpClientTestingModule} from "@angular/common/http/testing";
import {NO_ERRORS_SCHEMA} from "@angular/core";
import {async, ComponentFixture, TestBed,} from "@angular/core/testing";
import {ReactiveFormsModule} from "@angular/forms";
import {SharedSearchPresentational} from "@app/shared/components/presentationals/shared-search/shared-search.presentational";
import {TranslateService} from "@ngx-translate/core";
import {NgxsModule} from "@ngxs/store";
import {MockTranslatePipe} from "../../../../../../test-helpers/mock-translate.pipe";
import {MockTranslateService} from "../../../../../../test-helpers/mock-translate.service";
import {PreservationSpaceHomeRoutable} from "./preservation-space-home.routable";
describe("AdminHomeRoutable", () => {
let component: PreservationSpaceHomeRoutable;
let fixture: ComponentFixture<PreservationSpaceHomeRoutable>;
beforeEach(async(() => {
TestBed.configureTestingModule({
imports: [ReactiveFormsModule, HttpClientTestingModule, NgxsModule.forRoot([])],
declarations: [PreservationSpaceHomeRoutable, SharedSearchPresentational, MockTranslatePipe],
providers: [
{
provide: TranslateService,
useClass: MockTranslateService,
},
],
schemas: [NO_ERRORS_SCHEMA],
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(PreservationSpaceHomeRoutable);
component = fixture.componentInstance;
fixture.detectChanges();
});
xit("should create", () => {
expect(component).toBeTruthy();
});
});
import {ChangeDetectionStrategy, Component,} from "@angular/core";
import {SharedAbstractPresentational} from "@app/shared/components/presentationals/shared-abstract/shared-abstract.presentational";
import {ApplicationRoleEnum} from "@app/shared/enums/application-role.enum";
import {RoutesEnum} from "@app/shared/enums/routes.enum";
import {LocalStateModel} from "@app/shared/models/local-state.model";
import {Navigate} from "@ngxs/router-plugin";
import {Store} from "@ngxs/store";
import {TRANSLATE} from "solidify-frontend";
@Component({
selector: "dlcm-admin-home-routable",
templateUrl: "./preservation-space-home.routable.html",
styleUrls: ["./preservation-space-home.routable.scss"],
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class PreservationSpaceHomeRoutable extends SharedAbstractPresentational {
userRolesObs: ApplicationRoleEnum[];
preservationSpaceResources: PreservationSpaceResource[] = [
{
avatarIcon: "building",
titleToTranslate: TRANSLATE("admin.organizationalUnit.home.title"),
subtitleToTranslate: TRANSLATE("admin.organizationalUnit.home.subtitle"),
path: RoutesEnum.organizationalUnit,
isVisible: () => true,
},
{
avatarIcon: "file-upload",
titleToTranslate: TRANSLATE("admin.deposit.home.title"),
subtitleToTranslate: TRANSLATE("admin.deposit.home.subtitle"),
path: RoutesEnum.deposit,
isVisible: () => true,
},
{
avatarIcon: "user-edit",
titleToTranslate: TRANSLATE("admin.contributor.home.title"),
subtitleToTranslate: TRANSLATE("admin.contributor.home.subtitle"),
path: RoutesEnum.contributor,
isVisible: () => true,
}
];
constructor(private store: Store) {
super();
this.userRolesObs = this.store.selectSnapshot((state: LocalStateModel) => state.application.userRoles);
}
navigate(path: RoutesEnum): void {
this.store.dispatch(new Navigate([path]));
}
getPreservationSpaceResources(): PreservationSpaceResource[] {
return this.preservationSpaceResources.filter((resource) => resource.isVisible() === true);
}
}
interface PreservationSpaceResource {
avatarIcon: string;
titleToTranslate: string;
subtitleToTranslate: string;
path: RoutesEnum;
isVisible: () => boolean;
}
<form [formGroup]="form"
(ngSubmit)="onSubmit()"
>
<mat-form-field>
<mat-label>{{'admin.contributor.form.lastName' | translate }}</mat-label>
<input matInput
[formControlName]="formDefinition.lastName"
[required]="isRequired(formDefinition.lastName)"
>
</mat-form-field>
<mat-form-field>
<mat-label>{{'admin.contributor.form.firstName' | translate}}</mat-label>
<input matInput
[formControlName]="formDefinition.firstName"
[required]="isRequired(formDefinition.firstName)"
>
</mat-form-field>
<mat-form-field>
<mat-label>{{'admin.contributor.form.orcid' | translate }}</mat-label>
<input matInput
[formControlName]="formDefinition.orcid"
[required]="isRequired(formDefinition.orcid)"
>
</mat-form-field>
</form>
import {
ChangeDetectionStrategy,
ChangeDetectorRef,
Component,
} from "@angular/core";
import {FormBuilder} from "@angular/forms";
import {Contributor} from "@app/generated-api/model/contributor.partial.model";
import {SharedAbstractFormPresentational} from "@shared/components/presentationals/shared-abstract-form/shared-abstract-form.presentational";
import {BaseFormDefinition} from "@shared/models/base-form-definition.model";
import {BreakpointService} from "@shared/services/breakpoint.service";
import {PropertyName} from "solidify-frontend";
@Component({
selector: "dlcm-contributor-form",
templateUrl: "./contributor-form.presentational.html",
styleUrls: ["../../../../../../shared/components/presentationals/shared-abstract-form/shared-abstract-form.presentational.scss"],
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class ContributorFormPresentational extends SharedAbstractFormPresentational<Contributor> {
formDefinition: FormComponentFormDefinition = new FormComponentFormDefinition();
constructor(protected readonly _changeDetectorRef: ChangeDetectorRef,
private readonly _fb: FormBuilder,
public readonly breakpointService: BreakpointService) {
super(_changeDetectorRef);
}
protected initNewForm(): void {
this.form = this._fb.group({
[this.formDefinition.lastName]: [""],
[this.formDefinition.firstName]: [""],
[this.formDefinition.orcid]: [""],
});
}
protected bindFormTo(contributor: Contributor): void {
this.form = this._fb.group({
[this.formDefinition.lastName]: [contributor.lastName],
[this.formDefinition.firstName]: [contributor.firstName],
[this.formDefinition.orcid]: [contributor.orcid],
});
}
protected treatmentBeforeSubmit(model: Contributor): Contributor {
return undefined;
}
}
class FormComponentFormDefinition extends BaseFormDefinition {
@PropertyName() lastName: string;
@PropertyName() firstName: string;
@PropertyName() orcid: string;
}
<dlcm-shared-banner-edit-mode [isEdit]="false"></dlcm-shared-banner-edit-mode>
<dlcm-button-toolbar-detail [mode]="'detail'"
[currentModel]="currentObs | async"
[editAvailable]="false"
[deleteAvailable]="false"
(backToDetailChange)="backToDetail()"
(backToListChange)="backToList()"
>
</dlcm-button-toolbar-detail>
<div class="wrapper"
[dlcmSpinner]="isLoadingWithDependencyObs | async"
>
<dlcm-contributor-form #formPresentational
*ngIf="isReadyToBeDisplayedObs | async"
[model]="currentObs| async"
[readonly]="true"
(submitChange)="update($event)"
(checkAvailableChange)="checkAvailable($event)"
(dirtyChange)="updateCanDeactivate($event)"
(navigate)="navigate($event)"
>
</dlcm-contributor-form>
</div>
<h1>{{'preservationSpace.contributor.deposit.title' | translate}}</h1>
<div class="wrapper"
[dlcmSpinner]="(isLoadingDepositObs | async)"
>
<dlcm-shared-data-table [columns]="columns"
[isLoading]="isLoadingDepositObs | async"
[datas]="listDepositObs | async"
[skipInitialQuery]="true"
[queryParameters]="queryParametersDepositObs | async"
(queryParametersChange)="onQueryParametersEvent($event)"
(selectChange)="goToDeposit($event)"
></dlcm-shared-data-table>
</div>
@import "../../../../../../shared/components/routables/shared-abstract-detail-edit-common/shared-abstract-detail-edit-common.routable.scss";
:host {
.wrapper {
min-height: 200px;
}
}
\ No newline at end of file
import {
ChangeDetectionStrategy,
ChangeDetectorRef,
Component,
OnInit,
} from "@angular/core";
import {MatDialog} from "@angular/material";
import {ActivatedRoute} from "@angular/router";
import {ContributorDepositAction} from "@app/features/preservation-space/contributor/stores/contributor-deposit/contributor-deposit.action";
import {ContributorDepositState} from "@app/features/preservation-space/contributor/stores/contributor-deposit/contributor-deposit.state";
import {contributorActionNameSpace} from "@app/features/preservation-space/contributor/stores/contributor.action";
import {
ContributorState,
ContributorStateModel,
} from "@app/features/preservation-space/contributor/stores/contributor.state";
import {Contributor} from "@app/generated-api/model/contributor.partial.model";
import {appAuthorizedOrganizationalUnitNameSpace} from "@app/stores/authorized-organizational-unit/app-authorized-organizational-unit.action";
import {AppAuthorizedOrganizationalUnitState} from "@app/stores/authorized-organizational-unit/app-authorized-organizational-unit.state";
import {Deposit} from "@models";
import {Navigate} from "@ngxs/router-plugin";
import {
Actions,
Select,
Store,
} from "@ngxs/store";
import {SharedAbstractDetailEditCommonRoutable} from "@shared/components/routables/shared-abstract-detail-edit-common/shared-abstract-detail-edit-common.routable";
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 {
DepositRoutesEnum,
RoutesEnum,
} from "@shared/enums/routes.enum";
import {DataTableColumns} from "@shared/models/data-table-columns.model";
import {Observable} from "rxjs";
import {
CompositionState,
MemoizedUtil,
OrderEnum,
QueryParameters,
ResourceNameSpace,
TRANSLATE,
} from "solidify-frontend";
@Component({
selector: "dlcm-orgunit-detail-edit-routable",
templateUrl: "./contributor-detail-edit.routable.html",
styleUrls: ["./contributor-detail-edit.routable.scss"],
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class ContributorDetailEditRoutable extends SharedAbstractDetailEditCommonRoutable<Contributor, ContributorStateModel> implements OnInit {
@Select(ContributorState.isLoadingWithDependency) isLoadingWithDependencyObs: Observable<boolean>;
@Select(ContributorState.isReadyToBeDisplayed) isReadyToBeDisplayedObs: Observable<boolean>;
listDepositObs: Observable<Deposit[]> = CompositionState.list(this._store, ContributorDepositState);
queryParametersDepositObs: Observable<QueryParameters> = CompositionState.queryParameters(this._store, ContributorDepositState);
isLoadingDepositObs: Observable<boolean> = MemoizedUtil.isLoading(this._store, ContributorDepositState);
appAuthorizedOrganizationalUnitNameSpace: ResourceNameSpace = appAuthorizedOrganizationalUnitNameSpace;
appAuthorizedOrganizationalUnitState: typeof AppAuthorizedOrganizationalUnitState = AppAuthorizedOrganizationalUnitState;
readonly KEY_PARAM_NAME: keyof Contributor & string = undefined;
columns: DataTableColumns[] = [
{
field: "title",
header: TRANSLATE("deposit.table.header.title"),
type: FieldTypeEnum.string,
order: OrderEnum.none,
isFilterable: false,
isSortable: false,
},
{
field: "organizationalUnitId" as any,
header: TRANSLATE("deposit.table.header.organizationalUnit"),
type: FieldTypeEnum.searchableSingleSelect,
order: OrderEnum.none,
component: DataTableComponentEnum.organizationalUnitName,
isFilterable: false,
isSortable: false,
resourceNameSpace: this.appAuthorizedOrganizationalUnitNameSpace,
resourceState: this.appAuthorizedOrganizationalUnitState as any,
},
{
field: "publicationDate",
header: TRANSLATE("deposit.table.header.publicationDate"),
type: FieldTypeEnum.date,
order: OrderEnum.none,
isFilterable: false,
isSortable: false,
},
{
field: "creation.when" as any,
header: TRANSLATE("deposit.table.header.creation.when"),
type: FieldTypeEnum.datetime,
order: OrderEnum.none,
isFilterable: true,
isSortable: true,
width: "145px",
},
{
field: "lastUpdate.when" as any,
header: TRANSLATE("deposit.table.header.lastUpdate.when"),
type: FieldTypeEnum.datetime,
order: OrderEnum.descending,
isFilterable: true,
isSortable: true,
},
];
constructor(protected _store: Store,
protected _route: ActivatedRoute,
protected readonly _actions$: Actions,
protected readonly _changeDetector: ChangeDetectorRef,
public _dialog: MatDialog) {
super(_store, _route, _actions$, _changeDetector, _dialog, LocalStateEnum.preservationSpace_contributor, contributorActionNameSpace, LocalStateEnum.preservationSpace);
}
ngOnInit(): void {
super.ngOnInit();
}
getSubResourceWithParentId(id: string): void {
this._store.dispatch(new ContributorDepositAction.GetAll(id));
}
onQueryParametersEvent(queryParameters: QueryParameters): void {
this._store.dispatch(new ContributorDepositAction.ChangeQueryParameters(this._resId, queryParameters, true));
}
goToDeposit(deposit: Deposit): void {
this._store.dispatch(new Navigate([RoutesEnum.deposit, deposit.organizationalUnitId, DepositRoutesEnum.detail, deposit.resId]));
}
}
import {
ChangeDetectionStrategy,
ChangeDetectorRef,
Component,
} from "@angular/core";
import {MatDialog} from "@angular/material/dialog";
import {ActivatedRoute} from "@angular/router";
import {contributorActionNameSpace} from "@app/features/preservation-space/contributor/stores/contributor.action";
import {ContributorStateModel} from "@app/features/preservation-space/contributor/stores/contributor.state";
import {Contributor} from "@app/generated-api/model/contributor.partial.model";
import {Aip} from "@models";
import {Navigate} from "@ngxs/router-plugin";
import {
Actions,
Store,
} from "@ngxs/store";
import {SharedAbstractListRoutable} from "@shared/components/routables/shared-abstract-list/shared-abstract-list.routable";
import {FieldTypeEnum} from "@shared/enums/field-type.enum";
import {LocalStateEnum} from "@shared/enums/local-state.enum";
import {RoutesEnum} from "@shared/enums/routes.enum";
import {SecurityService} from "@shared/services/security.service";
import {
OrderEnum,
Override,
TRANSLATE,
} from "solidify-frontend";
@Component({
selector: "dlcm-contributor-list-routable",
templateUrl: "../../../../../../shared/components/routables/shared-abstract-list/shared-abstract-list.routable.html",
styleUrls: ["../../../../../../shared/components/routables/shared-abstract-list/shared-abstract-list.routable.scss"],
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class ContributorListRoutable extends SharedAbstractListRoutable<Contributor, ContributorStateModel> {
readonly KEY_CREATE_BUTTON: string = undefined;
readonly KEY_REFRESH_BUTTON: string = TRANSLATE("preservationSpace.contributor.button.refresh");
readonly KEY_BACK_BUTTON: string | undefined = TRANSLATE("preservationSpace.contributor.button.goBackToPreservationSpace");
readonly KEY_PARAM_NAME: keyof Contributor & string = "resId";
constructor(<