Skip to content

Commit 25a5bc0

Browse files
[DURACOM-444] add group component
1 parent be381eb commit 25a5bc0

35 files changed

Lines changed: 1258 additions & 27 deletions

src/app/core/json-patch/builder/json-patch-operations-builder.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,6 @@ export class JsonPatchOperationsBuilder {
6464
* the value to update the referenced path
6565
* @param plain
6666
* a boolean representing if the value to be added is a plain text value
67-
* @param securityLevel
6867
* @param language
6968
*/
7069
replace(path: JsonPatchOperationPathObject, value, plain = false, language = null) {

src/app/core/submission/vocabularies/models/vocabulary-entry.model.ts

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -45,12 +45,6 @@ export class VocabularyEntry extends ListableObject {
4545
@autoserialize
4646
otherInformation: OtherInformation;
4747

48-
/**
49-
* A value representing security level value of the metadata
50-
*/
51-
@autoserialize
52-
securityLevel: number;
53-
5448
/**
5549
* A string representing the kind of vocabulary entry
5650
*/

src/app/shared/form/builder/ds-dynamic-form-ui/ds-dynamic-form-control-container.component.spec.ts

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ import { environment } from '../../../../../environments/environment';
6868
import { SubmissionService } from '../../../../submission/submission.service';
6969
import { SubmissionObjectService } from '../../../../submission/submission-object.service';
7070
import { SelectableListService } from '../../../object-list/selectable-list/selectable-list.service';
71+
import { getMockFormBuilderService } from '../../testing/form-builder-service.mock';
7172
import { FormBuilderService } from '../form-builder.service';
7273
import { DsDynamicFormControlContainerComponent } from './ds-dynamic-form-control-container.component';
7374
import { dsDynamicFormControlMapFn } from './ds-dynamic-form-control-map-fn';
@@ -88,6 +89,7 @@ import { DsDynamicOneboxComponent } from './models/onebox/dynamic-onebox.compone
8889
import { DynamicOneboxModel } from './models/onebox/dynamic-onebox.model';
8990
import { DsDynamicRelationGroupComponent } from './models/relation-group/dynamic-relation-group.components';
9091
import { DynamicRelationGroupModel } from './models/relation-group/dynamic-relation-group.model';
92+
import { DsDynamicRelationInlineGroupComponent } from './models/relation-inline-group/dynamic-relation-inline-group.components';
9193
import { DsDynamicScrollableDropdownComponent } from './models/scrollable-dropdown/dynamic-scrollable-dropdown.component';
9294
import { DynamicScrollableDropdownModel } from './models/scrollable-dropdown/dynamic-scrollable-dropdown.model';
9395
import { DsDynamicTagComponent } from './models/tag/dynamic-tag.component';
@@ -173,6 +175,7 @@ describe('DsDynamicFormControlContainerComponent test suite', () => {
173175
submissionId: '1234',
174176
id: 'relationGroup',
175177
formConfiguration: [],
178+
isInlineGroup: false,
176179
mandatoryField: '',
177180
name: 'relationGroup',
178181
relationFields: [],
@@ -182,6 +185,20 @@ describe('DsDynamicFormControlContainerComponent test suite', () => {
182185
metadataFields: [],
183186
hasSelectableMetadata: false,
184187
}),
188+
new DynamicRelationGroupModel({
189+
submissionId: '1234',
190+
id: 'inlineRelationGroup',
191+
formConfiguration: [],
192+
isInlineGroup: true,
193+
mandatoryField: '',
194+
name: 'inlineRelationGroup',
195+
relationFields: [],
196+
scopeUUID: '',
197+
submissionScope: '',
198+
repeatable: false,
199+
metadataFields: [],
200+
hasSelectableMetadata: false,
201+
}),
185202
new DynamicDsDatePickerModel({ id: 'datepicker', repeatable: false }),
186203
new DynamicLookupModel({
187204
id: 'lookup',
@@ -229,7 +246,7 @@ describe('DsDynamicFormControlContainerComponent test suite', () => {
229246
{ provide: Store, useValue: {} },
230247
{ provide: RelationshipDataService, useValue: {} },
231248
{ provide: SelectableListService, useValue: {} },
232-
{ provide: FormBuilderService, useValue: {} },
249+
{ provide: FormBuilderService, useValue: getMockFormBuilderService() },
233250
{ provide: SubmissionService, useValue: {} },
234251
{
235252
provide: SubmissionObjectService,
@@ -375,10 +392,11 @@ describe('DsDynamicFormControlContainerComponent test suite', () => {
375392
expect(testFn(formModel[19])).toEqual(DsDynamicListComponent);
376393
expect(testFn(formModel[20])).toEqual(DsDynamicListComponent);
377394
expect(testFn(formModel[21])).toEqual(DsDynamicRelationGroupComponent);
378-
expect(testFn(formModel[22])).toEqual(DsDatePickerComponent);
379-
expect(testFn(formModel[23])).toEqual(DsDynamicLookupComponent);
395+
expect(testFn(formModel[22])).toEqual(DsDynamicRelationInlineGroupComponent);
396+
expect(testFn(formModel[23])).toEqual(DsDatePickerComponent);
380397
expect(testFn(formModel[24])).toEqual(DsDynamicLookupComponent);
381-
expect(testFn(formModel[25])).toEqual(DsDynamicFormGroupComponent);
398+
expect(testFn(formModel[25])).toEqual(DsDynamicLookupComponent);
399+
expect(testFn(formModel[26])).toEqual(DsDynamicFormGroupComponent);
382400
});
383401

384402
});

src/app/shared/form/builder/ds-dynamic-form-ui/ds-dynamic-form-control-map-fn.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,8 @@ import { DYNAMIC_FORM_CONTROL_TYPE_LOOKUP_NAME } from './models/lookup/dynamic-l
4444
import { DsDynamicOneboxComponent } from './models/onebox/dynamic-onebox.component';
4545
import { DYNAMIC_FORM_CONTROL_TYPE_ONEBOX } from './models/onebox/dynamic-onebox.model';
4646
import { DsDynamicRelationGroupComponent } from './models/relation-group/dynamic-relation-group.components';
47+
import { DynamicRelationGroupModel } from './models/relation-group/dynamic-relation-group.model';
48+
import { DsDynamicRelationInlineGroupComponent } from './models/relation-inline-group/dynamic-relation-inline-group.components';
4749
import { DsDynamicScrollableDropdownComponent } from './models/scrollable-dropdown/dynamic-scrollable-dropdown.component';
4850
import { DYNAMIC_FORM_CONTROL_TYPE_SCROLLABLE_DROPDOWN } from './models/scrollable-dropdown/dynamic-scrollable-dropdown.model';
4951
import { DsDynamicTagComponent } from './models/tag/dynamic-tag.component';
@@ -93,7 +95,7 @@ export function dsDynamicFormControlMapFn(model: DynamicFormControlModel): Type<
9395
return DsDynamicTagComponent;
9496

9597
case DYNAMIC_FORM_CONTROL_TYPE_RELATION_GROUP:
96-
return DsDynamicRelationGroupComponent;
98+
return (model as DynamicRelationGroupModel).isInlineGroup ? DsDynamicRelationInlineGroupComponent : DsDynamicRelationGroupComponent;
9799

98100
case DYNAMIC_FORM_CONTROL_TYPE_DSDATEPICKER:
99101
return DsDatePickerComponent;

src/app/shared/form/builder/ds-dynamic-form-ui/models/ds-dynamic-input.model.ts

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,12 @@ import { LanguageCode } from '@dspace/core/shared/form/models/form-field-languag
22
import { FormFieldMetadataValueObject } from '@dspace/core/shared/form/models/form-field-metadata-value.model';
33
import { RelationshipOptions } from '@dspace/core/shared/relationship-options.model';
44
import { VocabularyOptions } from '@dspace/core/submission/vocabularies/models/vocabulary-options.model';
5-
import { hasValue } from '@dspace/shared/utils/empty.util';
65
import {
6+
hasValue,
7+
isNotUndefined,
8+
} from '@dspace/shared/utils/empty.util';
9+
import {
10+
AUTOCOMPLETE_OFF,
711
DynamicFormControlLayout,
812
DynamicFormControlRelation,
913
DynamicInputModel,
@@ -27,6 +31,7 @@ export interface DsDynamicInputModelConfig extends DynamicInputModelConfig {
2731
metadataValue?: FormFieldMetadataValueObject;
2832
isModelOfInnerForm?: boolean;
2933
hideErrorMessages?: boolean;
34+
isModelOfNotRepeatableGroup?: boolean;
3035
}
3136

3237
export class DsDynamicInputModel extends DynamicInputModel {
@@ -46,10 +51,12 @@ export class DsDynamicInputModel extends DynamicInputModel {
4651
@serializable() metadataValue: FormFieldMetadataValueObject;
4752
@serializable() isModelOfInnerForm: boolean;
4853
@serializable() hideErrorMessages?: boolean;
54+
@serializable() isModelOfNotRepeatableGroup = false;
4955

5056

5157
constructor(config: DsDynamicInputModelConfig, layout?: DynamicFormControlLayout) {
5258
super(config, layout);
59+
this.autoComplete = AUTOCOMPLETE_OFF;
5360
this.repeatable = config.repeatable;
5461
this.metadataFields = config.metadataFields;
5562
this.hint = config.hint;
@@ -61,6 +68,9 @@ export class DsDynamicInputModel extends DynamicInputModel {
6168
this.hasSelectableMetadata = config.hasSelectableMetadata;
6269
this.metadataValue = config.metadataValue;
6370
this.place = config.place;
71+
if (isNotUndefined(config.isModelOfNotRepeatableGroup)) {
72+
this.isModelOfNotRepeatableGroup = config.isModelOfNotRepeatableGroup;
73+
}
6474
this.isModelOfInnerForm = (hasValue(config.isModelOfInnerForm) ? config.isModelOfInnerForm : false);
6575
this.hideErrorMessages = config.hideErrorMessages;
6676

src/app/shared/form/builder/ds-dynamic-form-ui/models/relation-group/dynamic-relation-group.component.spec.ts

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,11 +22,15 @@ import { SubmissionFormsModel } from '@dspace/core/config/models/config-submissi
2222
import { APP_DATA_SERVICES_MAP } from '@dspace/core/data-services-map-type';
2323
import { FormFieldModel } from '@dspace/core/shared/form/models/form-field.model';
2424
import { FormFieldMetadataValueObject } from '@dspace/core/shared/form/models/form-field-metadata-value.model';
25+
import { Vocabulary } from '@dspace/core/submission/vocabularies/models/vocabulary.model';
2526
import { VocabularyService } from '@dspace/core/submission/vocabularies/vocabulary.service';
27+
import { SubmissionServiceStub } from '@dspace/core/testing/submission-service.stub';
2628
import { createTestComponent } from '@dspace/core/testing/utils.test';
2729
import { VocabularyServiceStub } from '@dspace/core/testing/vocabulary-service.stub';
30+
import { createSuccessfulRemoteDataObject$ } from '@dspace/core/utilities/remote-data.utils';
2831
import { XSRFService } from '@dspace/core/xsrf/xsrf.service';
2932
import {
33+
NgbModal,
3034
NgbModule,
3135
NgbTooltip,
3236
} from '@ng-bootstrap/ng-bootstrap';
@@ -74,6 +78,49 @@ const initialState: any = {
7478
'route': {},
7579
},
7680
};
81+
82+
const vocabulary: any = Object.assign(new Vocabulary(), {
83+
id: 'types',
84+
name: 'types',
85+
scrollable: true,
86+
hierarchical: false,
87+
preloadLevel: 1,
88+
entity: null,
89+
externalSource: null,
90+
type: 'vocabulary',
91+
uuid: 'vocabulary-types',
92+
_links: {
93+
self: {
94+
href: 'https://rest.api/rest/api/submission/vocabularies/types',
95+
},
96+
entries: {
97+
href: 'https://rest.api/rest/api/submission/vocabularies/types/entries',
98+
},
99+
},
100+
});
101+
102+
const vocabularyExternal: any = Object.assign(new Vocabulary(), {
103+
id: 'author',
104+
name: 'author',
105+
scrollable: true,
106+
hierarchical: false,
107+
preloadLevel: 1,
108+
entity: 'test',
109+
externalSource: {
110+
'dc.contributor.author': 'authorExternalSource',
111+
},
112+
type: 'vocabulary',
113+
uuid: 'vocabulary-author',
114+
_links: {
115+
self: {
116+
href: 'https://rest.api/rest/api/submission/vocabularies/types',
117+
},
118+
entries: {
119+
href: 'https://rest.api/rest/api/submission/vocabularies/types/entries',
120+
},
121+
},
122+
});
123+
77124
function init() {
78125
FORM_GROUP_TEST_MODEL_CONFIG = {
79126
disabled: false,
@@ -111,6 +158,7 @@ function init() {
111158
submissionId,
112159
id: 'dc_contributor_author',
113160
label: 'Authors',
161+
isInlineGroup: false,
114162
mandatoryField: 'dc.contributor.author',
115163
name: 'dc.contributor.author',
116164
placeholder: 'Authors',
@@ -168,7 +216,9 @@ describe('DsDynamicRelationGroupComponent test suite', () => {
168216
FormBuilderService,
169217
FormComponent,
170218
FormService,
219+
NgbModal,
171220
provideMockStore({ initialState }),
221+
{ provide: SubmissionService, useClass: SubmissionServiceStub },
172222
{ provide: VocabularyService, useValue: vocabularyServiceStub },
173223
{ provide: DsDynamicTypeBindRelationService, useClass: DsDynamicTypeBindRelationService },
174224
{ provide: SubmissionObjectService, useValue: {} },
@@ -187,6 +237,7 @@ describe('DsDynamicRelationGroupComponent test suite', () => {
187237
describe('', () => {
188238
// synchronous beforeEach
189239
beforeEach(() => {
240+
spyOn(vocabularyServiceStub, 'findVocabularyById').and.returnValue(createSuccessfulRemoteDataObject$(vocabulary));
190241
html = `<ds-dynamic-relation-group [model]="model"
191242
[formId]="formId"
192243
[group]="group"

src/app/shared/form/builder/ds-dynamic-form-ui/models/relation-group/dynamic-relation-group.model.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import {
2323
export interface DynamicRelationGroupModelConfig extends DsDynamicInputModelConfig {
2424
submissionId: string;
2525
formConfiguration: FormRowModel[];
26+
isInlineGroup: boolean;
2627
mandatoryField: string;
2728
relationFields: string[];
2829
scopeUUID: string;
@@ -35,6 +36,7 @@ export interface DynamicRelationGroupModelConfig extends DsDynamicInputModelConf
3536
export class DynamicRelationGroupModel extends DsDynamicInputModel {
3637
@serializable() submissionId: string;
3738
@serializable() formConfiguration: FormRowModel[];
39+
@serializable() isInlineGroup: boolean;
3840
@serializable() mandatoryField: string;
3941
@serializable() relationFields: string[];
4042
@serializable() scopeUUID: string;
@@ -50,6 +52,7 @@ export class DynamicRelationGroupModel extends DsDynamicInputModel {
5052
this.relationFields = config.relationFields;
5153
this.scopeUUID = config.scopeUUID;
5254
this.submissionScope = config.submissionScope;
55+
this.isInlineGroup = config.isInlineGroup;
5356
const value = config.value || [];
5457
this.value = value;
5558
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
<div class="pt-2 border-top" [ngClass]="{ 'inline-group-is-invalid': showErrorMessages}" [hidden]="model.hidden">
2+
@if (formModel) {
3+
<ds-form #formRef="formComponent" @shrinkInOut
4+
[formId]="formId"
5+
[formModel]="formModel"
6+
[displayCancel]="false"
7+
[displaySubmit]="false"
8+
[arrayButtonsStyle]="'inline-btn-group'"
9+
[isInlineGroupForm]="true"
10+
(dfBlur)="onBlur($event)"
11+
(dfChange)="onChange($event)"
12+
(dfFocus)="onFocus($event)"
13+
(ngbEvent)="onCustomEvent($event)"
14+
(removeArrayItem)="remove($event)"></ds-form>
15+
}
16+
</div>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
.inline-btn-group {
2+
margin-top: 2rem;
3+
}
4+
5+
.inline-group-is-invalid ds-form:has(ds-dynamic-form-array) .grey-background {
6+
border: 1px solid var(--bs-danger);
7+
}

0 commit comments

Comments
 (0)