Commit 35af1480 authored by Quentin Torck's avatar Quentin Torck
Browse files

Merge branch 'master' of gitlab.unige.ch:dlcm/ui/dlcm-portal

parents 344cc294 9850ed81
This diff is collapsed.
......@@ -8,6 +8,7 @@ import {
ErrorHandler,
NgModule,
} from "@angular/core";
import {ReactiveFormsModule} from "@angular/forms";
import {
MAT_MOMENT_DATE_ADAPTER_OPTIONS,
MAT_MOMENT_DATE_FORMATS,
......@@ -50,6 +51,8 @@ import {AppOrganizationalUnitPersonRoleState} from "@app/stores/organizational-u
import {AppPersonState} from "@app/stores/person/app-person.state";
import {AppTocState} from "@app/stores/toc/app-toc.state";
import {AppUserState} from "@app/stores/user/app-user.state";
import {FormlyModule} from "@ngx-formly/core";
import {FormlyMaterialModule} from "@ngx-formly/material";
import {
TranslateLoader,
TranslateModule,
......@@ -184,6 +187,9 @@ export function hljsLanguages(): any {
registrationStrategy: "registerImmediately",
scope: window.location.pathname.replace(/\/[^\/]+$/, "/"),
}),
ReactiveFormsModule,
FormlyModule.forRoot(),
FormlyMaterialModule,
],
providers: [
{
......
......@@ -164,7 +164,7 @@ export class AdminOrgunitFormPresentational extends SharedAbstractFormPresentati
[this.formDefinition.institutions]: [_.map(this.selectedInstitutions, LocalModelAttributeEnum.resId), [SolidifyValidator]],
[this.formDefinition.researchDomains]: [_.map(organizationalUnit.researchDomains, LocalModelAttributeEnum.resId), [SolidifyValidator]],
[this.formDefinition.keywords]: [[...organizationalUnit.keywords], [SolidifyValidator]],
[this.formDefinition.defaultLicense]: [organizationalUnit.defaultLicense.resId, [SolidifyValidator]],
[this.formDefinition.defaultLicense]: [organizationalUnit?.defaultLicense?.resId, [SolidifyValidator]],
});
}
......@@ -204,10 +204,11 @@ export class AdminOrgunitFormPresentational extends SharedAbstractFormPresentati
organizationalUnit.researchDomains.push({resId: resId});
});
}
if (this.form.get(this.formDefinition.defaultLicense).value === "") {
const defaultLicenseResId = this.form.get(this.formDefinition.defaultLicense).value;
if (isNullOrUndefined(defaultLicenseResId) || isEmptyString(defaultLicenseResId)) {
organizationalUnit.defaultLicense = null;
} else {
organizationalUnit.defaultLicense = {resId: organizationalUnit.defaultLicense};
organizationalUnit.defaultLicense = {resId: defaultLicenseResId};
}
return organizationalUnit;
}
......
......@@ -198,7 +198,7 @@
<mat-select [formControl]="fd"
[required]="formValidationHelper.hasRequiredField(fd)"
[solidifyValidation]="errors"
[disabled]="this.listSubmissionPolicies < 1 || readonly"
[disabled]="readonly"
data-test="deposit-submissionPolicy"
>
<mat-option *ngFor="let submission of listSubmissionPolicies"
......@@ -220,7 +220,7 @@
<mat-select [formControl]="fd"
[required]="formValidationHelper.hasRequiredField(fd)"
[solidifyValidation]="errors"
[disabled]="this.listPreservationPolicies < 1 || readonly"
[disabled]="readonly"
data-test="deposit-preservationPolicy"
>
<mat-option *ngFor="let preservation of listPreservationPolicies"
......@@ -336,13 +336,16 @@
</div>
</div>
</dlcm-shared-panel-expandable>
<!-- <dlcm-shared-panel-expandable class="section"-->
<!-- [titleToTranslate]="'deposit.form.section.optional' | translate"-->
<!-- [isOpen]="false"-->
<!-- >-->
<!-- <div class="two-columns-wrapper">-->
<!-- <div class="left-part"></div>-->
<!-- <div class="right-part"></div>-->
<!-- </div>-->
<!-- </dlcm-shared-panel-expandable>-->
<dlcm-shared-panel-expandable class="section"
*ngIf="addFieldsForm | isNotNullNorUndefined"
[titleToTranslate]="'deposit.form.section.optional' | translate"
[isOpen]="true"
>
<formly-form class="formly"
[form]="formFormly"
[model]="additionalFieldsValues"
[fields]="fields"
(modelChange)="formlyChange()"
></formly-form>
</dlcm-shared-panel-expandable>
</form>
......@@ -64,4 +64,19 @@
text-align: right;
}
}
.formly {
display: grid;
grid-template-columns: 1fr 1fr;
grid-gap: 0 40px;
overflow: hidden;
@include respond-to-smaller-than-breakpoint('md') {
grid-template-columns: 1fr;
}
::ng-deep > * {
width: 100%;
}
}
}
......@@ -6,11 +6,11 @@ import {
ElementRef,
Input,
OnInit,
Output,
ViewChild,
} from "@angular/core";
import {
FormBuilder,
FormGroup,
Validators,
} from "@angular/forms";
import {MatDialog} from "@angular/material/dialog";
......@@ -26,6 +26,7 @@ import {
import {DepositPersonDialog} from "@deposit/components/dialogs/deposit-person/deposit-person.dialog";
import {environment} from "@environments/environment";
import {
AdditionalFieldsForm,
Deposit,
Language,
License,
......@@ -34,6 +35,8 @@ import {
PreservationPolicy,
SubmissionPolicy,
} from "@models";
import {FormlyFieldConfig} from "@ngx-formly/core";
import {TranslateService} from "@ngx-translate/core";
import {SharedSearchableMultiSelectPresentational} from "@shared/components/presentationals/shared-searchable-multi-select/shared-searchable-multi-select.presentational";
import {ApplicationRoleEnum} from "@shared/enums/application-role.enum";
import {AccessLevelEnumHelper} from "@shared/enums/business/access-level-enum.helper";
......@@ -44,24 +47,18 @@ import {
SharedPersonState,
SharedPersonStateModel,
} from "@shared/stores/person/shared-person.state";
import {UserPreferencesUtil} from "@shared/utils/user-preferences.util";
import _ from "lodash";
import {
BehaviorSubject,
Observable,
} from "rxjs";
import {
distinctUntilChanged,
skipWhile,
takeWhile,
tap,
} from "rxjs/operators";
import {
DateUtil,
isEmptyArray,
isNotNullNorUndefined,
isNullOrUndefined,
KeyValue,
ObservableUtil,
MappingObjectUtil,
PropertyName,
ResourceNameSpace,
SolidifyValidator,
......@@ -80,6 +77,22 @@ export class DepositFormPresentational extends SharedAbstractFormPresentational<
accessEnumValues: KeyValue[] = AccessLevelEnumHelper.getListKeyValue();
additionalFieldsValues: Object;
formFormly: FormGroup;
addFieldsForm: AdditionalFieldsForm;
@Input()
set additionalFieldsForm(additionalFieldsForm: AdditionalFieldsForm) {
if (isNotNullNorUndefined(additionalFieldsForm)) {
this.addFieldsForm = additionalFieldsForm;
this.fields = JSON.parse(additionalFieldsForm.description);
}
}
fields: FormlyFieldConfig[];
@Input()
isReady: boolean = false;
......@@ -105,10 +118,7 @@ export class DepositFormPresentational extends SharedAbstractFormPresentational<
currentApplicationRole: ApplicationRoleEnum[];
@Input()
selectedOrgUnit: Observable<OrganizationalUnit>;
@Input()
listAuthorizedOrgUnit: OrganizationalUnit[];
orgUnit: OrganizationalUnit;
@ViewChild("authorMultiSearchableSelect")
authorMultiSearchableSelect: SharedSearchableMultiSelectPresentational<SharedPersonStateModel, Person>;
......@@ -127,21 +137,17 @@ export class DepositFormPresentational extends SharedAbstractFormPresentational<
licenceCallback: (value: License) => string = (value: License) => value.openLicenseId + " (" + value.title + ")";
private readonly _orgUnitValueBS: BehaviorSubject<string | undefined> = new BehaviorSubject<string | undefined>(undefined);
@Output("orgUnitChange")
readonly orgUnitValueObs: Observable<string | undefined> = ObservableUtil.asObservable(this._orgUnitValueBS);
constructor(protected readonly _changeDetectorRef: ChangeDetectorRef,
protected readonly _elementRef: ElementRef,
private readonly _fb: FormBuilder,
private readonly dialog: MatDialog,
public readonly breakpointService: BreakpointService) {
public readonly breakpointService: BreakpointService,
private readonly _translateService: TranslateService) {
super(_changeDetectorRef, _elementRef);
}
ngOnInit(): void {
super.ngOnInit();
this.validationLicenseRequiredWhenAccessPublic();
}
......@@ -161,10 +167,9 @@ export class DepositFormPresentational extends SharedAbstractFormPresentational<
}
protected initNewForm(): void {
const orgUnit = UserPreferencesUtil.getPreferredOrgUnitInDepositMenu(this.listAuthorizedOrgUnit);
const orgUnitId = isNullOrUndefined(orgUnit) ? "" : orgUnit.resId;
this.form = this._fb.group({
[this.formDefinition.organizationalUnitId]: [orgUnitId, [Validators.required, SolidifyValidator]],
let formDesc = {
[this.formDefinition.organizationalUnitId]: [this.orgUnit.resId, [Validators.required, SolidifyValidator]],
[this.formDefinition.title]: ["", [Validators.required, SolidifyValidator]],
[this.formDefinition.description]: ["", [Validators.required, SolidifyValidator]],
[this.formDefinition.languageId]: [""],
......@@ -173,19 +178,29 @@ export class DepositFormPresentational extends SharedAbstractFormPresentational<
[this.formDefinition.collectionEnd]: [""],
[this.formDefinition.access]: [AccessEnum.PUBLIC],
[this.formDefinition.hasEmbargo]: [false],
[this.formDefinition.licenseId]: [orgUnit?.defaultLicense?.resId, [SolidifyValidator]],
[this.formDefinition.submissionPolicyId]: ["", [Validators.required, SolidifyValidator]],
[this.formDefinition.preservationPolicyId]: ["", [Validators.required, SolidifyValidator]],
[this.formDefinition.licenseId]: [this.orgUnit?.defaultLicense?.resId, [SolidifyValidator]],
[this.formDefinition.submissionPolicyId]: [this.orgUnit?.defaultSubmissionPolicy?.resId, [Validators.required, SolidifyValidator]],
[this.formDefinition.preservationPolicyId]: [this.orgUnit?.defaultPreservationPolicy?.resId, [Validators.required, SolidifyValidator]],
[this.formDefinition.authors]: ["", [Validators.required, SolidifyValidator]],
[this.formDefinition.keywords]: [[], [SolidifyValidator]],
[this.formDefinition.keywords]: [[...this.orgUnit?.keywords], [SolidifyValidator]],
[this.formDefinition.doi]: [null, {disabled: true}],
});
// [this.formDefinition.additionalFieldsValues]: [this._fb.group({})],
};
if (isNotNullNorUndefined(this.addFieldsForm)) {
formDesc = {
...formDesc,
[this.formDefinition.additionalFieldsFormId]: [this.addFieldsForm.resId, [Validators.required, SolidifyValidator]],
};
}
this.orgUnitSelectionChange(orgUnitId);
this.form = this._fb.group(formDesc);
this.formFormly = this._fb.group({});
}
protected bindFormTo(deposit: Deposit): void {
this.form = this._fb.group({
let formDesc = {
[this.formDefinition.organizationalUnitId]: [deposit.organizationalUnitId, [Validators.required, SolidifyValidator]],
[this.formDefinition.title]: [deposit.title, [Validators.required, SolidifyValidator]],
[this.formDefinition.description]: [deposit.description, [Validators.required, SolidifyValidator]],
......@@ -199,9 +214,23 @@ export class DepositFormPresentational extends SharedAbstractFormPresentational<
[this.formDefinition.submissionPolicyId]: [deposit.submissionPolicyId, [Validators.required, SolidifyValidator]],
[this.formDefinition.preservationPolicyId]: [deposit.preservationPolicyId, [Validators.required, SolidifyValidator]],
[this.formDefinition.authors]: [_.map(this.selectedPersons, LocalModelAttributeEnum.resId), [Validators.required, SolidifyValidator]],
[this.formDefinition.keywords]: [[...deposit.keywords], [SolidifyValidator]],
[this.formDefinition.keywords]: [isNullOrUndefined(deposit.keywords) ? [] : [...deposit.keywords], [SolidifyValidator]],
[this.formDefinition.doi]: [deposit.doi, {disabled: true}],
});
// [this.formDefinition.additionalFieldsValues]: [this._fb.group({})],
};
if (isNotNullNorUndefined(deposit.additionalFieldsFormId)) {
formDesc = {
...formDesc,
[this.formDefinition.additionalFieldsFormId]: [deposit.additionalFieldsFormId, [Validators.required, SolidifyValidator]],
};
}
this.form = this._fb.group(formDesc);
this.formFormly = this._fb.group({}); // TODO INIT FORM WITH MODEL
this.additionalFieldsValues = JSON.parse(deposit.additionalFieldsValues);
this.isValidWhenDisable = this.form.valid;
}
......@@ -209,6 +238,12 @@ export class DepositFormPresentational extends SharedAbstractFormPresentational<
deposit.publicationDate = DateUtil.convertToLocalDateDateSimple(deposit.publicationDate);
deposit.collectionBegin = DateUtil.convertToOffsetDateTimeIso8601(deposit.collectionBegin);
deposit.collectionEnd = DateUtil.convertToOffsetDateTimeIso8601(deposit.collectionEnd);
deposit.collectionEnd = DateUtil.convertToOffsetDateTimeIso8601(deposit.collectionEnd);
if (isNotNullNorUndefined(this.formFormly.value) && MappingObjectUtil.size(this.formFormly.value) > 0) {
deposit.additionalFieldsValues = JSON.stringify(this.formFormly.value);
} else {
deposit.additionalFieldsValues = null;
}
return deposit;
}
......@@ -244,32 +279,6 @@ export class DepositFormPresentational extends SharedAbstractFormPresentational<
return this.form.get(this.formDefinition.authors).value.includes(this.personConnected.resId);
}
orgUnitSelectionChange(orgUnitResId: string | undefined): void {
if (isNullOrUndefined(orgUnitResId)) {
this.form.get(this.formDefinition.preservationPolicyId).setValue(undefined);
this.form.get(this.formDefinition.submissionPolicyId).setValue(undefined);
return;
}
this._orgUnitValueBS.next(orgUnitResId);
let valueChange: boolean = false;
this.subscribe(this.selectedOrgUnit.pipe(
skipWhile(o => o === null || o === undefined),
takeWhile(() => valueChange === false),
tap(o => {
if (!isNullOrUndefined(o.defaultPreservationPolicy)) {
this.form.get(this.formDefinition.preservationPolicyId).setValue(o.defaultPreservationPolicy.resId);
}
if (!isNullOrUndefined(o.defaultSubmissionPolicy)) {
this.form.get(this.formDefinition.submissionPolicyId).setValue(o.defaultSubmissionPolicy.resId);
}
if (!isNullOrUndefined(o.keywords)) {
this.form.get(this.formDefinition.keywords).setValue([...o.keywords]);
}
valueChange = true;
}),
));
}
getSipPath(sipId: string): string {
return "#" + urlSeparator + RoutesEnum.preservationSipDetail + urlSeparator + sipId;
}
......@@ -298,6 +307,14 @@ export class DepositFormPresentational extends SharedAbstractFormPresentational<
),
);
}
formlyChange(): void {
if (this.form.dirty) {
return;
}
this.form.markAsDirty();
this._changeDetectorRef.detectChanges();
}
}
class FormComponentFormDefinition extends BaseFormDefinition {
......@@ -316,4 +333,5 @@ class FormComponentFormDefinition extends BaseFormDefinition {
@PropertyName() preservationPolicyId: string;
@PropertyName() keywords: string;
@PropertyName() doi: string;
@PropertyName() additionalFieldsFormId: string;
}
<dlcm-button-toolbar-detail [mode]="'create'"
[formPresentational]="formPresentational"
[listExtraButtons]="listExtraButtons"
[saveAvailable]="false"
(backToListChange)="backToList()"
>
</dlcm-button-toolbar-detail>
......@@ -10,14 +12,13 @@
<dlcm-deposit-form #formPresentational
*ngIf="isReadyToBeDisplayedInCreateModeObs | async"
(submitChange)="create($event)"
[listAuthorizedOrgUnit]="listAuthorizedOrgUnit"
[languages]="languagesObs | async"
[listSubmissionPolicies]="listSubmissionPoliciesObs | async"
[listPreservationPolicies]="listPreservationPoliciesObs | async"
[personConnected]="personConnectedObs | async"
[listPersons]="listPersonObs | async"
[selectedOrgUnit]="selectedOrgUnitObs"
(orgUnitChange)="adaptPolicies($event)"
[orgUnit]="orgUnitObs | async"
[additionalFieldsForm]="additionalFieldsFormObs | async"
[readonly]="false"
(dirtyChange)="updateCanDeactivate($event)"
(navigate)="navigate($event)"
......
......@@ -12,13 +12,14 @@ import {
DepositState,
DepositStateModel,
} from "@app/features/deposit/stores/deposit.state";
import {SharedAbstractFormPresentational} from "@app/shared/components/presentationals/shared-abstract-form/shared-abstract-form.presentational";
import {SharedAbstractCreateRoutable} from "@app/shared/components/routables/shared-abstract-create/shared-abstract-create.routable";
import {LocalStateEnum} from "@app/shared/enums/local-state.enum";
import {LocalStateModel} from "@app/shared/models/local-state.model";
import {SharedOrgUnitAction} from "@app/shared/stores/organizational-unit/shared-organizational-unit.action";
import {AppAuthorizedOrganizationalUnitState} from "@app/stores/authorized-organizational-unit/app-authorized-organizational-unit.state";
import {DepositFormPresentational} from "@deposit/components/presentationals/deposit-form/deposit-form.presentational";
import {DepositOrganizationalUnitAdditionalFieldsFormAction} from "@deposit/stores/organizational-unit/additional-fields-form/deposit-organizational-unit-additional-fields-form.action";
import {DepositOrganizationalUnitAdditionalFieldsFormState} from "@deposit/stores/organizational-unit/additional-fields-form/deposit-organizational-unit-additional-fields-form.state";
import {
AdditionalFieldsForm,
Deposit,
Language,
OrganizationalUnit,
......@@ -31,12 +32,20 @@ import {
Select,
Store,
} from "@ngxs/store";
import {ExtraButtonToolbar} from "@shared/models/extra-button-toolbar.model";
import {SharedOrgUnitPreservationPolicyAction} from "@shared/stores/organizational-unit/preservation-policy/shared-organizational-unit-preservation-policy.action";
import {SharedOrgUnitSubmissionPolicyAction} from "@shared/stores/organizational-unit/submission-policy/shared-organizational-unit-submission-policy.action";
import {Observable} from "rxjs";
import {
distinctUntilChanged,
filter,
} from "rxjs/operators";
import {
CompositionState,
FormState,
ResourceState,
isNotNullNorUndefined,
MemoizedUtil,
TRANSLATE,
} from "solidify-frontend";
@Component({
......@@ -55,10 +64,24 @@ export class DepositCreateRoutable extends SharedAbstractCreateRoutable<Deposit,
@Select((state: LocalStateModel) => state.shared.shared_organizationalUnit.shared_organizationalUnit_submissionPolicy.selected) listSubmissionPoliciesObs: Observable<SubmissionPolicy[]>;
@Select((state: LocalStateModel) => state.application.application_person.current) personConnectedObs: Observable<Person>;
@Select((state: LocalStateModel) => state.shared.shared_organizationalUnit.current) selectedOrgUnitObs: Observable<OrganizationalUnit>;
additionalFieldsFormObs: Observable<AdditionalFieldsForm> = CompositionState.current(this._store, DepositOrganizationalUnitAdditionalFieldsFormState);
@ViewChild("formPresentational")
readonly formPresentational: SharedAbstractFormPresentational<Deposit>;
listAuthorizedOrgUnit: OrganizationalUnit[] = ResourceState.listSnapshot(this._store, AppAuthorizedOrganizationalUnitState);
readonly formPresentational: DepositFormPresentational;
orgUnitObs: Observable<OrganizationalUnit> = MemoizedUtil.select(this._store, DepositState, (state) => state.organizationalUnit);
listExtraButtons: ExtraButtonToolbar<Deposit>[] = [
{
color: "primary",
typeButton: "flat-button",
icon: "save",
labelToTranslate: TRANSLATE("app.navigation.button.save"),
order: 40,
callback: () => this.formPresentational.onSubmit(),
displayCondition: (resource) => true,
disableCondition: () => this.formPresentational?.form?.pristine || this.formPresentational?.form?.invalid || this.formPresentational?.formFormly?.invalid,
},
];
constructor(protected readonly _store: Store,
protected readonly _actions$: Actions,
......@@ -68,17 +91,19 @@ export class DepositCreateRoutable extends SharedAbstractCreateRoutable<Deposit,
ngOnInit(): void {
super.ngOnInit();
this.subscribe(this.orgUnitObs.pipe(
distinctUntilChanged(),
filter(orgUnit => isNotNullNorUndefined(orgUnit)),
), orgUnit => {
this._store.dispatch(new DepositOrganizationalUnitAdditionalFieldsFormAction.GetCurrentMetadataForm(orgUnit.resId));
this._store.dispatch(new SharedOrgUnitPreservationPolicyAction.GetAll(orgUnit.resId));
this._store.dispatch(new SharedOrgUnitSubmissionPolicyAction.GetAll(orgUnit.resId));
});
}
getSubResourceWithParentId(id: string): void {
}
adaptPolicies(organizationalUnitId: string): void {
this._store.dispatch(new SharedOrgUnitAction.GetById(organizationalUnitId));
this._store.dispatch(new SharedOrgUnitPreservationPolicyAction.GetAll(organizationalUnitId));
this._store.dispatch(new SharedOrgUnitSubmissionPolicyAction.GetAll(organizationalUnitId));
}
ngOnDestroy(): void {
this._store.dispatch(new SharedOrgUnitPreservationPolicyAction.Clear());
this._store.dispatch(new SharedOrgUnitSubmissionPolicyAction.Clear());
......
......@@ -15,11 +15,12 @@
[deleteAvailable]="canDoAlterationActions"
[editAvailable]="canDoAlterationActions"
[listExtraButtons]="listExtraButtons"
[saveAvailable]="false"
[historyAvailable]="true"
(editChange)="edit()"
(deleteChange)="delete()"
(backToDetailChange)="backToDetail()"
(backToListChange)="backToList()"
[historyAvailable]="true"
(showHistoryChange)="showHistory()"
>
</dlcm-button-toolbar-detail>
......
......@@ -137,6 +137,16 @@ export class DepositDetailEditRoutable extends SharedAbstractDetailEditRoutable<
readonly KEY_PARAM_NAME: keyof Deposit & string = "title";
listExtraButtons: ExtraButtonToolbar<Deposit>[] = [
{
color: "primary",
typeButton: "flat-button",
icon: "save",
labelToTranslate: TRANSLATE("app.navigation.button.save"),
order: 40,
callback: () => this.depositService?.formPresentational?.onSubmit(),
displayCondition: (resource) => this.isEdit,
disableCondition: () => this.depositService?.formPresentational?.form?.pristine || this.depositService?.formPresentational?.form?.invalid || this.depositService?.formPresentational?.formFormly?.invalid,
},
{
color: "primary",
icon: "file_download",
......
......@@ -11,9 +11,9 @@
[selectedPersons]="selectedPersonObs | async"
[personConnected]="personConnectedObs | async"
[currentApplicationRole]="currentUserApplicationRoleObs | async"
[orgUnit]="orgUnitObs | async"
[additionalFieldsForm]="additionalFieldsFormObs | async"
(submitChange)="update($event)"
[selectedOrgUnit]="selectedOrgUnitObs"
(orgUnitChange)="adaptPolicies($event)"
[readonly]="!isEdit"
[editAvailable]="canEditObs | async"
(dirtyChange)="updateCanDeactivate($event)"
......