mirror of
https://github.com/DSpace/dspace-angular.git
synced 2025-10-18 07:23:03 +00:00
Merge remote-tracking branch 'origin/main' into #1171
This commit is contained in:
@@ -4,7 +4,8 @@ import { TranslateLoader, TranslateModule } from '@ngx-translate/core';
|
||||
import {
|
||||
DYNAMIC_FORM_CONTROL_TYPE_ARRAY,
|
||||
DYNAMIC_FORM_CONTROL_TYPE_GROUP,
|
||||
DynamicFormControlEvent
|
||||
DynamicFormControlEvent,
|
||||
DynamicInputModel
|
||||
} from '@ng-dynamic-forms/core';
|
||||
|
||||
import { FormBuilderService } from '../../../shared/form/builder/form-builder.service';
|
||||
@@ -28,6 +29,7 @@ import {
|
||||
} from '../../../shared/mocks/form-models.mock';
|
||||
import { FormFieldMetadataValueObject } from '../../../shared/form/builder/models/form-field-metadata-value.model';
|
||||
import { VocabularyEntry } from '../../../core/submission/vocabularies/models/vocabulary-entry.model';
|
||||
import { DynamicRowArrayModel } from '../../../shared/form/builder/ds-dynamic-form-ui/models/ds-dynamic-row-array-model';
|
||||
|
||||
describe('SectionFormOperationsService test suite', () => {
|
||||
let formBuilderService: any;
|
||||
@@ -83,6 +85,11 @@ describe('SectionFormOperationsService test suite', () => {
|
||||
formBuilderService = TestBed.inject(FormBuilderService);
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
jsonPatchOpBuilder.add.calls.reset();
|
||||
jsonPatchOpBuilder.remove.calls.reset();
|
||||
});
|
||||
|
||||
describe('dispatchOperationsFromEvent', () => {
|
||||
it('should call dispatchOperationsFromRemoveEvent on remove event', () => {
|
||||
const previousValue = new FormFieldPreviousValueObject(['path', 'test'], 'value');
|
||||
@@ -567,7 +574,7 @@ describe('SectionFormOperationsService test suite', () => {
|
||||
});
|
||||
|
||||
it('should dispatch a json-path remove operation when has a stored value', () => {
|
||||
const previousValue = new FormFieldPreviousValueObject(['path', 'test'], 'value');
|
||||
let previousValue = new FormFieldPreviousValueObject(['path', 'test'], 'value');
|
||||
const event = Object.assign({}, dynamicFormControlChangeEvent, {
|
||||
model: {
|
||||
parent: mockRowGroupModel
|
||||
@@ -590,6 +597,7 @@ describe('SectionFormOperationsService test suite', () => {
|
||||
|
||||
spyIndex.and.returnValue(1);
|
||||
spyPath.and.returnValue('path/1');
|
||||
previousValue = new FormFieldPreviousValueObject(['path', 'test'], 'value');
|
||||
serviceAsAny.dispatchOperationsFromChangeEvent(pathCombiner, event, previousValue, true);
|
||||
|
||||
expect(jsonPatchOpBuilder.remove).toHaveBeenCalledWith(pathCombiner.getPath('path/1'));
|
||||
@@ -620,6 +628,32 @@ describe('SectionFormOperationsService test suite', () => {
|
||||
new FormFieldMetadataValueObject('test'));
|
||||
});
|
||||
|
||||
it('should dispatch a json-path add operation when has a stored value but previous value is empty', () => {
|
||||
const previousValue = new FormFieldPreviousValueObject(['path', 'test'], null);
|
||||
const event = Object.assign({}, dynamicFormControlChangeEvent, {
|
||||
model: {
|
||||
parent: mockRowGroupModel
|
||||
}
|
||||
});
|
||||
spyOn(service, 'getFieldPathFromEvent').and.returnValue('path/0');
|
||||
spyOn(service, 'getFieldPathSegmentedFromChangeEvent').and.returnValue('path');
|
||||
spyOn(service, 'getFieldValueFromChangeEvent').and.returnValue(new FormFieldMetadataValueObject('test'));
|
||||
spyOn(service, 'getArrayIndexFromEvent').and.returnValue(0);
|
||||
spyOn(serviceAsAny, 'getValueMap');
|
||||
spyOn(serviceAsAny, 'dispatchOperationsFromMap');
|
||||
formBuilderService.isQualdropGroup.and.returnValue(false);
|
||||
formBuilderService.isRelationGroup.and.returnValue(false);
|
||||
formBuilderService.hasArrayGroupValue.and.returnValue(false);
|
||||
spyOn(previousValue, 'isPathEqual').and.returnValue(false);
|
||||
|
||||
serviceAsAny.dispatchOperationsFromChangeEvent(pathCombiner, event, previousValue, true);
|
||||
|
||||
expect(jsonPatchOpBuilder.add).toHaveBeenCalledWith(
|
||||
pathCombiner.getPath('path'),
|
||||
new FormFieldMetadataValueObject('test'),
|
||||
true);
|
||||
});
|
||||
|
||||
it('should dispatch a json-path add operation when has a value and field index is zero or undefined', () => {
|
||||
const previousValue = new FormFieldPreviousValueObject(['path', 'test'], 'value');
|
||||
const event = Object.assign({}, dynamicFormControlChangeEvent, {
|
||||
@@ -760,4 +794,86 @@ describe('SectionFormOperationsService test suite', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('handleArrayGroupPatch', () => {
|
||||
let arrayModel;
|
||||
let previousValue;
|
||||
beforeEach(() => {
|
||||
arrayModel = new DynamicRowArrayModel(
|
||||
{
|
||||
id: 'testFormRowArray',
|
||||
initialCount: 5,
|
||||
notRepeatable: false,
|
||||
relationshipConfig: undefined,
|
||||
submissionId: '1234',
|
||||
isDraggable: true,
|
||||
groupFactory: () => {
|
||||
return [
|
||||
new DynamicInputModel({ id: 'testFormRowArrayGroupInput' })
|
||||
];
|
||||
},
|
||||
required: false,
|
||||
metadataKey: 'dc.contributor.author',
|
||||
metadataFields: ['dc.contributor.author'],
|
||||
hasSelectableMetadata: true
|
||||
}
|
||||
);
|
||||
spyOn(serviceAsAny, 'getFieldPathSegmentedFromChangeEvent').and.returnValue('path');
|
||||
previousValue = new FormFieldPreviousValueObject(['path'], null);
|
||||
});
|
||||
|
||||
it('should not dispatch a json-path operation when a array value is empty', () => {
|
||||
formBuilderService.getValueFromModel.and.returnValue({});
|
||||
spyOn(previousValue, 'isPathEqual').and.returnValue(false);
|
||||
|
||||
serviceAsAny.handleArrayGroupPatch(
|
||||
pathCombiner,
|
||||
dynamicFormControlChangeEvent,
|
||||
arrayModel,
|
||||
previousValue
|
||||
);
|
||||
|
||||
expect(jsonPatchOpBuilder.add).not.toHaveBeenCalled();
|
||||
expect(jsonPatchOpBuilder.remove).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should dispatch a json-path add operation when a array value is not empty', () => {
|
||||
const pathValue = [
|
||||
new FormFieldMetadataValueObject('test'),
|
||||
new FormFieldMetadataValueObject('test two')
|
||||
];
|
||||
formBuilderService.getValueFromModel.and.returnValue({
|
||||
path:pathValue
|
||||
});
|
||||
spyOn(previousValue, 'isPathEqual').and.returnValue(false);
|
||||
|
||||
serviceAsAny.handleArrayGroupPatch(
|
||||
pathCombiner,
|
||||
dynamicFormControlChangeEvent,
|
||||
arrayModel,
|
||||
previousValue
|
||||
);
|
||||
|
||||
expect(jsonPatchOpBuilder.add).toHaveBeenCalledWith(
|
||||
pathCombiner.getPath('path'),
|
||||
pathValue,
|
||||
false
|
||||
);
|
||||
expect(jsonPatchOpBuilder.remove).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should dispatch a json-path remove operation when a array value is empty and has previous value', () => {
|
||||
formBuilderService.getValueFromModel.and.returnValue({});
|
||||
spyOn(previousValue, 'isPathEqual').and.returnValue(true);
|
||||
|
||||
serviceAsAny.handleArrayGroupPatch(
|
||||
pathCombiner,
|
||||
dynamicFormControlChangeEvent,
|
||||
arrayModel,
|
||||
previousValue
|
||||
);
|
||||
|
||||
expect(jsonPatchOpBuilder.add).not.toHaveBeenCalled();
|
||||
expect(jsonPatchOpBuilder.remove).toHaveBeenCalledWith(pathCombiner.getPath('path'));
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@@ -6,7 +6,8 @@ import {
|
||||
DYNAMIC_FORM_CONTROL_TYPE_GROUP,
|
||||
DynamicFormArrayGroupModel,
|
||||
DynamicFormControlEvent,
|
||||
DynamicFormControlModel, isDynamicFormControlEvent
|
||||
DynamicFormControlModel,
|
||||
isDynamicFormControlEvent
|
||||
} from '@ng-dynamic-forms/core';
|
||||
|
||||
import { hasValue, isNotEmpty, isNotNull, isNotUndefined, isNull, isUndefined } from '../../../shared/empty.util';
|
||||
@@ -297,17 +298,14 @@ export class SectionFormOperationsService {
|
||||
event: DynamicFormControlEvent,
|
||||
previousValue: FormFieldPreviousValueObject): void {
|
||||
|
||||
if (event.context && event.context instanceof DynamicFormArrayGroupModel) {
|
||||
// Model is a DynamicRowArrayModel
|
||||
this.handleArrayGroupPatch(pathCombiner, event, (event as any).context.context);
|
||||
return;
|
||||
}
|
||||
|
||||
const path = this.getFieldPathFromEvent(event);
|
||||
const value = this.getFieldValueFromChangeEvent(event);
|
||||
console.log(value);
|
||||
if (this.formBuilder.isQualdropGroup(event.model as DynamicFormControlModel)) {
|
||||
this.dispatchOperationsFromMap(this.getQualdropValueMap(event), pathCombiner, event, previousValue);
|
||||
} else if (event.context && event.context instanceof DynamicFormArrayGroupModel) {
|
||||
// Model is a DynamicRowArrayModel
|
||||
this.handleArrayGroupPatch(pathCombiner, event, (event as any).context.context, previousValue);
|
||||
} else if ((isNotEmpty(value) && typeof value === 'string') || (isNotEmpty(value) && value instanceof FormFieldMetadataValueObject && value.hasValue())) {
|
||||
this.operationsBuilder.remove(pathCombiner.getPath(path));
|
||||
}
|
||||
@@ -368,7 +366,7 @@ export class SectionFormOperationsService {
|
||||
|
||||
if (event.context && event.context instanceof DynamicFormArrayGroupModel) {
|
||||
// Model is a DynamicRowArrayModel
|
||||
this.handleArrayGroupPatch(pathCombiner, event, (event as any).context.context);
|
||||
this.handleArrayGroupPatch(pathCombiner, event, (event as any).context.context, previousValue);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -388,7 +386,7 @@ export class SectionFormOperationsService {
|
||||
this.operationsBuilder.add(
|
||||
pathCombiner.getPath(segmentedPath),
|
||||
value, true);
|
||||
} else if (previousValue.isPathEqual(this.formBuilder.getPath(event.model)) || hasStoredValue) {
|
||||
} else if (previousValue.isPathEqual(this.formBuilder.getPath(event.model)) || (hasStoredValue && isNotEmpty(previousValue.value)) ) {
|
||||
// Here model has a previous value changed or stored in the server
|
||||
if (hasValue(event.$event) && hasValue(event.$event.previousIndex)) {
|
||||
if (event.$event.previousIndex < 0) {
|
||||
@@ -421,7 +419,7 @@ export class SectionFormOperationsService {
|
||||
previousValue.delete();
|
||||
} else if (value.hasValue()) {
|
||||
// Here model has no previous value but a new one
|
||||
if (isUndefined(this.getArrayIndexFromEvent(event)) || this.getArrayIndexFromEvent(event) === 0) {
|
||||
if (isUndefined(this.getArrayIndexFromEvent(event)) || this.getArrayIndexFromEvent(event) === 0) {
|
||||
// Model is single field or is part of an array model but is the first item,
|
||||
// so dispatch an add operation that initialize the values of a specific metadata
|
||||
this.operationsBuilder.add(
|
||||
@@ -498,23 +496,37 @@ export class SectionFormOperationsService {
|
||||
event: DynamicFormControlEvent,
|
||||
previousValue: FormFieldPreviousValueObject) {
|
||||
|
||||
return this.handleArrayGroupPatch(pathCombiner, event.$event, (event as any).$event.arrayModel);
|
||||
return this.handleArrayGroupPatch(pathCombiner, event.$event, (event as any).$event.arrayModel, previousValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* Specific patch handler for a DynamicRowArrayModel.
|
||||
* Configure a Patch ADD with the current array value.
|
||||
* @param pathCombiner
|
||||
* the [[JsonPatchOperationPathCombiner]] object for the specified operation
|
||||
* @param event
|
||||
* the [[DynamicFormControlEvent]] for the specified operation
|
||||
* @param model
|
||||
* the [[DynamicRowArrayModel]] model
|
||||
* @param previousValue
|
||||
* the [[FormFieldPreviousValueObject]] for the specified operation
|
||||
*/
|
||||
private handleArrayGroupPatch(pathCombiner: JsonPatchOperationPathCombiner,
|
||||
event,
|
||||
model: DynamicRowArrayModel) {
|
||||
model: DynamicRowArrayModel,
|
||||
previousValue: FormFieldPreviousValueObject) {
|
||||
|
||||
const arrayValue = this.formBuilder.getValueFromModel([model]);
|
||||
const segmentedPath2 = this.getFieldPathSegmentedFromChangeEvent(event);
|
||||
this.operationsBuilder.add(
|
||||
pathCombiner.getPath(segmentedPath2),
|
||||
arrayValue[segmentedPath2], false);
|
||||
const segmentedPath = this.getFieldPathSegmentedFromChangeEvent(event);
|
||||
if (isNotEmpty(arrayValue)) {
|
||||
this.operationsBuilder.add(
|
||||
pathCombiner.getPath(segmentedPath),
|
||||
arrayValue[segmentedPath],
|
||||
false
|
||||
);
|
||||
} else if (previousValue.isPathEqual(this.formBuilder.getPath(event.model))) {
|
||||
this.operationsBuilder.remove(pathCombiner.getPath(segmentedPath));
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
@@ -0,0 +1,6 @@
|
||||
|
||||
::ng-deep .access-condition-group {
|
||||
position: relative;
|
||||
top: -2.3rem;
|
||||
margin-bottom: -2.3rem;
|
||||
}
|
@@ -18,6 +18,8 @@ import {
|
||||
import { WorkspaceitemSectionUploadFileObject } from '../../../../../core/submission/models/workspaceitem-section-upload-file.model';
|
||||
import { FormBuilderService } from '../../../../../shared/form/builder/form-builder.service';
|
||||
import {
|
||||
BITSTREAM_ACCESS_CONDITION_GROUP_CONFIG,
|
||||
BITSTREAM_ACCESS_CONDITION_GROUP_LAYOUT,
|
||||
BITSTREAM_ACCESS_CONDITIONS_FORM_ARRAY_CONFIG,
|
||||
BITSTREAM_ACCESS_CONDITIONS_FORM_ARRAY_LAYOUT,
|
||||
BITSTREAM_FORM_ACCESS_CONDITION_END_DATE_CONFIG,
|
||||
@@ -43,6 +45,7 @@ import { FormComponent } from '../../../../../shared/form/form.component';
|
||||
*/
|
||||
@Component({
|
||||
selector: 'ds-submission-section-upload-file-edit',
|
||||
styleUrls: ['./section-upload-file-edit.component.scss'],
|
||||
templateUrl: './section-upload-file-edit.component.html',
|
||||
})
|
||||
export class SubmissionSectionUploadFileEditComponent implements OnChanges {
|
||||
@@ -209,8 +212,9 @@ export class SubmissionSectionUploadFileEditComponent implements OnChanges {
|
||||
|
||||
const startDate = new DynamicDatePickerModel(startDateConfig, BITSTREAM_FORM_ACCESS_CONDITION_START_DATE_LAYOUT);
|
||||
const endDate = new DynamicDatePickerModel(endDateConfig, BITSTREAM_FORM_ACCESS_CONDITION_END_DATE_LAYOUT);
|
||||
|
||||
return [type, startDate, endDate];
|
||||
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
|
||||
@@ -233,7 +237,7 @@ export class SubmissionSectionUploadFileEditComponent implements OnChanges {
|
||||
public initModelData(formModel: DynamicFormControlModel[]) {
|
||||
this.fileData.accessConditions.forEach((accessCondition, index) => {
|
||||
Array.of('name', 'startDate', 'endDate')
|
||||
.filter((key) => accessCondition.hasOwnProperty(key))
|
||||
.filter((key) => accessCondition.hasOwnProperty(key) && isNotEmpty(accessCondition[key]))
|
||||
.forEach((key) => {
|
||||
const metadataModel: any = this.formBuilderService.findById(key, formModel, index);
|
||||
if (metadataModel) {
|
||||
|
@@ -15,12 +15,24 @@ export const BITSTREAM_METADATA_FORM_GROUP_CONFIG: DynamicFormGroupModelConfig =
|
||||
export const BITSTREAM_METADATA_FORM_GROUP_LAYOUT: DynamicFormControlLayout = {
|
||||
element: {
|
||||
container: 'form-group',
|
||||
label: 'col-form-label'
|
||||
label: 'col-form-label'
|
||||
},
|
||||
grid: {
|
||||
label: 'col-sm-3'
|
||||
}
|
||||
};
|
||||
export const BITSTREAM_ACCESS_CONDITION_GROUP_CONFIG: DynamicFormGroupModelConfig = {
|
||||
id: 'accessConditionGroup',
|
||||
group: []
|
||||
};
|
||||
|
||||
export const BITSTREAM_ACCESS_CONDITION_GROUP_LAYOUT: DynamicFormControlLayout = {
|
||||
element: {
|
||||
host: 'form-group flex-fill access-condition-group',
|
||||
container: 'pl-1 pr-1',
|
||||
control: 'form-row '
|
||||
}
|
||||
};
|
||||
|
||||
export const BITSTREAM_ACCESS_CONDITIONS_FORM_ARRAY_CONFIG: DynamicFormArrayModelConfig = {
|
||||
id: 'accessConditions',
|
||||
@@ -28,7 +40,7 @@ export const BITSTREAM_ACCESS_CONDITIONS_FORM_ARRAY_CONFIG: DynamicFormArrayMode
|
||||
};
|
||||
export const BITSTREAM_ACCESS_CONDITIONS_FORM_ARRAY_LAYOUT: DynamicFormControlLayout = {
|
||||
grid: {
|
||||
group: 'form-row'
|
||||
group: 'form-row pt-4',
|
||||
}
|
||||
};
|
||||
|
||||
@@ -39,11 +51,8 @@ export const BITSTREAM_FORM_ACCESS_CONDITION_TYPE_CONFIG: DynamicSelectModelConf
|
||||
};
|
||||
export const BITSTREAM_FORM_ACCESS_CONDITION_TYPE_LAYOUT: DynamicFormControlLayout = {
|
||||
element: {
|
||||
container: 'p-0',
|
||||
label: 'col-form-label'
|
||||
},
|
||||
grid: {
|
||||
host: 'col-md-10'
|
||||
host: 'col-12',
|
||||
label: 'col-form-label name-label'
|
||||
}
|
||||
};
|
||||
|
||||
@@ -70,11 +79,10 @@ export const BITSTREAM_FORM_ACCESS_CONDITION_START_DATE_CONFIG: DynamicDatePicke
|
||||
};
|
||||
export const BITSTREAM_FORM_ACCESS_CONDITION_START_DATE_LAYOUT: DynamicFormControlLayout = {
|
||||
element: {
|
||||
container: 'p-0',
|
||||
label: 'col-form-label'
|
||||
},
|
||||
grid: {
|
||||
host: 'col-md-4'
|
||||
host: 'col-6'
|
||||
}
|
||||
};
|
||||
|
||||
@@ -101,10 +109,9 @@ export const BITSTREAM_FORM_ACCESS_CONDITION_END_DATE_CONFIG: DynamicDatePickerM
|
||||
};
|
||||
export const BITSTREAM_FORM_ACCESS_CONDITION_END_DATE_LAYOUT: DynamicFormControlLayout = {
|
||||
element: {
|
||||
container: 'p-0',
|
||||
label: 'col-form-label'
|
||||
},
|
||||
grid: {
|
||||
host: 'col-md-4'
|
||||
host: 'col-6'
|
||||
}
|
||||
};
|
||||
|
@@ -255,6 +255,7 @@ export class SubmissionSectionUploadFileComponent implements OnChanges, OnInit {
|
||||
});
|
||||
const accessConditionsToSave = [];
|
||||
formData.accessConditions
|
||||
.map((accessConditions) => accessConditions.accessConditionGroup)
|
||||
.filter((accessCondition) => isNotEmpty(accessCondition))
|
||||
.forEach((accessCondition) => {
|
||||
let accessConditionOpt;
|
||||
|
Reference in New Issue
Block a user