From df957fc31b04be2b8c8590100382c9e1e2cf1dc6 Mon Sep 17 00:00:00 2001 From: Davide Negretti Date: Fri, 19 Nov 2021 16:22:52 +0100 Subject: [PATCH 01/11] [CST-4878] Remove start and end date when embargo policy is changed to 'open access' --- .../file/section-upload-file.component.ts | 29 ++++++++++++------- 1 file changed, 18 insertions(+), 11 deletions(-) diff --git a/src/app/submission/sections/upload/file/section-upload-file.component.ts b/src/app/submission/sections/upload/file/section-upload-file.component.ts index ac6c0d70c4..64d229e3a7 100644 --- a/src/app/submission/sections/upload/file/section-upload-file.component.ts +++ b/src/app/submission/sections/upload/file/section-upload-file.component.ts @@ -262,17 +262,24 @@ export class SubmissionSectionUploadFileComponent implements OnChanges, OnInit { .forEach((element) => accessConditionOpt = element); if (accessConditionOpt) { - accessConditionOpt = Object.assign({}, accessCondition); - accessConditionOpt.name = this.retrieveValueFromField(accessCondition.name); - if (accessCondition.startDate) { - const startDate = this.retrieveValueFromField(accessCondition.startDate); - accessConditionOpt.startDate = dateToISOFormat(startDate); - } - if (accessCondition.endDate) { - const endDate = this.retrieveValueFromField(accessCondition.endDate); - accessConditionOpt.endDate = dateToISOFormat(endDate); - } - accessConditionsToSave.push(accessConditionOpt); + const currentAccessCondition = Object.assign({}, accessCondition); + currentAccessCondition.name = this.retrieveValueFromField(accessCondition.name); + + /* When start and end date fields are deactivated, their values may be still present in formData, + therefore it is necessary to delete them if they're not allowed by the current access condition option. */ + if (!accessConditionOpt.hasStartDate) { + delete currentAccessCondition.startDate; + } else if (accessCondition.startDate) { + const startDate = this.retrieveValueFromField(accessCondition.startDate); + currentAccessCondition.startDate = dateToISOFormat(startDate); + } + if (!accessConditionOpt.hasEndDate) { + delete currentAccessCondition.endDate; + } else if (accessCondition.endDate) { + const endDate = this.retrieveValueFromField(accessCondition.endDate); + currentAccessCondition.endDate = dateToISOFormat(endDate); + } + accessConditionsToSave.push(currentAccessCondition); } }); From 9363b0fb35f3b756f8ad6603e89c178108bf1d7f Mon Sep 17 00:00:00 2001 From: Davide Negretti Date: Fri, 19 Nov 2021 19:58:07 +0100 Subject: [PATCH 02/11] [CST-4947] File description on bitstream can now be deleted (test TBD) --- .../file/section-upload-file.component.ts | 29 ++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/src/app/submission/sections/upload/file/section-upload-file.component.ts b/src/app/submission/sections/upload/file/section-upload-file.component.ts index 64d229e3a7..9807aecda3 100644 --- a/src/app/submission/sections/upload/file/section-upload-file.component.ts +++ b/src/app/submission/sections/upload/file/section-upload-file.component.ts @@ -6,7 +6,7 @@ import { DynamicFormControlModel, } from '@ng-dynamic-forms/core'; import { NgbModal } from '@ng-bootstrap/ng-bootstrap'; import { SectionUploadService } from '../section-upload.service'; -import { isNotEmpty, isNotNull, isNotUndefined } from '../../../../shared/empty.util'; +import { hasNoValue, isNotEmpty, isNotNull, isNotUndefined } from '../../../../shared/empty.util'; import { FormService } from '../../../../shared/form/form.service'; import { JsonPatchOperationsBuilder } from '../../../../core/json-patch/builder/json-patch-operations-builder'; import { JsonPatchOperationPathCombiner } from '../../../../core/json-patch/builder/json-patch-operation-path-combiner'; @@ -129,6 +129,12 @@ export class SubmissionSectionUploadFileComponent implements OnChanges, OnInit { */ protected subscriptions: Subscription[] = []; + /** + * Array containing all the form metadata defined in configMetadataForm + * @type {Array} + */ + protected formMetadata: string[] = []; + /** * The [[SubmissionSectionUploadFileEditComponent]] reference * @type {SubmissionSectionUploadFileEditComponent} @@ -158,6 +164,17 @@ export class SubmissionSectionUploadFileComponent implements OnChanges, OnInit { this.readMode = true; } + protected loadFormMetadata() { + this.configMetadataForm.rows.forEach((row) => { + row.fields.forEach((field) => { + field.selectableMetadata.forEach((metadatum) => { + this.formMetadata.push(metadatum.metadata); + }); + }); + } + ); + } + /** * Retrieve bitstream's metadata */ @@ -182,6 +199,7 @@ export class SubmissionSectionUploadFileComponent implements OnChanges, OnInit { ngOnInit() { this.formId = this.formService.getUniqueId(this.fileId); this.pathCombiner = new JsonPatchOperationPathCombiner('sections', this.sectionId, 'files', this.fileIndex); + this.loadFormMetadata(); } /** @@ -250,6 +268,15 @@ export class SubmissionSectionUploadFileComponent implements OnChanges, OnInit { const path = `metadata/${metadataKey}`; this.operationsBuilder.add(this.pathCombiner.getPath(path), formData.metadata[key], true); }); + Object.keys((this.fileData.metadata)) + .filter((key) => isNotEmpty(this.fileData.metadata[key])) + .filter((key) => hasNoValue(formData.metadata[key])) + .filter((key) => this.formMetadata.includes(key)) + .forEach((key) => { + const metadataKey = key.replace(/_/g, '.'); + const path = `metadata/${metadataKey}`; + this.operationsBuilder.remove(this.pathCombiner.getPath(path)); + }); const accessConditionsToSave = []; formData.accessConditions .map((accessConditions) => accessConditions.accessConditionGroup) From 25795772257a2ec05e39da2d7f7199481f08e138 Mon Sep 17 00:00:00 2001 From: Davide Negretti Date: Fri, 19 Nov 2021 19:58:07 +0100 Subject: [PATCH 03/11] [CST-4947] Test WIP --- .../section-upload-file.component.spec.ts | 25 ++++++++++++---- .../file/section-upload-file.component.ts | 29 ++++++++++++++++++- 2 files changed, 48 insertions(+), 6 deletions(-) diff --git a/src/app/submission/sections/upload/file/section-upload-file.component.spec.ts b/src/app/submission/sections/upload/file/section-upload-file.component.spec.ts index 39aebf7413..d16f648e68 100644 --- a/src/app/submission/sections/upload/file/section-upload-file.component.spec.ts +++ b/src/app/submission/sections/upload/file/section-upload-file.component.spec.ts @@ -3,7 +3,7 @@ import { ComponentFixture, fakeAsync, inject, TestBed, tick, waitForAsync } from import { BrowserModule, By } from '@angular/platform-browser'; import { CommonModule } from '@angular/common'; -import { of as observableOf } from 'rxjs'; +import { of, of as observableOf } from 'rxjs'; import { TranslateModule } from '@ngx-translate/core'; import { FormService } from '../../../../shared/form/form.service'; @@ -36,8 +36,20 @@ import { FormFieldMetadataValueObject } from '../../../../shared/form/builder/mo import { SubmissionSectionUploadFileEditComponent } from './edit/section-upload-file-edit.component'; import { FormBuilderService } from '../../../../shared/form/builder/form-builder.service'; import { dateToISOFormat } from '../../../../shared/date.util'; +import { SubmissionFormModel } from '../../../../core/config/models/config-submission-form.model'; -describe('SubmissionSectionUploadFileComponent test suite', () => { +const configMetadataFormMock = { + rows: [{ + fields: [{ + selectableMetadata: [ + {metadata: 'dc.title', label: null, closed: false}, + {metadata: 'dc.description', label: null, closed: false} + ] + }] + }] +}; + +fdescribe('SubmissionSectionUploadFileComponent test suite', () => { let comp: SubmissionSectionUploadFileComponent; let compAsAny: any; @@ -117,6 +129,9 @@ describe('SubmissionSectionUploadFileComponent test suite', () => { testFixture = createTestComponent(html, TestComponent) as ComponentFixture; testComp = testFixture.componentInstance; + + // testComp.configMetadataForm = configMetadataFormMock; + // testFixture.detectChanges(); }); afterEach(() => { @@ -124,9 +139,8 @@ describe('SubmissionSectionUploadFileComponent test suite', () => { }); it('should create SubmissionSectionUploadFileComponent', inject([SubmissionSectionUploadFileComponent], (app: SubmissionSectionUploadFileComponent) => { - + app.configMetadataForm = Object.assign(new SubmissionFormModel(), configMetadataFormMock); expect(app).toBeDefined(); - })); }); @@ -135,6 +149,7 @@ describe('SubmissionSectionUploadFileComponent test suite', () => { fixture = TestBed.createComponent(SubmissionSectionUploadFileComponent); comp = fixture.componentInstance; compAsAny = comp; + compAsAny.configMetadataForm = configMetadataFormMock; submissionServiceStub = TestBed.inject(SubmissionService as any); uploadService = TestBed.inject(SectionUploadService); formService = TestBed.inject(FormService); @@ -314,7 +329,7 @@ class TestComponent { availableAccessConditionOptions; collectionId = mockSubmissionCollectionId; collectionPolicyType; - configMetadataForm$; + configMetadataForm$ = of(configMetadataFormMock); fileIndexes = []; fileList = []; fileNames = []; diff --git a/src/app/submission/sections/upload/file/section-upload-file.component.ts b/src/app/submission/sections/upload/file/section-upload-file.component.ts index 64d229e3a7..9807aecda3 100644 --- a/src/app/submission/sections/upload/file/section-upload-file.component.ts +++ b/src/app/submission/sections/upload/file/section-upload-file.component.ts @@ -6,7 +6,7 @@ import { DynamicFormControlModel, } from '@ng-dynamic-forms/core'; import { NgbModal } from '@ng-bootstrap/ng-bootstrap'; import { SectionUploadService } from '../section-upload.service'; -import { isNotEmpty, isNotNull, isNotUndefined } from '../../../../shared/empty.util'; +import { hasNoValue, isNotEmpty, isNotNull, isNotUndefined } from '../../../../shared/empty.util'; import { FormService } from '../../../../shared/form/form.service'; import { JsonPatchOperationsBuilder } from '../../../../core/json-patch/builder/json-patch-operations-builder'; import { JsonPatchOperationPathCombiner } from '../../../../core/json-patch/builder/json-patch-operation-path-combiner'; @@ -129,6 +129,12 @@ export class SubmissionSectionUploadFileComponent implements OnChanges, OnInit { */ protected subscriptions: Subscription[] = []; + /** + * Array containing all the form metadata defined in configMetadataForm + * @type {Array} + */ + protected formMetadata: string[] = []; + /** * The [[SubmissionSectionUploadFileEditComponent]] reference * @type {SubmissionSectionUploadFileEditComponent} @@ -158,6 +164,17 @@ export class SubmissionSectionUploadFileComponent implements OnChanges, OnInit { this.readMode = true; } + protected loadFormMetadata() { + this.configMetadataForm.rows.forEach((row) => { + row.fields.forEach((field) => { + field.selectableMetadata.forEach((metadatum) => { + this.formMetadata.push(metadatum.metadata); + }); + }); + } + ); + } + /** * Retrieve bitstream's metadata */ @@ -182,6 +199,7 @@ export class SubmissionSectionUploadFileComponent implements OnChanges, OnInit { ngOnInit() { this.formId = this.formService.getUniqueId(this.fileId); this.pathCombiner = new JsonPatchOperationPathCombiner('sections', this.sectionId, 'files', this.fileIndex); + this.loadFormMetadata(); } /** @@ -250,6 +268,15 @@ export class SubmissionSectionUploadFileComponent implements OnChanges, OnInit { const path = `metadata/${metadataKey}`; this.operationsBuilder.add(this.pathCombiner.getPath(path), formData.metadata[key], true); }); + Object.keys((this.fileData.metadata)) + .filter((key) => isNotEmpty(this.fileData.metadata[key])) + .filter((key) => hasNoValue(formData.metadata[key])) + .filter((key) => this.formMetadata.includes(key)) + .forEach((key) => { + const metadataKey = key.replace(/_/g, '.'); + const path = `metadata/${metadataKey}`; + this.operationsBuilder.remove(this.pathCombiner.getPath(path)); + }); const accessConditionsToSave = []; formData.accessConditions .map((accessConditions) => accessConditions.accessConditionGroup) From 5df2f6f8d5c4b4f697bb3bbd0bbe55279d222704 Mon Sep 17 00:00:00 2001 From: Davide Negretti Date: Mon, 22 Nov 2021 11:15:11 +0100 Subject: [PATCH 04/11] [CST-4947] File description on bitstream can now be deleted --- .../upload/file/section-upload-file.component.spec.ts | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/app/submission/sections/upload/file/section-upload-file.component.spec.ts b/src/app/submission/sections/upload/file/section-upload-file.component.spec.ts index d16f648e68..cf02dadea7 100644 --- a/src/app/submission/sections/upload/file/section-upload-file.component.spec.ts +++ b/src/app/submission/sections/upload/file/section-upload-file.component.spec.ts @@ -36,7 +36,6 @@ import { FormFieldMetadataValueObject } from '../../../../shared/form/builder/mo import { SubmissionSectionUploadFileEditComponent } from './edit/section-upload-file-edit.component'; import { FormBuilderService } from '../../../../shared/form/builder/form-builder.service'; import { dateToISOFormat } from '../../../../shared/date.util'; -import { SubmissionFormModel } from '../../../../core/config/models/config-submission-form.model'; const configMetadataFormMock = { rows: [{ @@ -49,7 +48,7 @@ const configMetadataFormMock = { }] }; -fdescribe('SubmissionSectionUploadFileComponent test suite', () => { +describe('SubmissionSectionUploadFileComponent test suite', () => { let comp: SubmissionSectionUploadFileComponent; let compAsAny: any; @@ -130,8 +129,6 @@ fdescribe('SubmissionSectionUploadFileComponent test suite', () => { testFixture = createTestComponent(html, TestComponent) as ComponentFixture; testComp = testFixture.componentInstance; - // testComp.configMetadataForm = configMetadataFormMock; - // testFixture.detectChanges(); }); afterEach(() => { @@ -139,7 +136,6 @@ fdescribe('SubmissionSectionUploadFileComponent test suite', () => { }); it('should create SubmissionSectionUploadFileComponent', inject([SubmissionSectionUploadFileComponent], (app: SubmissionSectionUploadFileComponent) => { - app.configMetadataForm = Object.assign(new SubmissionFormModel(), configMetadataFormMock); expect(app).toBeDefined(); })); }); @@ -228,6 +224,7 @@ fdescribe('SubmissionSectionUploadFileComponent test suite', () => { it('should save Bitstream File data properly when form is valid', fakeAsync(() => { compAsAny.fileEditComp = TestBed.inject(SubmissionSectionUploadFileEditComponent); compAsAny.fileEditComp.formRef = {formGroup: null}; + compAsAny.fileData = fileData; compAsAny.pathCombiner = pathCombiner; const event = new Event('click', null); spyOn(comp, 'switchMode'); From 624f39df1e4cadba6358b1bc4e094627bf27f2e8 Mon Sep 17 00:00:00 2001 From: Davide Negretti Date: Mon, 22 Nov 2021 18:14:45 +0100 Subject: [PATCH 05/11] [CST-4884] Bitstream edit form moved inside modal (test TBD) --- .../section-upload-file-edit.component.html | 26 +- .../section-upload-file-edit.component.ts | 355 ++++++++++++------ .../file/section-upload-file.component.html | 37 +- .../file/section-upload-file.component.ts | 231 ++++-------- 4 files changed, 355 insertions(+), 294 deletions(-) diff --git a/src/app/submission/sections/upload/file/edit/section-upload-file-edit.component.html b/src/app/submission/sections/upload/file/edit/section-upload-file-edit.component.html index f6e0646974..2baa6c1555 100644 --- a/src/app/submission/sections/upload/file/edit/section-upload-file-edit.component.html +++ b/src/app/submission/sections/upload/file/edit/section-upload-file-edit.component.html @@ -1,9 +1,21 @@
- + +
diff --git a/src/app/submission/sections/upload/file/edit/section-upload-file-edit.component.ts b/src/app/submission/sections/upload/file/edit/section-upload-file-edit.component.ts index 96725f151e..78bcca876f 100644 --- a/src/app/submission/sections/upload/file/edit/section-upload-file-edit.component.ts +++ b/src/app/submission/sections/upload/file/edit/section-upload-file-edit.component.ts @@ -1,4 +1,4 @@ -import { ChangeDetectorRef, Component, Input, OnChanges, ViewChild } from '@angular/core'; +import { ChangeDetectorRef, Component, Input, OnInit, ViewChild } from '@angular/core'; import { FormControl } from '@angular/forms'; import { @@ -32,13 +32,23 @@ import { BITSTREAM_METADATA_FORM_GROUP_LAYOUT } from './section-upload-file-edit.model'; import { POLICY_DEFAULT_WITH_LIST } from '../../section-upload.component'; -import { isNotEmpty } from '../../../../../shared/empty.util'; +import { hasNoValue, hasValue, isNotEmpty, isNotNull } from '../../../../../shared/empty.util'; import { SubmissionFormsModel } from '../../../../../core/config/models/config-submission-forms.model'; import { FormFieldModel } from '../../../../../shared/form/builder/models/form-field.model'; import { AccessConditionOption } from '../../../../../core/config/models/config-access-condition-option.model'; import { SubmissionService } from '../../../../submission.service'; import { FormService } from '../../../../../shared/form/form.service'; import { FormComponent } from '../../../../../shared/form/form.component'; +import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap'; +import { filter, mergeMap, take } from 'rxjs/operators'; +import { dateToISOFormat } from '../../../../../shared/date.util'; +import { SubmissionObject } from '../../../../../core/submission/models/submission-object.model'; +import { WorkspaceitemSectionUploadObject } from '../../../../../core/submission/models/workspaceitem-section-upload.model'; +import { JsonPatchOperationsBuilder } from '../../../../../core/json-patch/builder/json-patch-operations-builder'; +import { SubmissionJsonPatchOperationsService } from '../../../../../core/submission/submission-json-patch-operations.service'; +import { JsonPatchOperationPathCombiner } from '../../../../../core/json-patch/builder/json-patch-operation-path-combiner'; +import { SectionUploadService } from '../../section-upload.service'; +import { Subscription } from 'rxjs'; /** * This component represents the edit form for bitstream @@ -48,7 +58,31 @@ import { FormComponent } from '../../../../../shared/form/form.component'; styleUrls: ['./section-upload-file-edit.component.scss'], templateUrl: './section-upload-file-edit.component.html', }) -export class SubmissionSectionUploadFileEditComponent implements OnChanges { +export class SubmissionSectionUploadFileEditComponent implements OnInit { + + /** + * Initialize instance variables + * + * @param activeModal + * @param {ChangeDetectorRef} cdr + * @param {FormBuilderService} formBuilderService + * @param {FormService} formService + * @param {SubmissionService} submissionService + * @param {JsonPatchOperationsBuilder} operationsBuilder + * @param {SubmissionJsonPatchOperationsService} operationsService + * @param {SectionUploadService} uploadService + */ + constructor( + protected activeModal: NgbActiveModal, + private cdr: ChangeDetectorRef, + private formBuilderService: FormBuilderService, + private formService: FormService, + private submissionService: SubmissionService, + private operationsBuilder: JsonPatchOperationsBuilder, + private operationsService: SubmissionJsonPatchOperationsService, + private uploadService: SectionUploadService, + ) { + } /** * The list of available access condition @@ -113,10 +147,15 @@ export class SubmissionSectionUploadFileEditComponent implements OnChanges { @Input() submissionId: string; /** - * The form model - * @type {DynamicFormControlModel[]} + * The list of all available metadata */ - public formModel: DynamicFormControlModel[]; + @Input() formMetadata: string[] = []; + + /** + * The [JsonPatchOperationPathCombiner] object + * @type {JsonPatchOperationPathCombiner} + */ + @Input() pathCombiner: JsonPatchOperationPathCombiner; /** * The FormComponent reference @@ -124,108 +163,18 @@ export class SubmissionSectionUploadFileEditComponent implements OnChanges { @ViewChild('formRef') public formRef: FormComponent; /** - * Initialize instance variables - * - * @param {ChangeDetectorRef} cdr - * @param {FormBuilderService} formBuilderService - * @param {FormService} formService - * @param {SubmissionService} submissionService + * The form model + * @type {DynamicFormControlModel[]} */ - constructor(private cdr: ChangeDetectorRef, - private formBuilderService: FormBuilderService, - private formService: FormService, - private submissionService: SubmissionService) { - } + formModel: DynamicFormControlModel[]; - /** - * Dispatch form model init - */ - ngOnChanges() { - if (this.fileData && this.formId) { - this.formModel = this.buildFileEditForm(); - this.cdr.detectChanges(); - } - } + isSaving = false; - /** - * Initialize form model - */ - protected buildFileEditForm() { - const configDescr: FormFieldModel = Object.assign({}, this.configMetadataForm.rows[0].fields[0]); - configDescr.repeatable = false; - const configForm = Object.assign({}, this.configMetadataForm, { - fields: Object.assign([], this.configMetadataForm.rows[0].fields[0], [ - this.configMetadataForm.rows[0].fields[0], - configDescr - ]) - }); - const formModel: DynamicFormControlModel[] = []; - const metadataGroupModelConfig = Object.assign({}, BITSTREAM_METADATA_FORM_GROUP_CONFIG); - metadataGroupModelConfig.group = this.formBuilderService.modelFromConfiguration( - this.submissionId, - configForm, - this.collectionId, - this.fileData.metadata, - this.submissionService.getSubmissionScope() - ); - formModel.push(new DynamicFormGroupModel(metadataGroupModelConfig, BITSTREAM_METADATA_FORM_GROUP_LAYOUT)); - const accessConditionTypeModelConfig = Object.assign({}, BITSTREAM_FORM_ACCESS_CONDITION_TYPE_CONFIG); - const accessConditionsArrayConfig = Object.assign({}, BITSTREAM_ACCESS_CONDITIONS_FORM_ARRAY_CONFIG); - const accessConditionTypeOptions = []; + protected subscriptions: Subscription[] = []; - if (this.collectionPolicyType === POLICY_DEFAULT_WITH_LIST) { - for (const accessCondition of this.availableAccessConditionOptions) { - accessConditionTypeOptions.push( - { - label: accessCondition.name, - value: accessCondition.name - } - ); - } - accessConditionTypeModelConfig.options = accessConditionTypeOptions; - - // Dynamically assign of relation in config. For startdate, endDate, groups. - const hasStart = []; - const hasEnd = []; - const hasGroups = []; - this.availableAccessConditionOptions.forEach((condition) => { - const showStart: boolean = condition.hasStartDate === true; - const showEnd: boolean = condition.hasEndDate === true; - const showGroups: boolean = showStart || showEnd; - if (showStart) { - hasStart.push({ id: 'name', value: condition.name }); - } - if (showEnd) { - hasEnd.push({ id: 'name', value: condition.name }); - } - if (showGroups) { - hasGroups.push({ id: 'name', value: condition.name }); - } - }); - const confStart = { relations: [{ match: MATCH_ENABLED, operator: OR_OPERATOR, when: hasStart }] }; - const confEnd = { relations: [{ match: MATCH_ENABLED, operator: OR_OPERATOR, when: hasEnd }] }; - - accessConditionsArrayConfig.groupFactory = () => { - const type = new DynamicSelectModel(accessConditionTypeModelConfig, BITSTREAM_FORM_ACCESS_CONDITION_TYPE_LAYOUT); - const startDateConfig = Object.assign({}, BITSTREAM_FORM_ACCESS_CONDITION_START_DATE_CONFIG, confStart); - const endDateConfig = Object.assign({}, BITSTREAM_FORM_ACCESS_CONDITION_END_DATE_CONFIG, confEnd); - - const startDate = new DynamicDatePickerModel(startDateConfig, BITSTREAM_FORM_ACCESS_CONDITION_START_DATE_LAYOUT); - const endDate = new DynamicDatePickerModel(endDateConfig, BITSTREAM_FORM_ACCESS_CONDITION_END_DATE_LAYOUT); - const accessConditionGroupConfig = Object.assign({}, BITSTREAM_ACCESS_CONDITION_GROUP_CONFIG); - accessConditionGroupConfig.group = [type, startDate, endDate]; - return [new DynamicFormGroupModel(accessConditionGroupConfig, BITSTREAM_ACCESS_CONDITION_GROUP_LAYOUT)]; - }; - - // Number of access conditions blocks in form - accessConditionsArrayConfig.initialCount = isNotEmpty(this.fileData.accessConditions) ? this.fileData.accessConditions.length : 1; - formModel.push( - new DynamicFormArrayModel(accessConditionsArrayConfig, BITSTREAM_ACCESS_CONDITIONS_FORM_ARRAY_LAYOUT) - ); - - } - this.initModelData(formModel); - return formModel; + private static retrieveValueFromField(field: any) { + const temp = Array.isArray(field) ? field[0] : field; + return (temp) ? temp.value : undefined; } /** @@ -262,12 +211,21 @@ export class SubmissionSectionUploadFileEditComponent implements OnChanges { * @param event * The event emitted */ - public onChange(event: DynamicFormControlEvent) { + onChange(event: DynamicFormControlEvent) { if (event.model.id === 'name') { this.setOptions(event.model, event.control); } } + onModalClose() { + this.activeModal.dismiss(); + } + + onSubmit() { + this.isSaving = true; + this.saveBitstreamData(); + } + /** * Update `startDate`, 'groupUUID' and 'endDate' model * @@ -323,4 +281,191 @@ export class SubmissionSectionUploadFileEditComponent implements OnChanges { } } + /** + * Dispatch form model init + */ + ngOnInit() { + if (this.fileData && this.formId) { + this.formModel = this.buildFileEditForm(); + this.cdr.detectChanges(); + } + } + + ngOnDestroy(): void { + this.unsubscribeAll(); + } + + /** + * Initialize form model + */ + protected buildFileEditForm() { + const configDescr: FormFieldModel = Object.assign({}, this.configMetadataForm.rows[0].fields[0]); + configDescr.repeatable = false; + const configForm = Object.assign({}, this.configMetadataForm, { + fields: Object.assign([], this.configMetadataForm.rows[0].fields[0], [ + this.configMetadataForm.rows[0].fields[0], + configDescr + ]) + }); + const formModel: DynamicFormControlModel[] = []; + const metadataGroupModelConfig = Object.assign({}, BITSTREAM_METADATA_FORM_GROUP_CONFIG); + metadataGroupModelConfig.group = this.formBuilderService.modelFromConfiguration( + this.submissionId, + configForm, + this.collectionId, + this.fileData.metadata, + this.submissionService.getSubmissionScope() + ); + formModel.push(new DynamicFormGroupModel(metadataGroupModelConfig, BITSTREAM_METADATA_FORM_GROUP_LAYOUT)); + const accessConditionTypeModelConfig = Object.assign({}, BITSTREAM_FORM_ACCESS_CONDITION_TYPE_CONFIG); + const accessConditionsArrayConfig = Object.assign({}, BITSTREAM_ACCESS_CONDITIONS_FORM_ARRAY_CONFIG); + const accessConditionTypeOptions = []; + + if (this.collectionPolicyType === POLICY_DEFAULT_WITH_LIST) { + for (const accessCondition of this.availableAccessConditionOptions) { + accessConditionTypeOptions.push( + { + label: accessCondition.name, + value: accessCondition.name + } + ); + } + accessConditionTypeModelConfig.options = accessConditionTypeOptions; + + // Dynamically assign of relation in config. For startdate, endDate, groups. + const hasStart = []; + const hasEnd = []; + const hasGroups = []; + this.availableAccessConditionOptions.forEach((condition) => { + const showStart: boolean = condition.hasStartDate === true; + const showEnd: boolean = condition.hasEndDate === true; + const showGroups: boolean = showStart || showEnd; + if (showStart) { + hasStart.push({id: 'name', value: condition.name}); + } + if (showEnd) { + hasEnd.push({id: 'name', value: condition.name}); + } + if (showGroups) { + hasGroups.push({id: 'name', value: condition.name}); + } + }); + const confStart = {relations: [{match: MATCH_ENABLED, operator: OR_OPERATOR, when: hasStart}]}; + const confEnd = {relations: [{match: MATCH_ENABLED, operator: OR_OPERATOR, when: hasEnd}]}; + + accessConditionsArrayConfig.groupFactory = () => { + const type = new DynamicSelectModel(accessConditionTypeModelConfig, BITSTREAM_FORM_ACCESS_CONDITION_TYPE_LAYOUT); + const startDateConfig = Object.assign({}, BITSTREAM_FORM_ACCESS_CONDITION_START_DATE_CONFIG, confStart); + const endDateConfig = Object.assign({}, BITSTREAM_FORM_ACCESS_CONDITION_END_DATE_CONFIG, confEnd); + + const startDate = new DynamicDatePickerModel(startDateConfig, BITSTREAM_FORM_ACCESS_CONDITION_START_DATE_LAYOUT); + const endDate = new DynamicDatePickerModel(endDateConfig, BITSTREAM_FORM_ACCESS_CONDITION_END_DATE_LAYOUT); + const accessConditionGroupConfig = Object.assign({}, BITSTREAM_ACCESS_CONDITION_GROUP_CONFIG); + accessConditionGroupConfig.group = [type, startDate, endDate]; + return [new DynamicFormGroupModel(accessConditionGroupConfig, BITSTREAM_ACCESS_CONDITION_GROUP_LAYOUT)]; + }; + + // Number of access conditions blocks in form + accessConditionsArrayConfig.initialCount = isNotEmpty(this.fileData.accessConditions) ? this.fileData.accessConditions.length : 1; + formModel.push( + new DynamicFormArrayModel(accessConditionsArrayConfig, BITSTREAM_ACCESS_CONDITIONS_FORM_ARRAY_LAYOUT) + ); + + } + this.initModelData(formModel); + return formModel; + } + + /** + * Save bitstream metadata + */ + protected saveBitstreamData() { + // validate form + this.formService.validateAllFormFields(this.formRef.formGroup); + const saveBitstreamDataSubscription = this.formService.isValid(this.formId).pipe( + take(1), + filter((isValid) => isValid), + mergeMap(() => this.formService.getFormData(this.formId)), + take(1), + mergeMap((formData: any) => { + // collect bitstream metadata + Object.keys((formData.metadata)) + .filter((key) => isNotEmpty(formData.metadata[key])) + .forEach((key) => { + const metadataKey = key.replace(/_/g, '.'); + const path = `metadata/${metadataKey}`; + this.operationsBuilder.add(this.pathCombiner.getPath(path), formData.metadata[key], true); + }); + Object.keys((this.fileData.metadata)) + .filter((key) => isNotEmpty(this.fileData.metadata[key])) + .filter((key) => hasNoValue(formData.metadata[key])) + .filter((key) => this.formMetadata.includes(key)) + .forEach((key) => { + const metadataKey = key.replace(/_/g, '.'); + const path = `metadata/${metadataKey}`; + this.operationsBuilder.remove(this.pathCombiner.getPath(path)); + }); + const accessConditionsToSave = []; + formData.accessConditions + .map((accessConditions) => accessConditions.accessConditionGroup) + .filter((accessCondition) => isNotEmpty(accessCondition)) + .forEach((accessCondition) => { + let accessConditionOpt; + + this.availableAccessConditionOptions + .filter((element) => isNotNull(accessCondition.name) && element.name === accessCondition.name[0].value) + .forEach((element) => accessConditionOpt = element); + + if (accessConditionOpt) { + const currentAccessCondition = Object.assign({}, accessCondition); + currentAccessCondition.name = SubmissionSectionUploadFileEditComponent.retrieveValueFromField(accessCondition.name); + + /* When start and end date fields are deactivated, their values may be still present in formData, + therefore it is necessary to delete them if they're not allowed by the current access condition option. */ + if (!accessConditionOpt.hasStartDate) { + delete currentAccessCondition.startDate; + } else if (accessCondition.startDate) { + const startDate = SubmissionSectionUploadFileEditComponent.retrieveValueFromField(accessCondition.startDate); + currentAccessCondition.startDate = dateToISOFormat(startDate); + } + if (!accessConditionOpt.hasEndDate) { + delete currentAccessCondition.endDate; + } else if (accessCondition.endDate) { + const endDate = SubmissionSectionUploadFileEditComponent.retrieveValueFromField(accessCondition.endDate); + currentAccessCondition.endDate = dateToISOFormat(endDate); + } + accessConditionsToSave.push(currentAccessCondition); + } + }); + + if (isNotEmpty(accessConditionsToSave)) { + this.operationsBuilder.add(this.pathCombiner.getPath('accessConditions'), accessConditionsToSave, true); + } + + // dispatch a PATCH request to save metadata + return this.operationsService.jsonPatchByResourceID( + this.submissionService.getSubmissionObjectLinkName(), + this.submissionId, + this.pathCombiner.rootElement, + this.pathCombiner.subRootElement); + }) + ).subscribe((result: SubmissionObject[]) => { + if (result[0].sections[this.sectionId]) { + const uploadSection = (result[0].sections[this.sectionId] as WorkspaceitemSectionUploadObject); + Object.keys(uploadSection.files) + .filter((key) => uploadSection.files[key].uuid === this.fileId) + .forEach((key) => this.uploadService.updateFileData( + this.submissionId, this.sectionId, this.fileId, uploadSection.files[key]) + ); + } + this.isSaving = false; + this.activeModal.close(); + }); + this.subscriptions.push(saveBitstreamDataSubscription); + } + + private unsubscribeAll() { + this.subscriptions.filter((sub) => hasValue(sub)).forEach((sub) => sub.unsubscribe()); + } + } diff --git a/src/app/submission/sections/upload/file/section-upload-file.component.html b/src/app/submission/sections/upload/file/section-upload-file.component.html index 259418c22c..8749c8dcf2 100644 --- a/src/app/submission/sections/upload/file/section-upload-file.component.html +++ b/src/app/submission/sections/upload/file/section-upload-file.component.html @@ -9,14 +9,14 @@

{{fileName}} ({{fileData?.sizeBytes | dsFileSize}})

- + - - - - -
- - + diff --git a/src/app/submission/sections/upload/file/section-upload-file.component.ts b/src/app/submission/sections/upload/file/section-upload-file.component.ts index 9807aecda3..e152d2f651 100644 --- a/src/app/submission/sections/upload/file/section-upload-file.component.ts +++ b/src/app/submission/sections/upload/file/section-upload-file.component.ts @@ -1,25 +1,23 @@ import { ChangeDetectorRef, Component, Input, OnChanges, OnInit, ViewChild } from '@angular/core'; import { BehaviorSubject, Subscription } from 'rxjs'; -import { filter, mergeMap, take } from 'rxjs/operators'; +import { filter } from 'rxjs/operators'; import { DynamicFormControlModel, } from '@ng-dynamic-forms/core'; import { NgbModal } from '@ng-bootstrap/ng-bootstrap'; import { SectionUploadService } from '../section-upload.service'; -import { hasNoValue, isNotEmpty, isNotNull, isNotUndefined } from '../../../../shared/empty.util'; +import { hasValue, isNotUndefined } from '../../../../shared/empty.util'; import { FormService } from '../../../../shared/form/form.service'; import { JsonPatchOperationsBuilder } from '../../../../core/json-patch/builder/json-patch-operations-builder'; import { JsonPatchOperationPathCombiner } from '../../../../core/json-patch/builder/json-patch-operation-path-combiner'; import { WorkspaceitemSectionUploadFileObject } from '../../../../core/submission/models/workspaceitem-section-upload-file.model'; import { SubmissionFormsModel } from '../../../../core/config/models/config-submission-forms.model'; -import { dateToISOFormat } from '../../../../shared/date.util'; import { SubmissionService } from '../../../submission.service'; import { HALEndpointService } from '../../../../core/shared/hal-endpoint.service'; import { SubmissionJsonPatchOperationsService } from '../../../../core/submission/submission-json-patch-operations.service'; -import { SubmissionObject } from '../../../../core/submission/models/submission-object.model'; -import { WorkspaceitemSectionUploadObject } from '../../../../core/submission/models/workspaceitem-section-upload.model'; import { SubmissionSectionUploadFileEditComponent } from './edit/section-upload-file-edit.component'; import { Bitstream } from '../../../../core/shared/bitstream.model'; +import { NgbModalOptions } from '@ng-bootstrap/ng-bootstrap/modal/modal-config'; /** * This component represents a single bitstream contained in the submission @@ -87,6 +85,13 @@ export class SubmissionSectionUploadFileComponent implements OnChanges, OnInit { */ @Input() submissionId: string; + /** + * The [[SubmissionSectionUploadFileEditComponent]] reference + * @type {SubmissionSectionUploadFileEditComponent} + */ + @ViewChild(SubmissionSectionUploadFileEditComponent) fileEditComp: SubmissionSectionUploadFileEditComponent; + + /** * The bitstream's metadata data * @type {WorkspaceitemSectionUploadFileObject} @@ -135,12 +140,6 @@ export class SubmissionSectionUploadFileComponent implements OnChanges, OnInit { */ protected formMetadata: string[] = []; - /** - * The [[SubmissionSectionUploadFileEditComponent]] reference - * @type {SubmissionSectionUploadFileEditComponent} - */ - @ViewChild(SubmissionSectionUploadFileEditComponent) fileEditComp: SubmissionSectionUploadFileEditComponent; - /** * Initialize instance variables * @@ -153,28 +152,19 @@ export class SubmissionSectionUploadFileComponent implements OnChanges, OnInit { * @param {SubmissionService} submissionService * @param {SectionUploadService} uploadService */ - constructor(private cdr: ChangeDetectorRef, - private formService: FormService, - private halService: HALEndpointService, - private modalService: NgbModal, - private operationsBuilder: JsonPatchOperationsBuilder, - private operationsService: SubmissionJsonPatchOperationsService, - private submissionService: SubmissionService, - private uploadService: SectionUploadService) { + constructor( + private cdr: ChangeDetectorRef, + private formService: FormService, + private halService: HALEndpointService, + private modalService: NgbModal, + private operationsBuilder: JsonPatchOperationsBuilder, + private operationsService: SubmissionJsonPatchOperationsService, + private submissionService: SubmissionService, + private uploadService: SectionUploadService, + ) { this.readMode = true; } - protected loadFormMetadata() { - this.configMetadataForm.rows.forEach((row) => { - row.fields.forEach((field) => { - field.selectableMetadata.forEach((metadatum) => { - this.formMetadata.push(metadatum.metadata); - }); - }); - } - ); - } - /** * Retrieve bitstream's metadata */ @@ -202,22 +192,6 @@ export class SubmissionSectionUploadFileComponent implements OnChanges, OnInit { this.loadFormMetadata(); } - /** - * Delete bitstream from submission - */ - protected deleteFile() { - this.operationsBuilder.remove(this.pathCombiner.getPath()); - this.subscriptions.push(this.operationsService.jsonPatchByResourceID( - this.submissionService.getSubmissionObjectLinkName(), - this.submissionId, - this.pathCombiner.rootElement, - this.pathCombiner.subRootElement) - .subscribe(() => { - this.uploadService.removeUploadedFile(this.submissionId, this.sectionId, this.fileId); - this.processingDelete$.next(false); - })); - } - /** * Show confirmation dialog for delete */ @@ -243,108 +217,6 @@ export class SubmissionSectionUploadFileComponent implements OnChanges, OnInit { }); } - /** - * Save bitstream metadata - * - * @param event - * the click event emitted - */ - public saveBitstreamData(event) { - event.preventDefault(); - - // validate form - this.formService.validateAllFormFields(this.fileEditComp.formRef.formGroup); - this.subscriptions.push(this.formService.isValid(this.formId).pipe( - take(1), - filter((isValid) => isValid), - mergeMap(() => this.formService.getFormData(this.formId)), - take(1), - mergeMap((formData: any) => { - // collect bitstream metadata - Object.keys((formData.metadata)) - .filter((key) => isNotEmpty(formData.metadata[key])) - .forEach((key) => { - const metadataKey = key.replace(/_/g, '.'); - const path = `metadata/${metadataKey}`; - this.operationsBuilder.add(this.pathCombiner.getPath(path), formData.metadata[key], true); - }); - Object.keys((this.fileData.metadata)) - .filter((key) => isNotEmpty(this.fileData.metadata[key])) - .filter((key) => hasNoValue(formData.metadata[key])) - .filter((key) => this.formMetadata.includes(key)) - .forEach((key) => { - const metadataKey = key.replace(/_/g, '.'); - const path = `metadata/${metadataKey}`; - this.operationsBuilder.remove(this.pathCombiner.getPath(path)); - }); - const accessConditionsToSave = []; - formData.accessConditions - .map((accessConditions) => accessConditions.accessConditionGroup) - .filter((accessCondition) => isNotEmpty(accessCondition)) - .forEach((accessCondition) => { - let accessConditionOpt; - - this.availableAccessConditionOptions - .filter((element) => isNotNull(accessCondition.name) && element.name === accessCondition.name[0].value) - .forEach((element) => accessConditionOpt = element); - - if (accessConditionOpt) { - const currentAccessCondition = Object.assign({}, accessCondition); - currentAccessCondition.name = this.retrieveValueFromField(accessCondition.name); - - /* When start and end date fields are deactivated, their values may be still present in formData, - therefore it is necessary to delete them if they're not allowed by the current access condition option. */ - if (!accessConditionOpt.hasStartDate) { - delete currentAccessCondition.startDate; - } else if (accessCondition.startDate) { - const startDate = this.retrieveValueFromField(accessCondition.startDate); - currentAccessCondition.startDate = dateToISOFormat(startDate); - } - if (!accessConditionOpt.hasEndDate) { - delete currentAccessCondition.endDate; - } else if (accessCondition.endDate) { - const endDate = this.retrieveValueFromField(accessCondition.endDate); - currentAccessCondition.endDate = dateToISOFormat(endDate); - } - accessConditionsToSave.push(currentAccessCondition); - } - }); - - if (isNotEmpty(accessConditionsToSave)) { - this.operationsBuilder.add(this.pathCombiner.getPath('accessConditions'), accessConditionsToSave, true); - } - - // dispatch a PATCH request to save metadata - return this.operationsService.jsonPatchByResourceID( - this.submissionService.getSubmissionObjectLinkName(), - this.submissionId, - this.pathCombiner.rootElement, - this.pathCombiner.subRootElement); - }) - ).subscribe((result: SubmissionObject[]) => { - if (result[0].sections[this.sectionId]) { - const uploadSection = (result[0].sections[this.sectionId] as WorkspaceitemSectionUploadObject); - Object.keys(uploadSection.files) - .filter((key) => uploadSection.files[key].uuid === this.fileId) - .forEach((key) => this.uploadService.updateFileData( - this.submissionId, this.sectionId, this.fileId, uploadSection.files[key]) - ); - } - this.switchMode(); - })); - } - - /** - * Retrieve field value - * - * @param field - * the specified field object - */ - private retrieveValueFromField(field: any) { - const temp = Array.isArray(field) ? field[0] : field; - return (temp) ? temp.value : undefined; - } - /** * Switch from edit form to metadata view */ @@ -353,4 +225,67 @@ export class SubmissionSectionUploadFileComponent implements OnChanges, OnInit { this.cdr.detectChanges(); } + editBitstreamData() { + + const options: NgbModalOptions = { + size: 'xl', + backdrop: 'static', + }; + + const activeModal = this.modalService.open(SubmissionSectionUploadFileEditComponent, options); + + activeModal.componentInstance.availableAccessConditionOptions = this.availableAccessConditionOptions; + activeModal.componentInstance.collectionId = this.collectionId; + activeModal.componentInstance.collectionPolicyType = this.collectionPolicyType; + activeModal.componentInstance.configMetadataForm = this.configMetadataForm; + activeModal.componentInstance.fileData = this.fileData; + activeModal.componentInstance.fileId = this.fileId; + activeModal.componentInstance.fileIndex = this.fileIndex; + activeModal.componentInstance.formId = this.formId; + activeModal.componentInstance.sectionId = this.sectionId; + activeModal.componentInstance.formMetadata = this.formMetadata; + activeModal.componentInstance.pathCombiner = this.pathCombiner; + activeModal.componentInstance.submissionId = this.submissionId; + + /*activeModal.componentInstance.saveBitstreamDataEvent.subscribe((res) => { + console.log(JSON.stringify(res)); + });*/ + + } + + ngOnDestroy(): void { + this.unsubscribeAll(); + } + + unsubscribeAll() { + this.subscriptions.filter((sub) => hasValue(sub)).forEach((sub) => sub.unsubscribe()); + } + + protected loadFormMetadata() { + this.configMetadataForm.rows.forEach((row) => { + row.fields.forEach((field) => { + field.selectableMetadata.forEach((metadatum) => { + this.formMetadata.push(metadatum.metadata); + }); + }); + } + ); + } + + /** + * Delete bitstream from submission + */ + protected deleteFile() { + this.operationsBuilder.remove(this.pathCombiner.getPath()); + this.subscriptions.push(this.operationsService.jsonPatchByResourceID( + this.submissionService.getSubmissionObjectLinkName(), + this.submissionId, + this.pathCombiner.rootElement, + this.pathCombiner.subRootElement) + .subscribe(() => { + this.uploadService.removeUploadedFile(this.submissionId, this.sectionId, this.fileId); + this.processingDelete$.next(false); + })); + } + } From 31442f36a3fbe9101de5b03a45f672722f48d48b Mon Sep 17 00:00:00 2001 From: Davide Negretti Date: Mon, 22 Nov 2021 19:11:58 +0100 Subject: [PATCH 06/11] [CST-4884] Bitstream edit form moved inside modal (test WIP) --- ...section-upload-file-edit.component.spec.ts | 43 +++++++++++++++++-- .../section-upload-file-edit.component.ts | 16 +++---- .../section-upload-file.component.spec.ts | 21 +++------ 3 files changed, 52 insertions(+), 28 deletions(-) diff --git a/src/app/submission/sections/upload/file/edit/section-upload-file-edit.component.spec.ts b/src/app/submission/sections/upload/file/edit/section-upload-file-edit.component.spec.ts index a644cf8270..9203930ef5 100644 --- a/src/app/submission/sections/upload/file/edit/section-upload-file-edit.component.spec.ts +++ b/src/app/submission/sections/upload/file/edit/section-upload-file-edit.component.spec.ts @@ -30,15 +30,31 @@ import { FormService } from '../../../../../shared/form/form.service'; import { getMockFormService } from '../../../../../shared/mocks/form-service.mock'; import { Group } from '../../../../../core/eperson/models/group.model'; import { createTestComponent } from '../../../../../shared/testing/utils.test'; +import { NgbActiveModal, NgbModal } from '@ng-bootstrap/ng-bootstrap'; +import { JsonPatchOperationsBuilder } from '../../../../../core/json-patch/builder/json-patch-operations-builder'; +import { SubmissionJsonPatchOperationsServiceStub } from '../../../../../shared/testing/submission-json-patch-operations-service.stub'; +import { SubmissionJsonPatchOperationsService } from '../../../../../core/submission/submission-json-patch-operations.service'; +import { SectionUploadService } from '../../section-upload.service'; +import { getMockSectionUploadService } from '../../../../../shared/mocks/section-upload.service.mock'; +import { FormFieldMetadataValueObject } from '../../../../../shared/form/builder/models/form-field-metadata-value.model'; -describe('SubmissionSectionUploadFileEditComponent test suite', () => { +const jsonPatchOpBuilder: any = jasmine.createSpyObj('jsonPatchOpBuilder', { + add: jasmine.createSpy('add'), + replace: jasmine.createSpy('replace'), + remove: jasmine.createSpy('remove'), +}); + +fdescribe('SubmissionSectionUploadFileEditComponent test suite', () => { let comp: SubmissionSectionUploadFileEditComponent; let compAsAny: any; let fixture: ComponentFixture; let submissionServiceStub: SubmissionServiceStub; let formbuilderService: any; + let operationsBuilder: any; + let operationsService: any; + const submissionJsonPatchOperationsServiceStub = new SubmissionJsonPatchOperationsServiceStub(); const submissionId = mockSubmissionId; const sectionId = 'upload'; const collectionId = mockSubmissionCollectionId; @@ -66,9 +82,14 @@ describe('SubmissionSectionUploadFileEditComponent test suite', () => { providers: [ { provide: FormService, useValue: getMockFormService() }, { provide: SubmissionService, useClass: SubmissionServiceStub }, + { provide: SubmissionJsonPatchOperationsService, useValue: submissionJsonPatchOperationsServiceStub }, + { provide: JsonPatchOperationsBuilder, useValue: jsonPatchOpBuilder }, + { provide: SectionUploadService, useValue: getMockSectionUploadService() }, FormBuilderService, ChangeDetectorRef, - SubmissionSectionUploadFileEditComponent + SubmissionSectionUploadFileEditComponent, + NgbModal, + NgbActiveModal, ], schemas: [NO_ERRORS_SCHEMA] }).compileComponents().then(); @@ -114,6 +135,8 @@ describe('SubmissionSectionUploadFileEditComponent test suite', () => { compAsAny = comp; submissionServiceStub = TestBed.inject(SubmissionService as any); formbuilderService = TestBed.inject(FormBuilderService); + operationsBuilder = TestBed.inject(JsonPatchOperationsBuilder); + operationsService = TestBed.inject(SubmissionJsonPatchOperationsService); comp.submissionId = submissionId; comp.collectionId = collectionId; @@ -135,7 +158,7 @@ describe('SubmissionSectionUploadFileEditComponent test suite', () => { comp.fileData = fileData; comp.formId = 'testFileForm'; - comp.ngOnChanges(); + comp.ngOnInit(); expect(comp.formModel).toBeDefined(); expect(comp.formModel.length).toBe(2); @@ -165,7 +188,7 @@ describe('SubmissionSectionUploadFileEditComponent test suite', () => { comp.fileData = fileData; comp.formId = 'testFileForm'; - comp.ngOnChanges(); + comp.ngOnInit(); const model: DynamicSelectModel = formbuilderService.findById('name', comp.formModel, 0); const formGroup = formbuilderService.createFormGroup(comp.formModel); @@ -186,6 +209,18 @@ describe('SubmissionSectionUploadFileEditComponent test suite', () => { comp.setOptions(model, control); expect(formbuilderService.findById).toHaveBeenCalledWith('startDate', (model.parent as DynamicFormArrayGroupModel).group); }); + + it('should retrieve Value From Field properly', () => { + let field; + expect(compAsAny.retrieveValueFromField(field)).toBeUndefined(); + + field = new FormFieldMetadataValueObject('test'); + expect(compAsAny.retrieveValueFromField(field)).toBe('test'); + + field = [new FormFieldMetadataValueObject('test')]; + expect(compAsAny.retrieveValueFromField(field)).toBe('test'); + }); + }); }); diff --git a/src/app/submission/sections/upload/file/edit/section-upload-file-edit.component.ts b/src/app/submission/sections/upload/file/edit/section-upload-file-edit.component.ts index 78bcca876f..eb8fbf95d0 100644 --- a/src/app/submission/sections/upload/file/edit/section-upload-file-edit.component.ts +++ b/src/app/submission/sections/upload/file/edit/section-upload-file-edit.component.ts @@ -172,11 +172,6 @@ export class SubmissionSectionUploadFileEditComponent implements OnInit { protected subscriptions: Subscription[] = []; - private static retrieveValueFromField(field: any) { - const temp = Array.isArray(field) ? field[0] : field; - return (temp) ? temp.value : undefined; - } - /** * Initialize form model values * @@ -295,6 +290,11 @@ export class SubmissionSectionUploadFileEditComponent implements OnInit { this.unsubscribeAll(); } + protected retrieveValueFromField(field: any) { + const temp = Array.isArray(field) ? field[0] : field; + return (temp) ? temp.value : undefined; + } + /** * Initialize form model */ @@ -418,20 +418,20 @@ export class SubmissionSectionUploadFileEditComponent implements OnInit { if (accessConditionOpt) { const currentAccessCondition = Object.assign({}, accessCondition); - currentAccessCondition.name = SubmissionSectionUploadFileEditComponent.retrieveValueFromField(accessCondition.name); + currentAccessCondition.name = this.retrieveValueFromField(accessCondition.name); /* When start and end date fields are deactivated, their values may be still present in formData, therefore it is necessary to delete them if they're not allowed by the current access condition option. */ if (!accessConditionOpt.hasStartDate) { delete currentAccessCondition.startDate; } else if (accessCondition.startDate) { - const startDate = SubmissionSectionUploadFileEditComponent.retrieveValueFromField(accessCondition.startDate); + const startDate = this.retrieveValueFromField(accessCondition.startDate); currentAccessCondition.startDate = dateToISOFormat(startDate); } if (!accessConditionOpt.hasEndDate) { delete currentAccessCondition.endDate; } else if (accessCondition.endDate) { - const endDate = SubmissionSectionUploadFileEditComponent.retrieveValueFromField(accessCondition.endDate); + const endDate = this.retrieveValueFromField(accessCondition.endDate); currentAccessCondition.endDate = dateToISOFormat(endDate); } accessConditionsToSave.push(currentAccessCondition); diff --git a/src/app/submission/sections/upload/file/section-upload-file.component.spec.ts b/src/app/submission/sections/upload/file/section-upload-file.component.spec.ts index cf02dadea7..a8ab34d866 100644 --- a/src/app/submission/sections/upload/file/section-upload-file.component.spec.ts +++ b/src/app/submission/sections/upload/file/section-upload-file.component.spec.ts @@ -48,7 +48,7 @@ const configMetadataFormMock = { }] }; -describe('SubmissionSectionUploadFileComponent test suite', () => { +fdescribe('SubmissionSectionUploadFileComponent test suite', () => { let comp: SubmissionSectionUploadFileComponent; let compAsAny: any; @@ -221,7 +221,7 @@ describe('SubmissionSectionUploadFileComponent test suite', () => { pathCombiner.subRootElement); }); - it('should save Bitstream File data properly when form is valid', fakeAsync(() => { + /*it('should save Bitstream File data properly when form is valid', fakeAsync(() => { compAsAny.fileEditComp = TestBed.inject(SubmissionSectionUploadFileEditComponent); compAsAny.fileEditComp.formRef = {formGroup: null}; compAsAny.fileData = fileData; @@ -275,9 +275,9 @@ describe('SubmissionSectionUploadFileComponent test suite', () => { expect(comp.switchMode).toHaveBeenCalled(); expect(uploadService.updateFileData).toHaveBeenCalledWith(submissionId, sectionId, mockUploadFiles[0].uuid, mockUploadFiles[0]); - })); + }));*/ - it('should not save Bitstream File data properly when form is not valid', fakeAsync(() => { + /*it('should not save Bitstream File data properly when form is not valid', fakeAsync(() => { compAsAny.fileEditComp = TestBed.inject(SubmissionSectionUploadFileEditComponent); compAsAny.fileEditComp.formRef = {formGroup: null}; compAsAny.pathCombiner = pathCombiner; @@ -289,18 +289,7 @@ describe('SubmissionSectionUploadFileComponent test suite', () => { expect(comp.switchMode).not.toHaveBeenCalled(); expect(uploadService.updateFileData).not.toHaveBeenCalled(); - })); - - it('should retrieve Value From Field properly', () => { - let field; - expect(compAsAny.retrieveValueFromField(field)).toBeUndefined(); - - field = new FormFieldMetadataValueObject('test'); - expect(compAsAny.retrieveValueFromField(field)).toBe('test'); - - field = [new FormFieldMetadataValueObject('test')]; - expect(compAsAny.retrieveValueFromField(field)).toBe('test'); - }); + }));*/ it('should switch read mode', () => { comp.readMode = false; From 5e8813f5b6c811ceb611eebdcd128dc3d67a4d8b Mon Sep 17 00:00:00 2001 From: Davide Negretti Date: Wed, 24 Nov 2021 13:12:01 +0100 Subject: [PATCH 07/11] [CST-4884] Bitstream edit form moved inside modal (test WIP) --- ...section-upload-file-edit.component.spec.ts | 89 ++++++++- .../section-upload-file-edit.component.ts | 183 +++++++++--------- .../section-upload-file.component.spec.ts | 6 +- 3 files changed, 179 insertions(+), 99 deletions(-) diff --git a/src/app/submission/sections/upload/file/edit/section-upload-file-edit.component.spec.ts b/src/app/submission/sections/upload/file/edit/section-upload-file-edit.component.spec.ts index 9203930ef5..866277108f 100644 --- a/src/app/submission/sections/upload/file/edit/section-upload-file-edit.component.spec.ts +++ b/src/app/submission/sections/upload/file/edit/section-upload-file-edit.component.spec.ts @@ -1,5 +1,5 @@ import { ChangeDetectorRef, Component, NO_ERRORS_SCHEMA } from '@angular/core'; -import { waitForAsync, ComponentFixture, inject, TestBed } from '@angular/core/testing'; +import { waitForAsync, ComponentFixture, inject, TestBed, fakeAsync, tick } from '@angular/core/testing'; import { BrowserModule } from '@angular/platform-browser'; import { CommonModule } from '@angular/common'; import { TranslateModule } from '@ngx-translate/core'; @@ -17,18 +17,18 @@ import { SubmissionService } from '../../../../submission.service'; import { SubmissionSectionUploadFileEditComponent } from './section-upload-file-edit.component'; import { POLICY_DEFAULT_WITH_LIST } from '../../section-upload.component'; import { - mockGroup, mockSubmissionCollectionId, mockSubmissionId, mockUploadConfigResponse, mockUploadConfigResponseMetadata, - mockUploadFiles + mockUploadFiles, + mockFileFormData, + mockSubmissionObject, } from '../../../../../shared/mocks/submission.mock'; import { FormsModule, ReactiveFormsModule } from '@angular/forms'; import { FormComponent } from '../../../../../shared/form/form.component'; import { FormService } from '../../../../../shared/form/form.service'; import { getMockFormService } from '../../../../../shared/mocks/form-service.mock'; -import { Group } from '../../../../../core/eperson/models/group.model'; import { createTestComponent } from '../../../../../shared/testing/utils.test'; import { NgbActiveModal, NgbModal } from '@ng-bootstrap/ng-bootstrap'; import { JsonPatchOperationsBuilder } from '../../../../../core/json-patch/builder/json-patch-operations-builder'; @@ -37,6 +37,9 @@ import { SubmissionJsonPatchOperationsService } from '../../../../../core/submis import { SectionUploadService } from '../../section-upload.service'; import { getMockSectionUploadService } from '../../../../../shared/mocks/section-upload.service.mock'; import { FormFieldMetadataValueObject } from '../../../../../shared/form/builder/models/form-field-metadata-value.model'; +import { JsonPatchOperationPathCombiner } from '../../../../../core/json-patch/builder/json-patch-operation-path-combiner'; +import { dateToISOFormat } from '../../../../../shared/date.util'; +import { of } from 'rxjs'; const jsonPatchOpBuilder: any = jasmine.createSpyObj('jsonPatchOpBuilder', { add: jasmine.createSpy('add'), @@ -44,6 +47,8 @@ const jsonPatchOpBuilder: any = jasmine.createSpyObj('jsonPatchOpBuilder', { remove: jasmine.createSpy('remove'), }); +const formMetadataMock = ['dc.title', 'dc.description']; + fdescribe('SubmissionSectionUploadFileEditComponent test suite', () => { let comp: SubmissionSectionUploadFileEditComponent; @@ -53,6 +58,8 @@ fdescribe('SubmissionSectionUploadFileEditComponent test suite', () => { let formbuilderService: any; let operationsBuilder: any; let operationsService: any; + let formService: any; + let uploadService: any; const submissionJsonPatchOperationsServiceStub = new SubmissionJsonPatchOperationsServiceStub(); const submissionId = mockSubmissionId; @@ -64,6 +71,7 @@ fdescribe('SubmissionSectionUploadFileEditComponent test suite', () => { const fileIndex = '0'; const fileId = '123456-test-upload'; const fileData: any = mockUploadFiles[0]; + const pathCombiner = new JsonPatchOperationPathCombiner('sections', sectionId, 'files', fileIndex); beforeEach(waitForAsync(() => { TestBed.configureTestingModule({ @@ -137,6 +145,8 @@ fdescribe('SubmissionSectionUploadFileEditComponent test suite', () => { formbuilderService = TestBed.inject(FormBuilderService); operationsBuilder = TestBed.inject(JsonPatchOperationsBuilder); operationsService = TestBed.inject(SubmissionJsonPatchOperationsService); + formService = TestBed.inject(FormService); + uploadService = TestBed.inject(SectionUploadService); comp.submissionId = submissionId; comp.collectionId = collectionId; @@ -146,6 +156,7 @@ fdescribe('SubmissionSectionUploadFileEditComponent test suite', () => { comp.fileIndex = fileIndex; comp.fileId = fileId; comp.configMetadataForm = configMetadataForm; + comp.formMetadata = formMetadataMock; }); afterEach(() => { @@ -221,6 +232,76 @@ fdescribe('SubmissionSectionUploadFileEditComponent test suite', () => { expect(compAsAny.retrieveValueFromField(field)).toBe('test'); }); + it('should save Bitstream File data properly when form is valid', fakeAsync(() => { + compAsAny.fileEditComp = TestBed.inject(SubmissionSectionUploadFileEditComponent); + compAsAny.fileEditComp.formRef = {formGroup: null}; + compAsAny.fileData = fileData; + compAsAny.pathCombiner = pathCombiner; + // const event = new Event('click', null); + // spyOn(comp, 'switchMode'); + formService.validateAllFormFields.and.callFake(() => null); + formService.isValid.and.returnValue(of(true)); + formService.getFormData.and.returnValue(of(mockFileFormData)); + + const response = [ + Object.assign(mockSubmissionObject, { + sections: { + upload: { + files: mockUploadFiles + } + } + }) + ]; + operationsService.jsonPatchByResourceID.and.returnValue(of(response)); + + const accessConditionsToSave = [ + { name: 'openaccess' }, + { name: 'lease', endDate: dateToISOFormat('2019-01-16T00:00:00Z') }, + { name: 'embargo', startDate: dateToISOFormat('2019-01-16T00:00:00Z') }, + ]; + comp.saveBitstreamData(); + tick(); + + let path = 'metadata/dc.title'; + expect(operationsBuilder.add).toHaveBeenCalledWith( + pathCombiner.getPath(path), + mockFileFormData.metadata['dc.title'], + true + ); + + path = 'metadata/dc.description'; + expect(operationsBuilder.add).toHaveBeenCalledWith( + pathCombiner.getPath(path), + mockFileFormData.metadata['dc.description'], + true + ); + + path = 'accessConditions'; + expect(operationsBuilder.add).toHaveBeenCalledWith( + pathCombiner.getPath(path), + accessConditionsToSave, + true + ); + + // expect(comp.switchMode).toHaveBeenCalled(); + expect(uploadService.updateFileData).toHaveBeenCalledWith(submissionId, sectionId, mockUploadFiles[0].uuid, mockUploadFiles[0]); + + })); + + it('should not save Bitstream File data properly when form is not valid', fakeAsync(() => { + compAsAny.fileEditComp = TestBed.inject(SubmissionSectionUploadFileEditComponent); + compAsAny.fileEditComp.formRef = {formGroup: null}; + compAsAny.pathCombiner = pathCombiner; + // const event = new Event('click', null); + // spyOn(comp, 'switchMode'); + formService.validateAllFormFields.and.callFake(() => null); + formService.isValid.and.returnValue(of(false)); + + // expect(comp.switchMode).not.toHaveBeenCalled(); + expect(uploadService.updateFileData).not.toHaveBeenCalled(); + + })); + }); }); diff --git a/src/app/submission/sections/upload/file/edit/section-upload-file-edit.component.ts b/src/app/submission/sections/upload/file/edit/section-upload-file-edit.component.ts index eb8fbf95d0..32b82bec45 100644 --- a/src/app/submission/sections/upload/file/edit/section-upload-file-edit.component.ts +++ b/src/app/submission/sections/upload/file/edit/section-upload-file-edit.component.ts @@ -1,4 +1,4 @@ -import { ChangeDetectorRef, Component, Input, OnInit, ViewChild } from '@angular/core'; +import { ChangeDetectorRef, Component, OnInit, ViewChild } from '@angular/core'; import { FormControl } from '@angular/forms'; import { @@ -60,6 +60,97 @@ import { Subscription } from 'rxjs'; }) export class SubmissionSectionUploadFileEditComponent implements OnInit { + /** + * The FormComponent reference + */ + @ViewChild('formRef') public formRef: FormComponent; + + /** + * The list of available access condition + * @type {Array} + */ + public availableAccessConditionOptions: any[]; + + /** + * The submission id + * @type {string} + */ + public collectionId: string; + + /** + * Define if collection access conditions policy type : + * POLICY_DEFAULT_NO_LIST : is not possible to define additional access group/s for the single file + * POLICY_DEFAULT_WITH_LIST : is possible to define additional access group/s for the single file + * @type {number} + */ + public collectionPolicyType: number; + + /** + * The configuration for the bitstream's metadata form + * @type {SubmissionFormsModel} + */ + public configMetadataForm: SubmissionFormsModel; + + /** + * The bitstream's metadata data + * @type {WorkspaceitemSectionUploadFileObject} + */ + public fileData: WorkspaceitemSectionUploadFileObject; + + /** + * The bitstream id + * @type {string} + */ + public fileId: string; + + /** + * The bitstream array key + * @type {string} + */ + public fileIndex: string; + + /** + * The form id + * @type {string} + */ + public formId: string; + + /** + * The section id + * @type {string} + */ + public sectionId: string; + + /** + * The submission id + * @type {string} + */ + public submissionId: string; + + /** + * The list of all available metadata + */ + formMetadata: string[] = []; + + /** + * The form model + * @type {DynamicFormControlModel[]} + */ + formModel: DynamicFormControlModel[]; + + /** + * When `true` form controls are deactivated + */ + isSaving = false; + + /** + * The [JsonPatchOperationPathCombiner] object + * @type {JsonPatchOperationPathCombiner} + */ + protected pathCombiner: JsonPatchOperationPathCombiner; + + protected subscriptions: Subscription[] = []; + /** * Initialize instance variables * @@ -84,94 +175,6 @@ export class SubmissionSectionUploadFileEditComponent implements OnInit { ) { } - /** - * The list of available access condition - * @type {Array} - */ - @Input() availableAccessConditionOptions: any[]; - - /** - * The submission id - * @type {string} - */ - @Input() collectionId: string; - - /** - * Define if collection access conditions policy type : - * POLICY_DEFAULT_NO_LIST : is not possible to define additional access group/s for the single file - * POLICY_DEFAULT_WITH_LIST : is possible to define additional access group/s for the single file - * @type {number} - */ - @Input() collectionPolicyType: number; - - /** - * The configuration for the bitstream's metadata form - * @type {SubmissionFormsModel} - */ - @Input() configMetadataForm: SubmissionFormsModel; - - /** - * The bitstream's metadata data - * @type {WorkspaceitemSectionUploadFileObject} - */ - @Input() fileData: WorkspaceitemSectionUploadFileObject; - - /** - * The bitstream id - * @type {string} - */ - @Input() fileId: string; - - /** - * The bitstream array key - * @type {string} - */ - @Input() fileIndex: string; - - /** - * The form id - * @type {string} - */ - @Input() formId: string; - - /** - * The section id - * @type {string} - */ - @Input() sectionId: string; - - /** - * The submission id - * @type {string} - */ - @Input() submissionId: string; - - /** - * The list of all available metadata - */ - @Input() formMetadata: string[] = []; - - /** - * The [JsonPatchOperationPathCombiner] object - * @type {JsonPatchOperationPathCombiner} - */ - @Input() pathCombiner: JsonPatchOperationPathCombiner; - - /** - * The FormComponent reference - */ - @ViewChild('formRef') public formRef: FormComponent; - - /** - * The form model - * @type {DynamicFormControlModel[]} - */ - formModel: DynamicFormControlModel[]; - - isSaving = false; - - protected subscriptions: Subscription[] = []; - /** * Initialize form model values * @@ -379,7 +382,7 @@ export class SubmissionSectionUploadFileEditComponent implements OnInit { /** * Save bitstream metadata */ - protected saveBitstreamData() { + saveBitstreamData() { // validate form this.formService.validateAllFormFields(this.formRef.formGroup); const saveBitstreamDataSubscription = this.formService.isValid(this.formId).pipe( diff --git a/src/app/submission/sections/upload/file/section-upload-file.component.spec.ts b/src/app/submission/sections/upload/file/section-upload-file.component.spec.ts index a8ab34d866..2fd7be96d0 100644 --- a/src/app/submission/sections/upload/file/section-upload-file.component.spec.ts +++ b/src/app/submission/sections/upload/file/section-upload-file.component.spec.ts @@ -1,5 +1,5 @@ import { ChangeDetectorRef, Component, NO_ERRORS_SCHEMA } from '@angular/core'; -import { ComponentFixture, fakeAsync, inject, TestBed, tick, waitForAsync } from '@angular/core/testing'; +import { ComponentFixture, inject, TestBed, waitForAsync } from '@angular/core/testing'; import { BrowserModule, By } from '@angular/platform-browser'; import { CommonModule } from '@angular/common'; @@ -17,10 +17,8 @@ import { SubmissionJsonPatchOperationsService } from '../../../../core/submissio import { SubmissionSectionUploadFileComponent } from './section-upload-file.component'; import { SubmissionServiceStub } from '../../../../shared/testing/submission-service.stub'; import { - mockFileFormData, mockSubmissionCollectionId, mockSubmissionId, - mockSubmissionObject, mockUploadConfigResponse, mockUploadFiles } from '../../../../shared/mocks/submission.mock'; @@ -32,10 +30,8 @@ import { FileSizePipe } from '../../../../shared/utils/file-size-pipe'; import { POLICY_DEFAULT_WITH_LIST } from '../section-upload.component'; import { JsonPatchOperationPathCombiner } from '../../../../core/json-patch/builder/json-patch-operation-path-combiner'; import { getMockSectionUploadService } from '../../../../shared/mocks/section-upload.service.mock'; -import { FormFieldMetadataValueObject } from '../../../../shared/form/builder/models/form-field-metadata-value.model'; import { SubmissionSectionUploadFileEditComponent } from './edit/section-upload-file-edit.component'; import { FormBuilderService } from '../../../../shared/form/builder/form-builder.service'; -import { dateToISOFormat } from '../../../../shared/date.util'; const configMetadataFormMock = { rows: [{ From 6752acbf128e611a9593679ca64aa52b5fe1d88f Mon Sep 17 00:00:00 2001 From: Davide Negretti Date: Wed, 24 Nov 2021 20:00:21 +0100 Subject: [PATCH 08/11] [CST-4884] Test --- ...section-upload-file-edit.component.spec.ts | 19 ++++++++----------- .../section-upload-file.component.spec.ts | 2 +- 2 files changed, 9 insertions(+), 12 deletions(-) diff --git a/src/app/submission/sections/upload/file/edit/section-upload-file-edit.component.spec.ts b/src/app/submission/sections/upload/file/edit/section-upload-file-edit.component.spec.ts index 866277108f..aa03d37eb2 100644 --- a/src/app/submission/sections/upload/file/edit/section-upload-file-edit.component.spec.ts +++ b/src/app/submission/sections/upload/file/edit/section-upload-file-edit.component.spec.ts @@ -49,7 +49,7 @@ const jsonPatchOpBuilder: any = jasmine.createSpyObj('jsonPatchOpBuilder', { const formMetadataMock = ['dc.title', 'dc.description']; -fdescribe('SubmissionSectionUploadFileEditComponent test suite', () => { +describe('SubmissionSectionUploadFileEditComponent test suite', () => { let comp: SubmissionSectionUploadFileEditComponent; let compAsAny: any; @@ -98,6 +98,7 @@ fdescribe('SubmissionSectionUploadFileEditComponent test suite', () => { SubmissionSectionUploadFileEditComponent, NgbModal, NgbActiveModal, + FormComponent, ], schemas: [NO_ERRORS_SCHEMA] }).compileComponents().then(); @@ -157,6 +158,8 @@ fdescribe('SubmissionSectionUploadFileEditComponent test suite', () => { comp.fileId = fileId; comp.configMetadataForm = configMetadataForm; comp.formMetadata = formMetadataMock; + + formService.isValid.and.returnValue(of(true)); }); afterEach(() => { @@ -233,12 +236,9 @@ fdescribe('SubmissionSectionUploadFileEditComponent test suite', () => { }); it('should save Bitstream File data properly when form is valid', fakeAsync(() => { - compAsAny.fileEditComp = TestBed.inject(SubmissionSectionUploadFileEditComponent); - compAsAny.fileEditComp.formRef = {formGroup: null}; + compAsAny.formRef = {formGroup: null}; compAsAny.fileData = fileData; compAsAny.pathCombiner = pathCombiner; - // const event = new Event('click', null); - // spyOn(comp, 'switchMode'); formService.validateAllFormFields.and.callFake(() => null); formService.isValid.and.returnValue(of(true)); formService.getFormData.and.returnValue(of(mockFileFormData)); @@ -283,21 +283,18 @@ fdescribe('SubmissionSectionUploadFileEditComponent test suite', () => { true ); - // expect(comp.switchMode).toHaveBeenCalled(); expect(uploadService.updateFileData).toHaveBeenCalledWith(submissionId, sectionId, mockUploadFiles[0].uuid, mockUploadFiles[0]); })); it('should not save Bitstream File data properly when form is not valid', fakeAsync(() => { - compAsAny.fileEditComp = TestBed.inject(SubmissionSectionUploadFileEditComponent); - compAsAny.fileEditComp.formRef = {formGroup: null}; + compAsAny.formRef = {formGroup: null}; compAsAny.pathCombiner = pathCombiner; - // const event = new Event('click', null); - // spyOn(comp, 'switchMode'); formService.validateAllFormFields.and.callFake(() => null); formService.isValid.and.returnValue(of(false)); + comp.saveBitstreamData(); + tick(); - // expect(comp.switchMode).not.toHaveBeenCalled(); expect(uploadService.updateFileData).not.toHaveBeenCalled(); })); diff --git a/src/app/submission/sections/upload/file/section-upload-file.component.spec.ts b/src/app/submission/sections/upload/file/section-upload-file.component.spec.ts index 2fd7be96d0..50b245e481 100644 --- a/src/app/submission/sections/upload/file/section-upload-file.component.spec.ts +++ b/src/app/submission/sections/upload/file/section-upload-file.component.spec.ts @@ -44,7 +44,7 @@ const configMetadataFormMock = { }] }; -fdescribe('SubmissionSectionUploadFileComponent test suite', () => { +describe('SubmissionSectionUploadFileComponent test suite', () => { let comp: SubmissionSectionUploadFileComponent; let compAsAny: any; From 27bce0e5bb550c1d02d7023eb7ffaf72243ca7cf Mon Sep 17 00:00:00 2001 From: Davide Negretti Date: Wed, 24 Nov 2021 20:17:16 +0100 Subject: [PATCH 09/11] [CST-4879] After changing options in access-conditions.xml, "grant access" fields are displayed incorrectly --- .../upload/file/edit/section-upload-file-edit.component.ts | 6 ++++-- .../sections/upload/file/section-upload-file.component.ts | 4 ---- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/src/app/submission/sections/upload/file/edit/section-upload-file-edit.component.ts b/src/app/submission/sections/upload/file/edit/section-upload-file-edit.component.ts index 32b82bec45..fda86dd629 100644 --- a/src/app/submission/sections/upload/file/edit/section-upload-file-edit.component.ts +++ b/src/app/submission/sections/upload/file/edit/section-upload-file-edit.component.ts @@ -235,7 +235,7 @@ export class SubmissionSectionUploadFileEditComponent implements OnInit { public setOptions(model: DynamicFormControlModel, control: FormControl) { let accessCondition: AccessConditionOption = null; this.availableAccessConditionOptions.filter((element) => element.name === control.value) - .forEach((element) => accessCondition = element); + .forEach((element) => accessCondition = element ); if (isNotEmpty(accessCondition)) { const showGroups: boolean = accessCondition.hasStartDate === true || accessCondition.hasEndDate === true; @@ -364,7 +364,9 @@ export class SubmissionSectionUploadFileEditComponent implements OnInit { const startDate = new DynamicDatePickerModel(startDateConfig, BITSTREAM_FORM_ACCESS_CONDITION_START_DATE_LAYOUT); const endDate = new DynamicDatePickerModel(endDateConfig, BITSTREAM_FORM_ACCESS_CONDITION_END_DATE_LAYOUT); const accessConditionGroupConfig = Object.assign({}, BITSTREAM_ACCESS_CONDITION_GROUP_CONFIG); - accessConditionGroupConfig.group = [type, startDate, endDate]; + accessConditionGroupConfig.group = [type]; + if (hasStart.length > 0) { accessConditionGroupConfig.group.push(startDate); } + if (hasEnd.length > 0) { accessConditionGroupConfig.group.push(endDate); } return [new DynamicFormGroupModel(accessConditionGroupConfig, BITSTREAM_ACCESS_CONDITION_GROUP_LAYOUT)]; }; diff --git a/src/app/submission/sections/upload/file/section-upload-file.component.ts b/src/app/submission/sections/upload/file/section-upload-file.component.ts index e152d2f651..0841e1ca3a 100644 --- a/src/app/submission/sections/upload/file/section-upload-file.component.ts +++ b/src/app/submission/sections/upload/file/section-upload-file.component.ts @@ -247,10 +247,6 @@ export class SubmissionSectionUploadFileComponent implements OnChanges, OnInit { activeModal.componentInstance.pathCombiner = this.pathCombiner; activeModal.componentInstance.submissionId = this.submissionId; - /*activeModal.componentInstance.saveBitstreamDataEvent.subscribe((res) => { - console.log(JSON.stringify(res)); - });*/ - } ngOnDestroy(): void { From 7218c450e6993a4b50f6e169a45e41532affe701 Mon Sep 17 00:00:00 2001 From: Davide Negretti Date: Wed, 24 Nov 2021 23:39:59 +0100 Subject: [PATCH 10/11] [CST-4884] Code cleanup and test improvement --- .../file/section-upload-file.component.html | 2 +- .../file/section-upload-file.component.scss | 6 -- .../section-upload-file.component.spec.ts | 84 ++----------------- .../file/section-upload-file.component.ts | 8 -- 4 files changed, 10 insertions(+), 90 deletions(-) diff --git a/src/app/submission/sections/upload/file/section-upload-file.component.html b/src/app/submission/sections/upload/file/section-upload-file.component.html index 8749c8dcf2..1bfc52529b 100644 --- a/src/app/submission/sections/upload/file/section-upload-file.component.html +++ b/src/app/submission/sections/upload/file/section-upload-file.component.html @@ -8,7 +8,7 @@

{{fileName}} ({{fileData?.sizeBytes | dsFileSize}})

-
+
diff --git a/src/app/submission/sections/upload/file/section-upload-file.component.scss b/src/app/submission/sections/upload/file/section-upload-file.component.scss index 256775eb66..e69de29bb2 100644 --- a/src/app/submission/sections/upload/file/section-upload-file.component.scss +++ b/src/app/submission/sections/upload/file/section-upload-file.component.scss @@ -1,6 +0,0 @@ -.sticky-buttons { - position: sticky; - top: calc(var(--bs-dropdown-item-padding-x) * 3); - z-index: var(--ds-submission-footer-z-index); - background-color: rgba(255, 255, 255, .97); -} diff --git a/src/app/submission/sections/upload/file/section-upload-file.component.spec.ts b/src/app/submission/sections/upload/file/section-upload-file.component.spec.ts index 50b245e481..4fea8d3f25 100644 --- a/src/app/submission/sections/upload/file/section-upload-file.component.spec.ts +++ b/src/app/submission/sections/upload/file/section-upload-file.component.spec.ts @@ -217,86 +217,20 @@ describe('SubmissionSectionUploadFileComponent test suite', () => { pathCombiner.subRootElement); }); - /*it('should save Bitstream File data properly when form is valid', fakeAsync(() => { - compAsAny.fileEditComp = TestBed.inject(SubmissionSectionUploadFileEditComponent); - compAsAny.fileEditComp.formRef = {formGroup: null}; - compAsAny.fileData = fileData; - compAsAny.pathCombiner = pathCombiner; - const event = new Event('click', null); - spyOn(comp, 'switchMode'); - formService.validateAllFormFields.and.callFake(() => null); - formService.isValid.and.returnValue(observableOf(true)); - formService.getFormData.and.returnValue(observableOf(mockFileFormData)); + it('should open edit modal when edit button is clicked', () => { + spyOn(compAsAny, 'editBitstreamData').and.callThrough(); + comp.fileData = fileData; - const response = [ - Object.assign(mockSubmissionObject, { - sections: { - upload: { - files: mockUploadFiles - } - } - }) - ]; - operationsService.jsonPatchByResourceID.and.returnValue(observableOf(response)); + fixture.detectChanges(); - const accessConditionsToSave = [ - { name: 'openaccess' }, - { name: 'lease', endDate: dateToISOFormat('2019-01-16T00:00:00Z') }, - { name: 'embargo', startDate: dateToISOFormat('2019-01-16T00:00:00Z') }, - ]; - comp.saveBitstreamData(event); - tick(); + const modalBtn = fixture.debugElement.query(By.css('.fa-edit ')); - let path = 'metadata/dc.title'; - expect(operationsBuilder.add).toHaveBeenCalledWith( - pathCombiner.getPath(path), - mockFileFormData.metadata['dc.title'], - true - ); + modalBtn.nativeElement.click(); + fixture.detectChanges(); - path = 'metadata/dc.description'; - expect(operationsBuilder.add).toHaveBeenCalledWith( - pathCombiner.getPath(path), - mockFileFormData.metadata['dc.description'], - true - ); - - path = 'accessConditions'; - expect(operationsBuilder.add).toHaveBeenCalledWith( - pathCombiner.getPath(path), - accessConditionsToSave, - true - ); - - expect(comp.switchMode).toHaveBeenCalled(); - expect(uploadService.updateFileData).toHaveBeenCalledWith(submissionId, sectionId, mockUploadFiles[0].uuid, mockUploadFiles[0]); - - }));*/ - - /*it('should not save Bitstream File data properly when form is not valid', fakeAsync(() => { - compAsAny.fileEditComp = TestBed.inject(SubmissionSectionUploadFileEditComponent); - compAsAny.fileEditComp.formRef = {formGroup: null}; - compAsAny.pathCombiner = pathCombiner; - const event = new Event('click', null); - spyOn(comp, 'switchMode'); - formService.validateAllFormFields.and.callFake(() => null); - formService.isValid.and.returnValue(observableOf(false)); - - expect(comp.switchMode).not.toHaveBeenCalled(); - expect(uploadService.updateFileData).not.toHaveBeenCalled(); - - }));*/ - - it('should switch read mode', () => { - comp.readMode = false; - - comp.switchMode(); - expect(comp.readMode).toBeTruthy(); - - comp.switchMode(); - - expect(comp.readMode).toBeFalsy(); + expect(compAsAny.editBitstreamData).toHaveBeenCalled(); }); + }); }); diff --git a/src/app/submission/sections/upload/file/section-upload-file.component.ts b/src/app/submission/sections/upload/file/section-upload-file.component.ts index 0841e1ca3a..53358d48e2 100644 --- a/src/app/submission/sections/upload/file/section-upload-file.component.ts +++ b/src/app/submission/sections/upload/file/section-upload-file.component.ts @@ -217,14 +217,6 @@ export class SubmissionSectionUploadFileComponent implements OnChanges, OnInit { }); } - /** - * Switch from edit form to metadata view - */ - public switchMode() { - this.readMode = !this.readMode; - this.cdr.detectChanges(); - } - editBitstreamData() { const options: NgbModalOptions = { From d246965cfb20c60b78b9d3b9ec5b0117875e833a Mon Sep 17 00:00:00 2001 From: Davide Negretti Date: Tue, 21 Dec 2021 11:17:12 +0100 Subject: [PATCH 11/11] [CST-4879] TypeError fixed --- .../file/edit/section-upload-file-edit.component.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/app/submission/sections/upload/file/edit/section-upload-file-edit.component.ts b/src/app/submission/sections/upload/file/edit/section-upload-file-edit.component.ts index fda86dd629..3a43e718a0 100644 --- a/src/app/submission/sections/upload/file/edit/section-upload-file-edit.component.ts +++ b/src/app/submission/sections/upload/file/edit/section-upload-file-edit.component.ts @@ -243,12 +243,12 @@ export class SubmissionSectionUploadFileEditComponent implements OnInit { const endDateControl: FormControl = control.parent.get('endDate') as FormControl; // Clear previous state - startDateControl.markAsUntouched(); - endDateControl.markAsUntouched(); + startDateControl?.markAsUntouched(); + endDateControl?.markAsUntouched(); - startDateControl.setValue(null); + startDateControl?.setValue(null); control.parent.markAsDirty(); - endDateControl.setValue(null); + endDateControl?.setValue(null); if (showGroups) { if (accessCondition.hasStartDate) {