diff --git a/docker/local.cfg b/docker/local.cfg
index 6692b13658..947b3c8248 100644
--- a/docker/local.cfg
+++ b/docker/local.cfg
@@ -1,6 +1,6 @@
dspace.dir=/dspace
db.url=jdbc:postgresql://dspacedb:5432/dspace
dspace.hostname=dspace
-dspace.baseUrl=http://localhost:8080
+dspace.baseUrl=http://localhost:8080/server
dspace.name=DSpace Started with Docker Compose
solr.server=http://dspacesolr:8983/solr
diff --git a/resources/i18n/en.json5 b/resources/i18n/en.json5
index 80847f5101..75617b8bcf 100644
--- a/resources/i18n/en.json5
+++ b/resources/i18n/en.json5
@@ -161,6 +161,7 @@
"collection.page.browse.recent.head": "Recent Submissions",
"collection.page.browse.recent.empty": "No items to show",
+ "collection.page.handle": "Permanent URI for this collection",
"collection.page.license": "License",
"collection.page.news": "News",
@@ -184,8 +185,10 @@
"community.form.rights": "Copyright text (HTML)",
"community.form.tableofcontents": "News (HTML)",
"community.form.title": "Name",
+ "community.page.handle": "Permanent URI for this community",
"community.page.license": "License",
"community.page.news": "News",
+ "community.all-lists.head": "Subcommunities and Collections",
"community.sub-collection-list.head": "Collections of this Community",
"community.sub-community-list.head": "Communities of this Community",
diff --git a/src/app/+browse-by/+browse-by-date-page/browse-by-date-page.component.spec.ts b/src/app/+browse-by/+browse-by-date-page/browse-by-date-page.component.spec.ts
index 78f5d52511..a507e8e585 100644
--- a/src/app/+browse-by/+browse-by-date-page/browse-by-date-page.component.spec.ts
+++ b/src/app/+browse-by/+browse-by-date-page/browse-by-date-page.component.spec.ts
@@ -19,6 +19,7 @@ import { ENV_CONFIG, GLOBAL_CONFIG } from '../../../config';
import { BrowseEntrySearchOptions } from '../../core/browse/browse-entry-search-options.model';
import { toRemoteData } from '../+browse-by-metadata-page/browse-by-metadata-page.component.spec';
import { createSuccessfulRemoteDataObject$ } from '../../shared/testing/utils';
+import { VarDirective } from '../../shared/utils/var.directive';
describe('BrowseByDatePageComponent', () => {
let comp: BrowseByDatePageComponent;
@@ -69,7 +70,7 @@ describe('BrowseByDatePageComponent', () => {
beforeEach(async(() => {
TestBed.configureTestingModule({
imports: [CommonModule, RouterTestingModule.withRoutes([]), TranslateModule.forRoot(), NgbModule.forRoot()],
- declarations: [BrowseByDatePageComponent, EnumKeysPipe],
+ declarations: [BrowseByDatePageComponent, EnumKeysPipe, VarDirective],
providers: [
{ provide: GLOBAL_CONFIG, useValue: ENV_CONFIG },
{ provide: ActivatedRoute, useValue: activatedRouteStub },
diff --git a/src/app/+browse-by/+browse-by-metadata-page/browse-by-metadata-page.component.html b/src/app/+browse-by/+browse-by-metadata-page/browse-by-metadata-page.component.html
index c589c543d4..45f2ef3b2a 100644
--- a/src/app/+browse-by/+browse-by-metadata-page/browse-by-metadata-page.component.html
+++ b/src/app/+browse-by/+browse-by-metadata-page/browse-by-metadata-page.component.html
@@ -1,7 +1,31 @@
-
diff --git a/src/app/+browse-by/+browse-by-metadata-page/browse-by-metadata-page.component.spec.ts b/src/app/+browse-by/+browse-by-metadata-page/browse-by-metadata-page.component.spec.ts
index 927effd303..553bd00f56 100644
--- a/src/app/+browse-by/+browse-by-metadata-page/browse-by-metadata-page.component.spec.ts
+++ b/src/app/+browse-by/+browse-by-metadata-page/browse-by-metadata-page.component.spec.ts
@@ -23,6 +23,7 @@ import { MockRouter } from '../../shared/mocks/mock-router';
import { ResourceType } from '../../core/shared/resource-type';
import { createSuccessfulRemoteDataObject$ } from '../../shared/testing/utils';
import { BrowseEntry } from '../../core/shared/browse-entry.model';
+import { VarDirective } from '../../shared/utils/var.directive';
describe('BrowseByMetadataPageComponent', () => {
let comp: BrowseByMetadataPageComponent;
@@ -86,7 +87,7 @@ describe('BrowseByMetadataPageComponent', () => {
beforeEach(async(() => {
TestBed.configureTestingModule({
imports: [CommonModule, RouterTestingModule.withRoutes([]), TranslateModule.forRoot(), NgbModule.forRoot()],
- declarations: [BrowseByMetadataPageComponent, EnumKeysPipe],
+ declarations: [BrowseByMetadataPageComponent, EnumKeysPipe, VarDirective],
providers: [
{ provide: ActivatedRoute, useValue: activatedRouteStub },
{ provide: BrowseService, useValue: mockBrowseService },
diff --git a/src/app/+browse-by/+browse-by-title-page/browse-by-title-page.component.spec.ts b/src/app/+browse-by/+browse-by-title-page/browse-by-title-page.component.spec.ts
index 3bc69e5fcb..90623eb3c7 100644
--- a/src/app/+browse-by/+browse-by-title-page/browse-by-title-page.component.spec.ts
+++ b/src/app/+browse-by/+browse-by-title-page/browse-by-title-page.component.spec.ts
@@ -18,6 +18,7 @@ import { DSpaceObjectDataService } from '../../core/data/dspace-object-data.serv
import { BrowseService } from '../../core/browse/browse.service';
import { MockRouter } from '../../shared/mocks/mock-router';
import { createSuccessfulRemoteDataObject$ } from '../../shared/testing/utils';
+import { VarDirective } from '../../shared/utils/var.directive';
describe('BrowseByTitlePageComponent', () => {
let comp: BrowseByTitlePageComponent;
@@ -64,7 +65,7 @@ describe('BrowseByTitlePageComponent', () => {
beforeEach(async(() => {
TestBed.configureTestingModule({
imports: [CommonModule, RouterTestingModule.withRoutes([]), TranslateModule.forRoot(), NgbModule.forRoot()],
- declarations: [BrowseByTitlePageComponent, EnumKeysPipe],
+ declarations: [BrowseByTitlePageComponent, EnumKeysPipe, VarDirective],
providers: [
{ provide: ActivatedRoute, useValue: activatedRouteStub },
{ provide: BrowseService, useValue: mockBrowseService },
diff --git a/src/app/+collection-page/collection-page.component.html b/src/app/+collection-page/collection-page.component.html
index 2b16bc1ca6..436cd351a0 100644
--- a/src/app/+collection-page/collection-page.component.html
+++ b/src/app/+collection-page/collection-page.component.html
@@ -3,18 +3,22 @@
*ngVar="(collectionRD$ | async) as collectionRD">
+
-
+
+
+
+
+
+
+
-
-
{{'collection.page.browse.recent.head' | translate}}
+
+
{{'collection.page.browse.recent.head' | translate}}
-
-
-
+
+
+
+
+
+
diff --git a/src/app/+community-page/community-page.component.html b/src/app/+community-page/community-page.component.html
index e429d224f2..05d0bd1d0e 100644
--- a/src/app/+community-page/community-page.component.html
+++ b/src/app/+community-page/community-page.component.html
@@ -1,33 +1,38 @@
diff --git a/src/app/core/submission/submission-object-data.service.spec.ts b/src/app/core/submission/submission-object-data.service.spec.ts
new file mode 100644
index 0000000000..b7c06272e6
--- /dev/null
+++ b/src/app/core/submission/submission-object-data.service.spec.ts
@@ -0,0 +1,95 @@
+import { Observable } from 'rxjs';
+import { SubmissionService } from '../../submission/submission.service';
+import { RemoteData } from '../data/remote-data';
+import { SubmissionObject } from './models/submission-object.model';
+import { WorkspaceItem } from './models/workspaceitem.model';
+import { SubmissionObjectDataService } from './submission-object-data.service';
+import { SubmissionScopeType } from './submission-scope-type';
+import { WorkflowItemDataService } from './workflowitem-data.service';
+import { WorkspaceitemDataService } from './workspaceitem-data.service';
+
+describe('SubmissionObjectDataService', () => {
+ let service: SubmissionObjectDataService;
+ let submissionService: SubmissionService;
+ let workspaceitemDataService: WorkspaceitemDataService;
+ let workflowItemDataService: WorkflowItemDataService;
+
+ const submissionId = '1234';
+ const wsiResult = 'wsiResult' as any;
+ const wfiResult = 'wfiResult' as any;
+
+ beforeEach(() => {
+ workspaceitemDataService = jasmine.createSpyObj('WorkspaceitemDataService', {
+ findById: wsiResult
+ });
+ workflowItemDataService = jasmine.createSpyObj('WorkflowItemDataService', {
+ findById: wfiResult
+ });
+ });
+
+ describe('findById', () => {
+ it('should call SubmissionService.getSubmissionScope to determine the type of submission object', () => {
+ submissionService = jasmine.createSpyObj('SubmissionService', {
+ getSubmissionScope: {}
+ });
+ service = new SubmissionObjectDataService(workspaceitemDataService, workflowItemDataService, submissionService);
+ service.findById(submissionId);
+ expect(submissionService.getSubmissionScope).toHaveBeenCalled();
+ });
+
+ describe('when the submission ID refers to a WorkspaceItem', () => {
+ beforeEach(() => {
+ submissionService = jasmine.createSpyObj('SubmissionService', {
+ getSubmissionScope: SubmissionScopeType.WorkspaceItem
+ });
+ service = new SubmissionObjectDataService(workspaceitemDataService, workflowItemDataService, submissionService);
+ });
+
+ it('should forward the result of WorkspaceitemDataService.findById()', () => {
+ const result = service.findById(submissionId);
+ expect(workspaceitemDataService.findById).toHaveBeenCalledWith(submissionId);
+ expect(result).toBe(wsiResult);
+ });
+ });
+
+ describe('when the submission ID refers to a WorkflowItem', () => {
+ beforeEach(() => {
+ submissionService = jasmine.createSpyObj('SubmissionService', {
+ getSubmissionScope: SubmissionScopeType.WorkflowItem
+ });
+ service = new SubmissionObjectDataService(workspaceitemDataService, workflowItemDataService, submissionService);
+ });
+
+ it('should forward the result of WorkflowItemDataService.findById()', () => {
+ const result = service.findById(submissionId);
+ expect(workflowItemDataService.findById).toHaveBeenCalledWith(submissionId);
+ expect(result).toBe(wfiResult);
+ });
+ });
+
+ describe('when the type of submission object is unknown', () => {
+ beforeEach(() => {
+ submissionService = jasmine.createSpyObj('SubmissionService', {
+ getSubmissionScope: 'Something else'
+ });
+ service = new SubmissionObjectDataService(workspaceitemDataService, workflowItemDataService, submissionService);
+ });
+
+ it('shouldn\'t call any data service methods', () => {
+ service.findById(submissionId);
+ expect(workspaceitemDataService.findById).not.toHaveBeenCalled();
+ expect(workflowItemDataService.findById).not.toHaveBeenCalled();
+ });
+
+ it('should return a RemoteData containing an error', (done) => {
+ const result = service.findById(submissionId);
+ result.subscribe((rd: RemoteData
) => {
+ expect(rd.hasFailed).toBe(true);
+ expect(rd.error).toBeDefined();
+ done();
+ })
+ });
+ });
+
+ });
+});
diff --git a/src/app/core/submission/submission-object-data.service.ts b/src/app/core/submission/submission-object-data.service.ts
new file mode 100644
index 0000000000..15ede18cb8
--- /dev/null
+++ b/src/app/core/submission/submission-object-data.service.ts
@@ -0,0 +1,46 @@
+import { Injectable } from '@angular/core';
+import { of as observableOf, Observable } from 'rxjs';
+import { SubmissionService } from '../../submission/submission.service';
+import { RemoteData } from '../data/remote-data';
+import { RemoteDataError } from '../data/remote-data-error';
+import { SubmissionObject } from './models/submission-object.model';
+import { SubmissionScopeType } from './submission-scope-type';
+import { WorkflowItemDataService } from './workflowitem-data.service';
+import { WorkspaceitemDataService } from './workspaceitem-data.service';
+
+/**
+ * A service to retrieve submission objects (WorkspaceItem/WorkflowItem)
+ * without knowing their type
+ */
+@Injectable({
+ providedIn: 'root'
+})
+export class SubmissionObjectDataService {
+ constructor(
+ private workspaceitemDataService: WorkspaceitemDataService,
+ private workflowItemDataService: WorkflowItemDataService,
+ private submissionService: SubmissionService
+ ) {
+ }
+
+ /**
+ * Retrieve a submission object based on its ID.
+ *
+ * @param id The identifier of a submission object
+ */
+ findById(id: string): Observable> {
+ switch (this.submissionService.getSubmissionScope()) {
+ case SubmissionScopeType.WorkspaceItem:
+ return this.workspaceitemDataService.findById(id);
+ case SubmissionScopeType.WorkflowItem:
+ return this.workflowItemDataService.findById(id);
+ default:
+ const error = new RemoteDataError(
+ undefined,
+ undefined,
+ 'The request couldn\'t be sent. Unable to determine the type of submission object'
+ );
+ return observableOf(new RemoteData(false, false, false, error, undefined));
+ }
+ }
+}
diff --git a/src/app/shared/browse-by/browse-by.component.html b/src/app/shared/browse-by/browse-by.component.html
index f7cd7e0d35..09d3cd3d60 100644
--- a/src/app/shared/browse-by/browse-by.component.html
+++ b/src/app/shared/browse-by/browse-by.component.html
@@ -1,5 +1,5 @@
- {{title | translate}}
+ {{title | translate}}
0" @fadeIn>
diff --git a/src/app/shared/browse-by/browse-by.component.ts b/src/app/shared/browse-by/browse-by.component.ts
index 6c4bc78213..230b0bc136 100644
--- a/src/app/shared/browse-by/browse-by.component.ts
+++ b/src/app/shared/browse-by/browse-by.component.ts
@@ -26,6 +26,10 @@ export class BrowseByComponent implements OnInit {
*/
@Input() title: string;
+ /**
+ * The parent name
+ */
+ @Input() parentname: string;
/**
* The list of objects to display
*/
diff --git a/src/app/shared/comcol-page-browse-by/comcol-page-browse-by.component.html b/src/app/shared/comcol-page-browse-by/comcol-page-browse-by.component.html
index 1c73fbb3df..504d9f4bcd 100644
--- a/src/app/shared/comcol-page-browse-by/comcol-page-browse-by.component.html
+++ b/src/app/shared/comcol-page-browse-by/comcol-page-browse-by.component.html
@@ -1,6 +1,24 @@
-
{{'browse.comcol.head' | translate}}
-
+
{{'browse.comcol.head' | translate}}
+
diff --git a/src/app/shared/comcol-page-browse-by/comcol-page-browse-by.component.scss b/src/app/shared/comcol-page-browse-by/comcol-page-browse-by.component.scss
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/src/app/shared/comcol-page-browse-by/comcol-page-browse-by.component.ts b/src/app/shared/comcol-page-browse-by/comcol-page-browse-by.component.ts
index dcc7840bb4..1bc83d74a5 100644
--- a/src/app/shared/comcol-page-browse-by/comcol-page-browse-by.component.ts
+++ b/src/app/shared/comcol-page-browse-by/comcol-page-browse-by.component.ts
@@ -1,6 +1,27 @@
-import { Component, Inject, Input, OnInit } from '@angular/core';
+import {
+ ChangeDetectionStrategy,
+ Component,
+ Inject,
+ Input, NgZone,
+ OnDestroy,
+ OnInit
+} from '@angular/core';
+import { Observable } from 'rxjs/internal/Observable';
+import { Subscription } from 'rxjs/internal/Subscription';
+import { filter, map, startWith, tap } from 'rxjs/operators';
+import { getCollectionPageRoute } from '../../+collection-page/collection-page-routing.module';
+import { getCommunityPageRoute } from '../../+community-page/community-page-routing.module';
import { GLOBAL_CONFIG, GlobalConfig } from '../../../config';
+import { Router, ActivatedRoute, RouterModule, UrlSegment } from '@angular/router';
import { BrowseByTypeConfig } from '../../../config/browse-by-type-config.interface';
+import { hasValue } from '../empty.util';
+
+export interface ComColPageNavOption {
+ id: string;
+ label: string,
+ routerLink: string
+ params?: any;
+};
/**
* A component to display the "Browse By" section of a Community or Collection page
@@ -8,24 +29,63 @@ import { BrowseByTypeConfig } from '../../../config/browse-by-type-config.interf
*/
@Component({
selector: 'ds-comcol-page-browse-by',
- templateUrl: './comcol-page-browse-by.component.html',
+ styleUrls: ['./comcol-page-browse-by.component.scss'],
+ templateUrl: './comcol-page-browse-by.component.html'
})
export class ComcolPageBrowseByComponent implements OnInit {
/**
* The ID of the Community or Collection
*/
@Input() id: string;
-
+ @Input() contentType: string;
/**
* List of currently active browse configurations
*/
types: BrowseByTypeConfig[];
- constructor(@Inject(GLOBAL_CONFIG) public config: GlobalConfig) {
+ allOptions: ComColPageNavOption[];
+
+ currentOptionId$: Observable
;
+
+ constructor(
+ @Inject(GLOBAL_CONFIG) public config: GlobalConfig,
+ private route: ActivatedRoute,
+ private router: Router) {
}
ngOnInit(): void {
- this.types = this.config.browseBy.types;
+ this.allOptions = this.config.browseBy.types
+ .map((config: BrowseByTypeConfig) => ({
+ id: config.id,
+ label: `browse.comcol.by.${config.id}`,
+ routerLink: `/browse/${config.id}`,
+ params: { scope: this.id }
+ }));
+
+ if (this.contentType === 'collection') {
+ this.allOptions = [ {
+ id: this.id,
+ label: 'collection.page.browse.recent.head',
+ routerLink: getCollectionPageRoute(this.id)
+ }, ...this.allOptions ];
+ } else if (this.contentType === 'community') {
+ this.allOptions = [{
+ id: this.id,
+ label: 'community.all-lists.head',
+ routerLink: getCommunityPageRoute(this.id)
+ }, ...this.allOptions ];
+ }
+
+ this.currentOptionId$ = this.route.url.pipe(
+ filter((urlSegments: UrlSegment[]) => hasValue(urlSegments)),
+ map((urlSegments: UrlSegment[]) => urlSegments[urlSegments.length - 1].path)
+ );
}
+ onSelectChange(newId: string) {
+ const selectedOption = this.allOptions
+ .find((option: ComColPageNavOption) => option.id === newId);
+
+ this.router.navigate([selectedOption.routerLink], { queryParams: selectedOption.params });
+ }
}
diff --git a/src/app/shared/comcol-page-handle/comcol-page-handle.component.html b/src/app/shared/comcol-page-handle/comcol-page-handle.component.html
new file mode 100644
index 0000000000..b3ca75bf94
--- /dev/null
+++ b/src/app/shared/comcol-page-handle/comcol-page-handle.component.html
@@ -0,0 +1,4 @@
+
+
{{ title | translate }}
+
+
diff --git a/src/app/shared/comcol-page-handle/comcol-page-handle.component.scss b/src/app/shared/comcol-page-handle/comcol-page-handle.component.scss
new file mode 100644
index 0000000000..5d7bac26c7
--- /dev/null
+++ b/src/app/shared/comcol-page-handle/comcol-page-handle.component.scss
@@ -0,0 +1,5 @@
+div {
+ word-break: break-word;
+ word-wrap: break-word;
+ overflow-wrap: break-word;
+}
diff --git a/src/app/shared/comcol-page-handle/comcol-page-handle.component.ts b/src/app/shared/comcol-page-handle/comcol-page-handle.component.ts
new file mode 100644
index 0000000000..3a2ab307be
--- /dev/null
+++ b/src/app/shared/comcol-page-handle/comcol-page-handle.component.ts
@@ -0,0 +1,29 @@
+import { Component, Input, Inject, Injectable } from '@angular/core';
+import { GlobalConfig } from '../../../config/global-config.interface';
+import { GLOBAL_CONFIG } from '../../../config';
+import { UIURLCombiner } from '../../core/url-combiner/ui-url-combiner';
+/**
+ * This component builds a URL from the value of "handle"
+ */
+
+@Component({
+ selector: 'ds-comcol-page-handle',
+ styleUrls: ['./comcol-page-handle.component.scss'],
+ templateUrl: './comcol-page-handle.component.html'
+})
+
+@Injectable()
+export class ComcolPageHandleComponent {
+
+ // Optional title
+ @Input() title: string;
+
+ // The value of "handle"
+ @Input() content: string;
+
+ constructor(@Inject(GLOBAL_CONFIG) private EnvConfig: GlobalConfig) {
+ }
+ public getHandle(): string {
+ return new UIURLCombiner(this.EnvConfig, '/handle/', this.content).toString();
+ }
+}
diff --git a/src/app/shared/form/builder/ds-dynamic-form-ui/ds-dynamic-form-control-container.component.spec.ts b/src/app/shared/form/builder/ds-dynamic-form-ui/ds-dynamic-form-control-container.component.spec.ts
index f598e142d9..76fe6909d3 100644
--- a/src/app/shared/form/builder/ds-dynamic-form-ui/ds-dynamic-form-control-container.component.spec.ts
+++ b/src/app/shared/form/builder/ds-dynamic-form-ui/ds-dynamic-form-control-container.component.spec.ts
@@ -115,6 +115,7 @@ describe('DsDynamicFormControlContainerComponent test suite', () => {
repeatable: false
}),
new DynamicRelationGroupModel({
+ submissionId: '1234',
id: 'relationGroup',
formConfiguration: [],
mandatoryField: '',
diff --git a/src/app/shared/form/builder/ds-dynamic-form-ui/models/relation-group/dynamic-relation-group.component.spec.ts b/src/app/shared/form/builder/ds-dynamic-form-ui/models/relation-group/dynamic-relation-group.component.spec.ts
index 664c72035d..e254967865 100644
--- a/src/app/shared/form/builder/ds-dynamic-form-ui/models/relation-group/dynamic-relation-group.component.spec.ts
+++ b/src/app/shared/form/builder/ds-dynamic-form-ui/models/relation-group/dynamic-relation-group.component.spec.ts
@@ -26,7 +26,6 @@ import { MOCK_SUBMISSION_CONFIG } from '../../../../../testing/mock-submission-c
import { Store, StoreModule } from '@ngrx/store';
import { MockStore } from '../../../../../testing/mock-store';
import { FormRowModel } from '../../../../../../core/config/models/config-submission-form.model';
-import { WorkspaceItem } from '../../../../../../core/submission/models/workspaceitem.model';
export let FORM_GROUP_TEST_MODEL_CONFIG;
@@ -34,6 +33,8 @@ export let FORM_GROUP_TEST_GROUP;
const config: GlobalConfig = MOCK_SUBMISSION_CONFIG;
+const submissionId = '1234';
+
function init() {
FORM_GROUP_TEST_MODEL_CONFIG = {
disabled: false,
@@ -68,6 +69,7 @@ function init() {
}]
} as FormFieldModel]
} as FormRowModel],
+ submissionId,
id: 'dc_contributor_author',
label: 'Authors',
mandatoryField: 'dc.contributor.author',
@@ -79,7 +81,6 @@ function init() {
scopeUUID: '43fe1f8c-09a6-4fcf-9c78-5d4fed8f2c8f',
submissionScope: undefined,
validators: { required: null },
- workspaceItem: new WorkspaceItem(),
repeatable: false
} as DynamicRelationGroupModelConfig;
@@ -186,7 +187,7 @@ describe('DsDynamicRelationGroupComponent test suite', () => {
it('should init component properly', inject([FormBuilderService], (service: FormBuilderService) => {
const formConfig = { rows: groupComp.model.formConfiguration } as SubmissionFormsModel;
- const formModel = service.modelFromConfiguration(formConfig, groupComp.model.scopeUUID, {}, new WorkspaceItem(), groupComp.model.submissionScope, groupComp.model.readOnly);
+ const formModel = service.modelFromConfiguration(submissionId, formConfig, groupComp.model.scopeUUID, {}, groupComp.model.submissionScope, groupComp.model.readOnly);
const chips = new Chips([], 'value', 'dc.contributor.author');
groupComp.formCollapsed.subscribe((value) => {
expect(value).toEqual(false);
@@ -260,7 +261,7 @@ describe('DsDynamicRelationGroupComponent test suite', () => {
it('should init component properly', inject([FormBuilderService], (service: FormBuilderService) => {
const formConfig = { rows: groupComp.model.formConfiguration } as SubmissionFormsModel;
- const formModel = service.modelFromConfiguration(formConfig, groupComp.model.scopeUUID, {}, new WorkspaceItem(), groupComp.model.submissionScope, groupComp.model.readOnly);
+ const formModel = service.modelFromConfiguration(submissionId, formConfig, groupComp.model.scopeUUID, {}, groupComp.model.submissionScope, groupComp.model.readOnly);
const chips = new Chips(modelValue, 'value', 'dc.contributor.author');
groupComp.formCollapsed.subscribe((value) => {
expect(value).toEqual(true);
diff --git a/src/app/shared/form/builder/ds-dynamic-form-ui/models/relation-group/dynamic-relation-group.components.ts b/src/app/shared/form/builder/ds-dynamic-form-ui/models/relation-group/dynamic-relation-group.components.ts
index 6427e6e939..8a74935ca0 100644
--- a/src/app/shared/form/builder/ds-dynamic-form-ui/models/relation-group/dynamic-relation-group.components.ts
+++ b/src/app/shared/form/builder/ds-dynamic-form-ui/models/relation-group/dynamic-relation-group.components.ts
@@ -93,6 +93,7 @@ export class DsDynamicRelationGroupComponent extends DynamicFormControlComponent
this.formId = this.formService.getUniqueId(this.model.id);
this.formModel = this.formBuilderService.modelFromConfiguration(
+ this.model.submissionId,
config,
this.model.scopeUUID,
{},
diff --git a/src/app/shared/form/builder/ds-dynamic-form-ui/models/relation-group/dynamic-relation-group.model.ts b/src/app/shared/form/builder/ds-dynamic-form-ui/models/relation-group/dynamic-relation-group.model.ts
index e6d2b95afc..c1f76f0431 100644
--- a/src/app/shared/form/builder/ds-dynamic-form-ui/models/relation-group/dynamic-relation-group.model.ts
+++ b/src/app/shared/form/builder/ds-dynamic-form-ui/models/relation-group/dynamic-relation-group.model.ts
@@ -10,6 +10,7 @@ export const PLACEHOLDER_PARENT_METADATA = '#PLACEHOLDER_PARENT_METADATA_VALUE#'
* Dynamic Group Model configuration interface
*/
export interface DynamicRelationGroupModelConfig extends DsDynamicInputModelConfig {
+ submissionId: string,
formConfiguration: FormRowModel[],
mandatoryField: string,
relationFields: string[],
@@ -21,6 +22,7 @@ export interface DynamicRelationGroupModelConfig extends DsDynamicInputModelConf
* Dynamic Group Model class
*/
export class DynamicRelationGroupModel extends DsDynamicInputModel {
+ @serializable() submissionId: string;
@serializable() formConfiguration: FormRowModel[];
@serializable() mandatoryField: string;
@serializable() relationFields: string[];
@@ -32,6 +34,7 @@ export class DynamicRelationGroupModel extends DsDynamicInputModel {
constructor(config: DynamicRelationGroupModelConfig, layout?: DynamicFormControlLayout) {
super(config, layout);
+ this.submissionId = config.submissionId;
this.formConfiguration = config.formConfiguration;
this.mandatoryField = config.mandatoryField;
this.relationFields = config.relationFields;
diff --git a/src/app/shared/form/builder/form-builder.service.spec.ts b/src/app/shared/form/builder/form-builder.service.spec.ts
index 8b91fd3eaf..b001b4b95f 100644
--- a/src/app/shared/form/builder/form-builder.service.spec.ts
+++ b/src/app/shared/form/builder/form-builder.service.spec.ts
@@ -49,7 +49,6 @@ import { DynamicConcatModel } from './ds-dynamic-form-ui/models/ds-dynamic-conca
import { DynamicLookupNameModel } from './ds-dynamic-form-ui/models/lookup/dynamic-lookup-name.model';
import { DynamicRowArrayModel } from './ds-dynamic-form-ui/models/ds-dynamic-row-array-model';
import { FormRowModel } from '../../../core/config/models/config-submission-form.model';
-import { WorkspaceItem } from '../../../core/submission/models/workspaceitem.model';
describe('FormBuilderService test suite', () => {
@@ -57,6 +56,8 @@ describe('FormBuilderService test suite', () => {
let testFormConfiguration: SubmissionFormsModel;
let service: FormBuilderService;
+ const submissionId = '1234';
+
function testValidator() {
return {testValidator: {valid: true}};
}
@@ -194,17 +195,18 @@ describe('FormBuilderService test suite', () => {
new DynamicColorPickerModel({id: 'testColorPicker'}),
- new DynamicTypeaheadModel({id: 'testTypeahead', workspaceItem: new WorkspaceItem(), repeatable: false}),
+ new DynamicTypeaheadModel({id: 'testTypeahead', repeatable: false}),
- new DynamicScrollableDropdownModel({id: 'testScrollableDropdown', authorityOptions: authorityOptions, workspaceItem: new WorkspaceItem(), repeatable: false}),
+ new DynamicScrollableDropdownModel({id: 'testScrollableDropdown', authorityOptions: authorityOptions, repeatable: false}),
- new DynamicTagModel({id: 'testTag', workspaceItem: new WorkspaceItem(), repeatable: false}),
+ new DynamicTagModel({id: 'testTag', repeatable: false}),
new DynamicListCheckboxGroupModel({id: 'testCheckboxList', authorityOptions: authorityOptions, repeatable: true}),
new DynamicListRadioGroupModel({id: 'testRadioList', authorityOptions: authorityOptions, repeatable: false}),
new DynamicRelationGroupModel({
+ submissionId,
id: 'testRelationGroup',
formConfiguration: [{
fields: [{
@@ -241,15 +243,14 @@ describe('FormBuilderService test suite', () => {
relationFields: [],
scopeUUID: '',
submissionScope: '',
- workspaceItem: new WorkspaceItem(),
repeatable: false
}),
new DynamicDsDatePickerModel({id: 'testDate'}),
- new DynamicLookupModel({id: 'testLookup', workspaceItem: new WorkspaceItem(), repeatable: false}),
+ new DynamicLookupModel({id: 'testLookup', repeatable: false}),
- new DynamicLookupNameModel({id: 'testLookupName', workspaceItem: new WorkspaceItem(), repeatable: false}),
+ new DynamicLookupNameModel({id: 'testLookupName', repeatable: false}),
new DynamicQualdropModel({id: 'testCombobox', readOnly: false, required: false}),
@@ -410,7 +411,7 @@ describe('FormBuilderService test suite', () => {
});
it('should create an array of form models', () => {
- const formModel = service.modelFromConfiguration(testFormConfiguration, 'testScopeUUID', {}, new WorkspaceItem());
+ const formModel = service.modelFromConfiguration(submissionId, testFormConfiguration, 'testScopeUUID');
expect(formModel[0] instanceof DynamicRowGroupModel).toBe(true);
expect((formModel[0] as DynamicRowGroupModel).group.length).toBe(3);
@@ -431,7 +432,7 @@ describe('FormBuilderService test suite', () => {
});
it('should return form\'s fields value from form model', () => {
- const formModel = service.modelFromConfiguration(testFormConfiguration, 'testScopeUUID', {}, new WorkspaceItem());
+ const formModel = service.modelFromConfiguration(submissionId, testFormConfiguration, 'testScopeUUID');
let value = {} as any;
expect(service.getValueFromModel(formModel)).toEqual(value);
@@ -452,7 +453,7 @@ describe('FormBuilderService test suite', () => {
});
it('should clear all form\'s fields value', () => {
- const formModel = service.modelFromConfiguration(testFormConfiguration, 'testScopeUUID', {}, new WorkspaceItem());
+ const formModel = service.modelFromConfiguration(submissionId, testFormConfiguration, 'testScopeUUID');
const value = {} as any;
((formModel[0] as DynamicRowGroupModel).get(1) as DsDynamicInputModel).valueUpdates.next('test');
@@ -464,7 +465,7 @@ describe('FormBuilderService test suite', () => {
});
it('should return true when model has a custom group model as parent', () => {
- const formModel = service.modelFromConfiguration(testFormConfiguration, 'testScopeUUID', {}, new WorkspaceItem());
+ const formModel = service.modelFromConfiguration(submissionId, testFormConfiguration, 'testScopeUUID');
let model = service.findById('dc_identifier_QUALDROP_VALUE', formModel);
let modelParent = service.findById('dc_identifier_QUALDROP_GROUP', formModel);
model.parent = modelParent;
@@ -493,7 +494,7 @@ describe('FormBuilderService test suite', () => {
});
it('should return true when model value is a map', () => {
- const formModel = service.modelFromConfiguration(testFormConfiguration, 'testScopeUUID', {}, new WorkspaceItem());
+ const formModel = service.modelFromConfiguration(submissionId, testFormConfiguration, 'testScopeUUID');
const model = service.findById('dc_identifier_QUALDROP_VALUE', formModel);
const modelParent = service.findById('dc_identifier_QUALDROP_GROUP', formModel);
model.parent = modelParent;
@@ -502,7 +503,7 @@ describe('FormBuilderService test suite', () => {
});
it('should return true when model is a Qualdrop Group', () => {
- const formModel = service.modelFromConfiguration(testFormConfiguration, 'testScopeUUID', {}, new WorkspaceItem());
+ const formModel = service.modelFromConfiguration(submissionId, testFormConfiguration, 'testScopeUUID');
let model = service.findById('dc_identifier_QUALDROP_GROUP', formModel);
expect(service.isQualdropGroup(model)).toBe(true);
@@ -513,7 +514,7 @@ describe('FormBuilderService test suite', () => {
});
it('should return true when model is a Custom or List Group', () => {
- const formModel = service.modelFromConfiguration(testFormConfiguration, 'testScopeUUID', {}, new WorkspaceItem());
+ const formModel = service.modelFromConfiguration(submissionId, testFormConfiguration, 'testScopeUUID');
let model = service.findById('dc_identifier_QUALDROP_GROUP', formModel);
expect(service.isCustomOrListGroup(model)).toBe(true);
@@ -532,7 +533,7 @@ describe('FormBuilderService test suite', () => {
});
it('should return true when model is a Custom Group', () => {
- const formModel = service.modelFromConfiguration(testFormConfiguration, 'testScopeUUID', {}, new WorkspaceItem());
+ const formModel = service.modelFromConfiguration(submissionId, testFormConfiguration, 'testScopeUUID');
let model = service.findById('dc_identifier_QUALDROP_GROUP', formModel);
expect(service.isCustomGroup(model)).toBe(true);
diff --git a/src/app/shared/form/builder/form-builder.service.ts b/src/app/shared/form/builder/form-builder.service.ts
index 82317e02a7..dcc9403d9b 100644
--- a/src/app/shared/form/builder/form-builder.service.ts
+++ b/src/app/shared/form/builder/form-builder.service.ts
@@ -11,6 +11,7 @@ import {
DynamicFormControlModel,
DynamicFormGroupModel,
DynamicFormService,
+ DynamicFormValidationService,
DynamicPathable,
JSONUtils,
} from '@ng-dynamic-forms/core';
@@ -26,11 +27,17 @@ import { DynamicRowArrayModel } from './ds-dynamic-form-ui/models/ds-dynamic-row
import { DsDynamicInputModel } from './ds-dynamic-form-ui/models/ds-dynamic-input.model';
import { FormFieldMetadataValueObject } from './models/form-field-metadata-value.model';
import { isNgbDateStruct } from '../../date.util';
-import { WorkspaceItem } from '../../../core/submission/models/workspaceitem.model';
@Injectable()
export class FormBuilderService extends DynamicFormService {
+ constructor(
+ validationService: DynamicFormValidationService,
+ protected rowParser: RowParser
+ ) {
+ super(validationService);
+ }
+
findById(id: string, groupModel: DynamicFormControlModel[], arrayIndex = null): DynamicFormControlModel | null {
let result = null;
@@ -196,13 +203,13 @@ export class FormBuilderService extends DynamicFormService {
return result;
}
- modelFromConfiguration(json: string | SubmissionFormsModel, scopeUUID: string, initFormValues: any = {}, wsi: WorkspaceItem, submissionScope?: string, readOnly = false): DynamicFormControlModel[] | never {
+ modelFromConfiguration(submissionId: string, json: string | SubmissionFormsModel, scopeUUID: string, sectionData: any = {}, submissionScope?: string, readOnly = false): DynamicFormControlModel[] | never {
let rows: DynamicFormControlModel[] = [];
const rawData = typeof json === 'string' ? JSON.parse(json, JSONUtils.parseReviver) : json;
if (rawData.rows && !isEmpty(rawData.rows)) {
rawData.rows.forEach((currentRow) => {
- const rowParsed = new RowParser(currentRow, scopeUUID, initFormValues, wsi, submissionScope, readOnly).parse();
+ const rowParsed = this.rowParser.parse(submissionId, currentRow, scopeUUID, sectionData, submissionScope, readOnly);
if (isNotNull(rowParsed)) {
if (Array.isArray(rowParsed)) {
rows = rows.concat(rowParsed);
diff --git a/src/app/shared/form/builder/parsers/concat-field-parser.ts b/src/app/shared/form/builder/parsers/concat-field-parser.ts
index 57bdc8d0dc..33a92c726d 100644
--- a/src/app/shared/form/builder/parsers/concat-field-parser.ts
+++ b/src/app/shared/form/builder/parsers/concat-field-parser.ts
@@ -1,4 +1,4 @@
-import { FieldParser } from './field-parser';
+import { Inject } from '@angular/core';
import { FormFieldModel } from '../models/form-field.model';
import { FormFieldMetadataValueObject } from '../models/form-field-metadata-value.model';
import {
@@ -15,18 +15,25 @@ import {
} from '../ds-dynamic-form-ui/models/ds-dynamic-concat.model';
import { isNotEmpty } from '../../../empty.util';
import { ParserOptions } from './parser-options';
-import { WorkspaceItem } from '../../../../core/submission/models/workspaceitem.model';
+import {
+ CONFIG_DATA,
+ FieldParser,
+ INIT_FORM_VALUES,
+ PARSER_OPTIONS,
+ SUBMISSION_ID
+} from './field-parser';
export class ConcatFieldParser extends FieldParser {
- constructor(protected configData: FormFieldModel,
- protected initFormValues,
- protected parserOptions: ParserOptions,
- protected separator: string,
- protected workspaceItem: WorkspaceItem,
- protected firstPlaceholder: string = null,
- protected secondPlaceholder: string = null) {
- super(configData, initFormValues, parserOptions, workspaceItem);
+ constructor(
+ @Inject(SUBMISSION_ID) submissionId: string,
+ @Inject(CONFIG_DATA) configData: FormFieldModel,
+ @Inject(INIT_FORM_VALUES) initFormValues,
+ @Inject(PARSER_OPTIONS) parserOptions: ParserOptions,
+ protected separator: string,
+ protected firstPlaceholder: string = null,
+ protected secondPlaceholder: string = null) {
+ super(submissionId, configData, initFormValues, parserOptions);
this.separator = separator;
this.firstPlaceholder = firstPlaceholder;
diff --git a/src/app/shared/form/builder/parsers/date-field-parser.spec.ts b/src/app/shared/form/builder/parsers/date-field-parser.spec.ts
index a0b550d244..efa4f3cdb5 100644
--- a/src/app/shared/form/builder/parsers/date-field-parser.spec.ts
+++ b/src/app/shared/form/builder/parsers/date-field-parser.spec.ts
@@ -3,12 +3,12 @@ import { DateFieldParser } from './date-field-parser';
import { DynamicDsDatePickerModel } from '../ds-dynamic-form-ui/models/date-picker/date-picker.model';
import { FormFieldMetadataValueObject } from '../models/form-field-metadata-value.model';
import { ParserOptions } from './parser-options';
-import { WorkspaceItem } from '../../../../core/submission/models/workspaceitem.model';
describe('DateFieldParser test suite', () => {
let field: FormFieldModel;
let initFormValues: any = {};
+ const submissionId = '1234';
const parserOptions: ParserOptions = {
readOnly: false,
submissionScope: null,
@@ -36,13 +36,13 @@ describe('DateFieldParser test suite', () => {
});
it('should init parser properly', () => {
- const parser = new DateFieldParser(field, initFormValues, parserOptions, new WorkspaceItem());
+ const parser = new DateFieldParser(submissionId, field, initFormValues, parserOptions);
expect(parser instanceof DateFieldParser).toBe(true);
});
it('should return a DynamicDsDatePickerModel object when repeatable option is false', () => {
- const parser = new DateFieldParser(field, initFormValues, parserOptions, new WorkspaceItem());
+ const parser = new DateFieldParser(submissionId, field, initFormValues, parserOptions);
const fieldModel = parser.parse();
@@ -55,7 +55,7 @@ describe('DateFieldParser test suite', () => {
};
const expectedValue = '1983-11-18';
- const parser = new DateFieldParser(field, initFormValues, parserOptions, new WorkspaceItem());
+ const parser = new DateFieldParser(submissionId, field, initFormValues, parserOptions);
const fieldModel = parser.parse();
diff --git a/src/app/shared/form/builder/parsers/dropdown-field-parser.spec.ts b/src/app/shared/form/builder/parsers/dropdown-field-parser.spec.ts
index c42a80cb57..8dbd68e05a 100644
--- a/src/app/shared/form/builder/parsers/dropdown-field-parser.spec.ts
+++ b/src/app/shared/form/builder/parsers/dropdown-field-parser.spec.ts
@@ -2,11 +2,11 @@ import { FormFieldModel } from '../models/form-field.model';
import { DropdownFieldParser } from './dropdown-field-parser';
import { DynamicScrollableDropdownModel } from '../ds-dynamic-form-ui/models/scrollable-dropdown/dynamic-scrollable-dropdown.model';
import { ParserOptions } from './parser-options';
-import { WorkspaceItem } from '../../../../core/submission/models/workspaceitem.model';
describe('DropdownFieldParser test suite', () => {
let field: FormFieldModel;
+ const submissionId = '1234';
const initFormValues = {};
const parserOptions: ParserOptions = {
readOnly: false,
@@ -36,13 +36,13 @@ describe('DropdownFieldParser test suite', () => {
});
it('should init parser properly', () => {
- const parser = new DropdownFieldParser(field, initFormValues, parserOptions, new WorkspaceItem());
+ const parser = new DropdownFieldParser(submissionId, field, initFormValues, parserOptions);
expect(parser instanceof DropdownFieldParser).toBe(true);
});
it('should return a DynamicScrollableDropdownModel object when repeatable option is false', () => {
- const parser = new DropdownFieldParser(field, initFormValues, parserOptions, new WorkspaceItem());
+ const parser = new DropdownFieldParser(submissionId, field, initFormValues, parserOptions);
const fieldModel = parser.parse();
@@ -51,7 +51,7 @@ describe('DropdownFieldParser test suite', () => {
it('should throw when authority is not passed', () => {
field.selectableMetadata[0].authority = null;
- const parser = new DropdownFieldParser(field, initFormValues, parserOptions, new WorkspaceItem());
+ const parser = new DropdownFieldParser(submissionId, field, initFormValues, parserOptions);
expect(() => parser.parse())
.toThrow();
diff --git a/src/app/shared/form/builder/parsers/dropdown-field-parser.ts b/src/app/shared/form/builder/parsers/dropdown-field-parser.ts
index 1623829b15..4816a2a073 100644
--- a/src/app/shared/form/builder/parsers/dropdown-field-parser.ts
+++ b/src/app/shared/form/builder/parsers/dropdown-field-parser.ts
@@ -1,4 +1,12 @@
-import { FieldParser } from './field-parser';
+import { Inject } from '@angular/core';
+import { FormFieldModel } from '../models/form-field.model';
+import {
+ CONFIG_DATA,
+ FieldParser,
+ INIT_FORM_VALUES,
+ PARSER_OPTIONS,
+ SUBMISSION_ID
+} from './field-parser';
import { DynamicFormControlLayout, } from '@ng-dynamic-forms/core';
import {
DynamicScrollableDropdownModel,
@@ -6,9 +14,19 @@ import {
} from '../ds-dynamic-form-ui/models/scrollable-dropdown/dynamic-scrollable-dropdown.model';
import { isNotEmpty } from '../../../empty.util';
import { FormFieldMetadataValueObject } from '../models/form-field-metadata-value.model';
+import { ParserOptions } from './parser-options';
export class DropdownFieldParser extends FieldParser {
+ constructor(
+ @Inject(SUBMISSION_ID) submissionId: string,
+ @Inject(CONFIG_DATA) configData: FormFieldModel,
+ @Inject(INIT_FORM_VALUES) initFormValues,
+ @Inject(PARSER_OPTIONS) parserOptions: ParserOptions
+ ) {
+ super(submissionId, configData, initFormValues, parserOptions)
+ }
+
public modelFactory(fieldValue?: FormFieldMetadataValueObject | any, label?: boolean): any {
const dropdownModelConfig: DynamicScrollableDropdownModelConfig = this.initModel(null, label);
let layout: DynamicFormControlLayout;
diff --git a/src/app/shared/form/builder/parsers/field-parser.ts b/src/app/shared/form/builder/parsers/field-parser.ts
index 9092445905..6fbcef91ea 100644
--- a/src/app/shared/form/builder/parsers/field-parser.ts
+++ b/src/app/shared/form/builder/parsers/field-parser.ts
@@ -1,4 +1,5 @@
-import { hasValue, isEmpty, isNotEmpty, isNotNull, isNotUndefined } from '../../../empty.util';
+import { Inject, InjectionToken } from '@angular/core';
+import { hasValue, isNotEmpty, isNotNull, isNotUndefined, isEmpty } from '../../../empty.util';
import { FormFieldModel } from '../models/form-field.model';
import { uniqueId } from 'lodash';
@@ -12,13 +13,22 @@ import { DynamicFormControlLayout } from '@ng-dynamic-forms/core';
import { setLayout } from './parser.utils';
import { AuthorityOptions } from '../../../../core/integration/models/authority-options.model';
import { ParserOptions } from './parser-options';
-import { WorkspaceItem } from '../../../../core/submission/models/workspaceitem.model';
+
+export const SUBMISSION_ID: InjectionToken = new InjectionToken('submissionId');
+export const CONFIG_DATA: InjectionToken = new InjectionToken('configData');
+export const INIT_FORM_VALUES:InjectionToken = new InjectionToken('initFormValues');
+export const PARSER_OPTIONS: InjectionToken = new InjectionToken('parserOptions');
export abstract class FieldParser {
protected fieldId: string;
- constructor(protected configData: FormFieldModel, protected initFormValues, protected parserOptions: ParserOptions, protected workspaceItem: WorkspaceItem) {
- }
+
+ constructor(
+ @Inject(SUBMISSION_ID) protected submissionId: string,
+ @Inject(CONFIG_DATA) protected configData: FormFieldModel,
+ @Inject(INIT_FORM_VALUES) protected initFormValues: any,
+ @Inject(PARSER_OPTIONS) protected parserOptions: ParserOptions
+ ) {}
public abstract modelFactory(fieldValue?: FormFieldMetadataValueObject, label?: boolean): any;
@@ -31,11 +41,12 @@ export abstract class FieldParser {
) {
let arrayCounter = 0;
let fieldArrayCounter = 0;
+
const config = {
id: uniqueId() + '_array',
+ label: this.configData.label,
initialCount: this.getInitArrayIndex(),
notRepeatable: !this.configData.repeatable,
- label: this.configData.label,
required: isNotEmpty(this.configData.mandatory),
groupFactory: () => {
let model;
@@ -185,7 +196,6 @@ export abstract class FieldParser {
// Set read only option
controlModel.readOnly = this.parserOptions.readOnly;
controlModel.disabled = this.parserOptions.readOnly;
- controlModel.workspaceItem = this.workspaceItem;
controlModel.relationship = this.configData.selectableRelationship;
controlModel.repeatable = this.configData.repeatable;
controlModel.metadataFields = isNotEmpty(this.configData.selectableMetadata) ? this.configData.selectableMetadata.map((metadataObject) => metadataObject.metadata) : [];
diff --git a/src/app/shared/form/builder/parsers/list-field-parser.spec.ts b/src/app/shared/form/builder/parsers/list-field-parser.spec.ts
index a72f112212..fab5ec3888 100644
--- a/src/app/shared/form/builder/parsers/list-field-parser.spec.ts
+++ b/src/app/shared/form/builder/parsers/list-field-parser.spec.ts
@@ -4,12 +4,12 @@ import { ListFieldParser } from './list-field-parser';
import { DynamicListCheckboxGroupModel } from '../ds-dynamic-form-ui/models/list/dynamic-list-checkbox-group.model';
import { DynamicListRadioGroupModel } from '../ds-dynamic-form-ui/models/list/dynamic-list-radio-group.model';
import { ParserOptions } from './parser-options';
-import { WorkspaceItem } from '../../../../core/submission/models/workspaceitem.model';
describe('ListFieldParser test suite', () => {
let field: FormFieldModel;
let initFormValues = {};
+ const submissionId = '1234';
const parserOptions: ParserOptions = {
readOnly: false,
submissionScope: 'testScopeUUID',
@@ -38,13 +38,13 @@ describe('ListFieldParser test suite', () => {
});
it('should init parser properly', () => {
- const parser = new ListFieldParser(field, initFormValues, parserOptions, new WorkspaceItem());
+ const parser = new ListFieldParser(submissionId, field, initFormValues, parserOptions);
expect(parser instanceof ListFieldParser).toBe(true);
});
it('should return a DynamicListCheckboxGroupModel object when repeatable option is true', () => {
- const parser = new ListFieldParser(field, initFormValues, parserOptions, new WorkspaceItem());
+ const parser = new ListFieldParser(submissionId, field, initFormValues, parserOptions);
const fieldModel = parser.parse();
@@ -53,7 +53,7 @@ describe('ListFieldParser test suite', () => {
it('should return a DynamicListRadioGroupModel object when repeatable option is false', () => {
field.repeatable = false;
- const parser = new ListFieldParser(field, initFormValues, parserOptions, new WorkspaceItem());
+ const parser = new ListFieldParser(submissionId, field, initFormValues, parserOptions);
const fieldModel = parser.parse();
@@ -66,7 +66,7 @@ describe('ListFieldParser test suite', () => {
};
const expectedValue = [new FormFieldMetadataValueObject('test type')];
- const parser = new ListFieldParser(field, initFormValues, parserOptions, new WorkspaceItem());
+ const parser = new ListFieldParser(submissionId, field, initFormValues, parserOptions);
const fieldModel = parser.parse();
diff --git a/src/app/shared/form/builder/parsers/lookup-field-parser.spec.ts b/src/app/shared/form/builder/parsers/lookup-field-parser.spec.ts
index ad3bf08005..5e14e0c013 100644
--- a/src/app/shared/form/builder/parsers/lookup-field-parser.spec.ts
+++ b/src/app/shared/form/builder/parsers/lookup-field-parser.spec.ts
@@ -3,12 +3,12 @@ import { FormFieldMetadataValueObject } from '../models/form-field-metadata-valu
import { LookupFieldParser } from './lookup-field-parser';
import { DynamicLookupModel } from '../ds-dynamic-form-ui/models/lookup/dynamic-lookup.model';
import { ParserOptions } from './parser-options';
-import { WorkspaceItem } from '../../../../core/submission/models/workspaceitem.model';
describe('LookupFieldParser test suite', () => {
let field: FormFieldModel;
let initFormValues = {};
+ const submissionId = '1234';
const parserOptions: ParserOptions = {
readOnly: false,
submissionScope: 'testScopeUUID',
@@ -37,13 +37,13 @@ describe('LookupFieldParser test suite', () => {
});
it('should init parser properly', () => {
- const parser = new LookupFieldParser(field, initFormValues, parserOptions, new WorkspaceItem());
+ const parser = new LookupFieldParser(submissionId, field, initFormValues, parserOptions);
expect(parser instanceof LookupFieldParser).toBe(true);
});
it('should return a DynamicLookupModel object when repeatable option is false', () => {
- const parser = new LookupFieldParser(field, initFormValues, parserOptions, new WorkspaceItem());
+ const parser = new LookupFieldParser(submissionId, field, initFormValues, parserOptions);
const fieldModel = parser.parse();
@@ -56,7 +56,7 @@ describe('LookupFieldParser test suite', () => {
};
const expectedValue = new FormFieldMetadataValueObject('test journal');
- const parser = new LookupFieldParser(field, initFormValues, parserOptions, new WorkspaceItem());
+ const parser = new LookupFieldParser(submissionId, field, initFormValues, parserOptions);
const fieldModel = parser.parse();
diff --git a/src/app/shared/form/builder/parsers/lookup-name-field-parser.spec.ts b/src/app/shared/form/builder/parsers/lookup-name-field-parser.spec.ts
index 574f61b9d0..adc1e90166 100644
--- a/src/app/shared/form/builder/parsers/lookup-name-field-parser.spec.ts
+++ b/src/app/shared/form/builder/parsers/lookup-name-field-parser.spec.ts
@@ -1,16 +1,14 @@
import { FormFieldModel } from '../models/form-field.model';
import { FormFieldMetadataValueObject } from '../models/form-field-metadata-value.model';
-import { LookupFieldParser } from './lookup-field-parser';
-import { DynamicLookupModel } from '../ds-dynamic-form-ui/models/lookup/dynamic-lookup.model';
import { LookupNameFieldParser } from './lookup-name-field-parser';
import { DynamicLookupNameModel } from '../ds-dynamic-form-ui/models/lookup/dynamic-lookup-name.model';
import { ParserOptions } from './parser-options';
-import { WorkspaceItem } from '../../../../core/submission/models/workspaceitem.model';
describe('LookupNameFieldParser test suite', () => {
let field: FormFieldModel;
let initFormValues = {};
+ const submissionId = '1234';
const parserOptions: ParserOptions = {
readOnly: false,
submissionScope: 'testScopeUUID',
@@ -39,13 +37,13 @@ describe('LookupNameFieldParser test suite', () => {
});
it('should init parser properly', () => {
- const parser = new LookupNameFieldParser(field, initFormValues, parserOptions, new WorkspaceItem());
+ const parser = new LookupNameFieldParser(submissionId, field, initFormValues, parserOptions);
expect(parser instanceof LookupNameFieldParser).toBe(true);
});
it('should return a DynamicLookupNameModel object when repeatable option is false', () => {
- const parser = new LookupNameFieldParser(field, initFormValues, parserOptions, new WorkspaceItem());
+ const parser = new LookupNameFieldParser(submissionId, field, initFormValues, parserOptions);
const fieldModel = parser.parse();
@@ -58,7 +56,7 @@ describe('LookupNameFieldParser test suite', () => {
};
const expectedValue = new FormFieldMetadataValueObject('test author');
- const parser = new LookupNameFieldParser(field, initFormValues, parserOptions, new WorkspaceItem());
+ const parser = new LookupNameFieldParser(submissionId, field, initFormValues, parserOptions);
const fieldModel = parser.parse();
diff --git a/src/app/shared/form/builder/parsers/name-field-parser.spec.ts b/src/app/shared/form/builder/parsers/name-field-parser.spec.ts
index 116cd76911..1b0c637030 100644
--- a/src/app/shared/form/builder/parsers/name-field-parser.spec.ts
+++ b/src/app/shared/form/builder/parsers/name-field-parser.spec.ts
@@ -3,7 +3,6 @@ import { NameFieldParser } from './name-field-parser';
import { DynamicConcatModel } from '../ds-dynamic-form-ui/models/ds-dynamic-concat.model';
import { FormFieldMetadataValueObject } from '../models/form-field-metadata-value.model';
import { ParserOptions } from './parser-options';
-import { WorkspaceItem } from '../../../../core/submission/models/workspaceitem.model';
describe('NameFieldParser test suite', () => {
let field1: FormFieldModel;
@@ -11,6 +10,7 @@ describe('NameFieldParser test suite', () => {
let field3: FormFieldModel;
let initFormValues: any = {};
+ const submissionId = '1234';
const parserOptions: ParserOptions = {
readOnly: false,
submissionScope: 'testScopeUUID',
@@ -70,13 +70,13 @@ describe('NameFieldParser test suite', () => {
});
it('should init parser properly', () => {
- const parser = new NameFieldParser(field1, initFormValues, parserOptions, new WorkspaceItem());
+ const parser = new NameFieldParser(submissionId, field1, initFormValues, parserOptions);
expect(parser instanceof NameFieldParser).toBe(true);
});
it('should return a DynamicConcatModel object when repeatable option is false', () => {
- const parser = new NameFieldParser(field2, initFormValues, parserOptions, new WorkspaceItem());
+ const parser = new NameFieldParser(submissionId, field2, initFormValues, parserOptions);
const fieldModel = parser.parse();
@@ -84,7 +84,7 @@ describe('NameFieldParser test suite', () => {
});
it('should return a DynamicConcatModel object with the correct separator', () => {
- const parser = new NameFieldParser(field2, initFormValues, parserOptions, new WorkspaceItem());
+ const parser = new NameFieldParser(submissionId, field2, initFormValues, parserOptions);
const fieldModel = parser.parse();
@@ -97,7 +97,7 @@ describe('NameFieldParser test suite', () => {
};
const expectedValue = new FormFieldMetadataValueObject('test, name');
- const parser = new NameFieldParser(field1, initFormValues, parserOptions, new WorkspaceItem());
+ const parser = new NameFieldParser(submissionId, field1, initFormValues, parserOptions);
const fieldModel = parser.parse();
diff --git a/src/app/shared/form/builder/parsers/name-field-parser.ts b/src/app/shared/form/builder/parsers/name-field-parser.ts
index 8e2d3aa992..e5ecb034ea 100644
--- a/src/app/shared/form/builder/parsers/name-field-parser.ts
+++ b/src/app/shared/form/builder/parsers/name-field-parser.ts
@@ -1,11 +1,17 @@
+import { Inject } from '@angular/core';
import { FormFieldModel } from '../models/form-field.model';
import { ConcatFieldParser } from './concat-field-parser';
+import { CONFIG_DATA, INIT_FORM_VALUES, PARSER_OPTIONS, SUBMISSION_ID } from './field-parser';
import { ParserOptions } from './parser-options';
-import { WorkspaceItem } from '../../../../core/submission/models/workspaceitem.model';
export class NameFieldParser extends ConcatFieldParser {
- constructor(protected configData: FormFieldModel, protected initFormValues, protected parserOptions: ParserOptions, wsi: WorkspaceItem) {
- super(configData, initFormValues, parserOptions, ',', wsi, 'form.last-name', 'form.first-name');
+ constructor(
+ @Inject(SUBMISSION_ID) submissionId: string,
+ @Inject(CONFIG_DATA) configData: FormFieldModel,
+ @Inject(INIT_FORM_VALUES) initFormValues,
+ @Inject(PARSER_OPTIONS) parserOptions: ParserOptions
+ ) {
+ super(submissionId, configData, initFormValues, parserOptions, ',', 'form.last-name', 'form.first-name');
}
}
diff --git a/src/app/shared/form/builder/parsers/onebox-field-parser.spec.ts b/src/app/shared/form/builder/parsers/onebox-field-parser.spec.ts
index 9c4b3c47f1..4668b3017d 100644
--- a/src/app/shared/form/builder/parsers/onebox-field-parser.spec.ts
+++ b/src/app/shared/form/builder/parsers/onebox-field-parser.spec.ts
@@ -4,13 +4,13 @@ import { DynamicQualdropModel } from '../ds-dynamic-form-ui/models/ds-dynamic-qu
import { DynamicTypeaheadModel } from '../ds-dynamic-form-ui/models/typeahead/dynamic-typeahead.model';
import { DsDynamicInputModel } from '../ds-dynamic-form-ui/models/ds-dynamic-input.model';
import { ParserOptions } from './parser-options';
-import { WorkspaceItem } from '../../../../core/submission/models/workspaceitem.model';
describe('OneboxFieldParser test suite', () => {
let field1: FormFieldModel;
let field2: FormFieldModel;
let field3: FormFieldModel;
+ const submissionId = '1234';
const initFormValues = {};
const parserOptions: ParserOptions = {
readOnly: false,
@@ -71,13 +71,13 @@ describe('OneboxFieldParser test suite', () => {
});
it('should init parser properly', () => {
- const parser = new OneboxFieldParser(field1, initFormValues, parserOptions, new WorkspaceItem());
+ const parser = new OneboxFieldParser(submissionId, field1, initFormValues, parserOptions);
expect(parser instanceof OneboxFieldParser).toBe(true);
});
it('should return a DynamicQualdropModel object when selectableMetadata is multiple', () => {
- const parser = new OneboxFieldParser(field2, initFormValues, parserOptions, new WorkspaceItem());
+ const parser = new OneboxFieldParser(submissionId, field2, initFormValues, parserOptions);
const fieldModel = parser.parse();
@@ -85,7 +85,7 @@ describe('OneboxFieldParser test suite', () => {
});
it('should return a DsDynamicInputModel object when selectableMetadata is not multiple', () => {
- const parser = new OneboxFieldParser(field3, initFormValues, parserOptions, new WorkspaceItem());
+ const parser = new OneboxFieldParser(submissionId, field3, initFormValues, parserOptions);
const fieldModel = parser.parse();
@@ -93,7 +93,7 @@ describe('OneboxFieldParser test suite', () => {
});
it('should return a DynamicTypeaheadModel object when selectableMetadata has authority', () => {
- const parser = new OneboxFieldParser(field1, initFormValues, parserOptions, new WorkspaceItem());
+ const parser = new OneboxFieldParser(submissionId, field1, initFormValues, parserOptions);
const fieldModel = parser.parse();
diff --git a/src/app/shared/form/builder/parsers/parser-factory.ts b/src/app/shared/form/builder/parsers/parser-factory.ts
index f0fed02466..92d4f01555 100644
--- a/src/app/shared/form/builder/parsers/parser-factory.ts
+++ b/src/app/shared/form/builder/parsers/parser-factory.ts
@@ -1,6 +1,12 @@
+import { StaticProvider } from '@angular/core';
import { ParserType } from './parser-type';
-import { GenericConstructor } from '../../../../core/shared/generic-constructor';
-import { FieldParser } from './field-parser';
+import {
+ CONFIG_DATA,
+ FieldParser,
+ INIT_FORM_VALUES,
+ PARSER_OPTIONS,
+ SUBMISSION_ID
+} from './field-parser';
import { DateFieldParser } from './date-field-parser';
import { DropdownFieldParser } from './dropdown-field-parser';
import { RelationGroupFieldParser } from './relation-group-field-parser';
@@ -14,41 +20,92 @@ import { TagFieldParser } from './tag-field-parser';
import { TextareaFieldParser } from './textarea-field-parser';
import { DisabledFieldParser } from './disabled-field-parser';
+const fieldParserDeps = [
+ SUBMISSION_ID,
+ CONFIG_DATA,
+ INIT_FORM_VALUES,
+ PARSER_OPTIONS,
+];
+
export class ParserFactory {
- public static getConstructor(type: ParserType): GenericConstructor {
+ public static getProvider(type: ParserType): StaticProvider {
switch (type) {
case ParserType.Date: {
- return DateFieldParser
+ return {
+ provide: FieldParser,
+ useClass: DateFieldParser,
+ deps: [...fieldParserDeps]
+ }
}
case ParserType.Dropdown: {
- return DropdownFieldParser
+ return {
+ provide: FieldParser,
+ useClass: DropdownFieldParser,
+ deps: [...fieldParserDeps]
+ }
}
case ParserType.RelationGroup: {
- return RelationGroupFieldParser
+ return {
+ provide: FieldParser,
+ useClass: RelationGroupFieldParser,
+ deps: [...fieldParserDeps]
+ }
}
case ParserType.List: {
- return ListFieldParser
+ return {
+ provide: FieldParser,
+ useClass: ListFieldParser,
+ deps: [...fieldParserDeps]
+ }
}
case ParserType.Lookup: {
- return LookupFieldParser
+ return {
+ provide: FieldParser,
+ useClass: LookupFieldParser,
+ deps: [...fieldParserDeps]
+ }
}
case ParserType.LookupName: {
- return LookupNameFieldParser
+ return {
+ provide: FieldParser,
+ useClass: LookupNameFieldParser,
+ deps: [...fieldParserDeps]
+ }
}
case ParserType.Onebox: {
- return OneboxFieldParser
+ return {
+ provide: FieldParser,
+ useClass: OneboxFieldParser,
+ deps: [...fieldParserDeps]
+ }
}
case ParserType.Name: {
- return NameFieldParser
+ return {
+ provide: FieldParser,
+ useClass: NameFieldParser,
+ deps: [...fieldParserDeps]
+ }
}
case ParserType.Series: {
- return SeriesFieldParser
+ return {
+ provide: FieldParser,
+ useClass: SeriesFieldParser,
+ deps: [...fieldParserDeps]
+ }
}
case ParserType.Tag: {
- return TagFieldParser
+ return {
+ provide: FieldParser,
+ useClass: TagFieldParser,
+ deps: [...fieldParserDeps]
+ }
}
case ParserType.Textarea: {
- return TextareaFieldParser
+ return {
+ provide: FieldParser,
+ useClass: TextareaFieldParser,
+ deps: [...fieldParserDeps]
+ }
}
case undefined: {
return DisabledFieldParser
diff --git a/src/app/shared/form/builder/parsers/relation-group-field-parser.spec.ts b/src/app/shared/form/builder/parsers/relation-group-field-parser.spec.ts
index 63489e7809..84f3df0365 100644
--- a/src/app/shared/form/builder/parsers/relation-group-field-parser.spec.ts
+++ b/src/app/shared/form/builder/parsers/relation-group-field-parser.spec.ts
@@ -3,12 +3,12 @@ import { RelationGroupFieldParser } from './relation-group-field-parser';
import { DynamicRelationGroupModel } from '../ds-dynamic-form-ui/models/relation-group/dynamic-relation-group.model';
import { FormFieldMetadataValueObject } from '../models/form-field-metadata-value.model';
import { ParserOptions } from './parser-options';
-import { WorkspaceItem } from '../../../../core/submission/models/workspaceitem.model';
describe('RelationGroupFieldParser test suite', () => {
let field: FormFieldModel;
let initFormValues = {};
+ const submissionId = '1234';
const parserOptions: ParserOptions = {
readOnly: false,
submissionScope: 'testScopeUUID',
@@ -72,13 +72,13 @@ describe('RelationGroupFieldParser test suite', () => {
});
it('should init parser properly', () => {
- const parser = new RelationGroupFieldParser(field, initFormValues, parserOptions, new WorkspaceItem());
+ const parser = new RelationGroupFieldParser(submissionId, field, initFormValues, parserOptions);
expect(parser instanceof RelationGroupFieldParser).toBe(true);
});
it('should return a DynamicRelationGroupModel object', () => {
- const parser = new RelationGroupFieldParser(field, initFormValues, parserOptions, new WorkspaceItem());
+ const parser = new RelationGroupFieldParser(submissionId, field, initFormValues, parserOptions);
const fieldModel = parser.parse();
@@ -87,7 +87,7 @@ describe('RelationGroupFieldParser test suite', () => {
it('should throw when rows configuration is empty', () => {
field.rows = null;
- const parser = new RelationGroupFieldParser(field, initFormValues, parserOptions, new WorkspaceItem());
+ const parser = new RelationGroupFieldParser(submissionId, field, initFormValues, parserOptions);
expect(() => parser.parse())
.toThrow();
@@ -98,7 +98,7 @@ describe('RelationGroupFieldParser test suite', () => {
author: [new FormFieldMetadataValueObject('test author')],
affiliation: [new FormFieldMetadataValueObject('test affiliation')]
};
- const parser = new RelationGroupFieldParser(field, initFormValues, parserOptions, new WorkspaceItem());
+ const parser = new RelationGroupFieldParser(submissionId, field, initFormValues, parserOptions);
const fieldModel = parser.parse();
const expectedValue = [{
diff --git a/src/app/shared/form/builder/parsers/relation-group-field-parser.ts b/src/app/shared/form/builder/parsers/relation-group-field-parser.ts
index b3f6e749f3..01699d9e78 100644
--- a/src/app/shared/form/builder/parsers/relation-group-field-parser.ts
+++ b/src/app/shared/form/builder/parsers/relation-group-field-parser.ts
@@ -15,6 +15,7 @@ export class RelationGroupFieldParser extends FieldParser {
public modelFactory(fieldValue?: FormFieldMetadataValueObject | any, label?: boolean) {
const modelConfiguration: DynamicRelationGroupModelConfig = this.initModel(null, label);
+ modelConfiguration.submissionId = this.submissionId;
modelConfiguration.scopeUUID = this.parserOptions.authorityUuid;
modelConfiguration.submissionScope = this.parserOptions.submissionScope;
if (this.configData && this.configData.rows && this.configData.rows.length > 0) {
diff --git a/src/app/shared/form/builder/parsers/row-parser.spec.ts b/src/app/shared/form/builder/parsers/row-parser.spec.ts
index ab762bc9b2..435c6a6426 100644
--- a/src/app/shared/form/builder/parsers/row-parser.spec.ts
+++ b/src/app/shared/form/builder/parsers/row-parser.spec.ts
@@ -3,7 +3,6 @@ import { RowParser } from './row-parser';
import { DynamicRowGroupModel } from '../ds-dynamic-form-ui/models/ds-dynamic-row-group-model';
import { DynamicRowArrayModel } from '../ds-dynamic-form-ui/models/ds-dynamic-row-array-model';
import { FormRowModel } from '../../../../core/config/models/config-submission-form.model';
-import { WorkspaceItem } from '../../../../core/submission/models/workspaceitem.model';
describe('RowParser test suite', () => {
@@ -18,6 +17,7 @@ describe('RowParser test suite', () => {
let row9: FormRowModel;
let row10: FormRowModel;
+ const submissionId = '1234';
const scopeUUID = 'testScopeUUID';
const initFormValues = {};
const submissionScope = 'WORKSPACE';
@@ -329,76 +329,98 @@ describe('RowParser test suite', () => {
});
it('should init parser properly', () => {
- let parser = new RowParser(row1, scopeUUID, initFormValues, new WorkspaceItem(), submissionScope, readOnly);
-
- expect(parser instanceof RowParser).toBe(true);
-
- parser = new RowParser(row2, scopeUUID, initFormValues, new WorkspaceItem(), submissionScope, readOnly);
-
- expect(parser instanceof RowParser).toBe(true);
-
- parser = new RowParser(row3, scopeUUID, initFormValues, new WorkspaceItem(), submissionScope, readOnly);
-
- expect(parser instanceof RowParser).toBe(true);
-
- parser = new RowParser(row4, scopeUUID, initFormValues, new WorkspaceItem(), submissionScope, readOnly);
-
- expect(parser instanceof RowParser).toBe(true);
-
- parser = new RowParser(row5, scopeUUID, initFormValues, new WorkspaceItem(), submissionScope, readOnly);
-
- expect(parser instanceof RowParser).toBe(true);
-
- parser = new RowParser(row6, scopeUUID, initFormValues, new WorkspaceItem(), submissionScope, readOnly);
-
- expect(parser instanceof RowParser).toBe(true);
-
- parser = new RowParser(row7, scopeUUID, initFormValues, new WorkspaceItem(), submissionScope, readOnly);
-
- expect(parser instanceof RowParser).toBe(true);
-
- parser = new RowParser(row8, scopeUUID, initFormValues, new WorkspaceItem(), submissionScope, readOnly);
-
- expect(parser instanceof RowParser).toBe(true);
-
- parser = new RowParser(row9, scopeUUID, initFormValues, new WorkspaceItem(), submissionScope, readOnly);
-
- expect(parser instanceof RowParser).toBe(true);
-
- parser = new RowParser(row10, scopeUUID, initFormValues, new WorkspaceItem(), submissionScope, readOnly);
+ const parser = new RowParser(undefined);
expect(parser instanceof RowParser).toBe(true);
});
- it('should return a DynamicRowGroupModel object', () => {
- const parser = new RowParser(row1, scopeUUID, initFormValues, new WorkspaceItem(), submissionScope, readOnly);
+ describe('parse', () => {
+ it('should return a DynamicRowGroupModel object', () => {
+ const parser = new RowParser(undefined);
- const rowModel = parser.parse();
+ const rowModel = parser.parse(submissionId, row1, scopeUUID, initFormValues, submissionScope, readOnly);
- expect(rowModel instanceof DynamicRowGroupModel).toBe(true);
- });
+ expect(rowModel instanceof DynamicRowGroupModel).toBe(true);
+ });
- it('should return a row with three fields', () => {
- const parser = new RowParser(row1, scopeUUID, initFormValues, new WorkspaceItem(), submissionScope, readOnly);
+ it('should return a row with three fields', () => {
+ const parser = new RowParser(undefined);
- const rowModel = parser.parse();
+ const rowModel = parser.parse(submissionId, row1, scopeUUID, initFormValues, submissionScope, readOnly);
- expect((rowModel as DynamicRowGroupModel).group.length).toBe(3);
- });
+ expect((rowModel as DynamicRowGroupModel).group.length).toBe(3);
+ });
- it('should return a DynamicRowArrayModel object', () => {
- const parser = new RowParser(row2, scopeUUID, initFormValues, new WorkspaceItem(), submissionScope, readOnly);
+ it('should return a DynamicRowArrayModel object', () => {
+ const parser = new RowParser(undefined);
- const rowModel = parser.parse();
+ const rowModel = parser.parse(submissionId, row2, scopeUUID, initFormValues, submissionScope, readOnly);
- expect(rowModel instanceof DynamicRowArrayModel).toBe(true);
- });
+ expect(rowModel instanceof DynamicRowArrayModel).toBe(true);
+ });
- it('should return a row that contains only scoped fields', () => {
- const parser = new RowParser(row3, scopeUUID, initFormValues, new WorkspaceItem(), submissionScope, readOnly);
+ it('should return a row that contains only scoped fields', () => {
+ const parser = new RowParser(undefined);
- const rowModel = parser.parse();
+ const rowModel = parser.parse(submissionId, row3, scopeUUID, initFormValues, submissionScope, readOnly);
- expect((rowModel as DynamicRowGroupModel).group.length).toBe(1);
+ expect((rowModel as DynamicRowGroupModel).group.length).toBe(1);
+ });
+
+ it('should be able to parse a dropdown combo field', () => {
+ const parser = new RowParser(undefined);
+
+ const rowModel = parser.parse(submissionId, row4, scopeUUID, initFormValues, submissionScope, readOnly);
+
+ expect(rowModel).toBeDefined();
+ });
+
+ it('should be able to parse a lookup-name field', () => {
+ const parser = new RowParser(undefined);
+
+ const rowModel = parser.parse(submissionId, row5, scopeUUID, initFormValues, submissionScope, readOnly);
+
+ expect(rowModel).toBeDefined();
+ });
+
+ it('should be able to parse a list field', () => {
+ const parser = new RowParser(undefined);
+
+ const rowModel = parser.parse(submissionId, row6, scopeUUID, initFormValues, submissionScope, readOnly);
+
+ expect(rowModel).toBeDefined();
+ });
+
+ it('should be able to parse a date field', () => {
+ const parser = new RowParser(undefined);
+
+ const rowModel = parser.parse(submissionId, row7, scopeUUID, initFormValues, submissionScope, readOnly);
+
+ expect(rowModel).toBeDefined();
+ });
+
+ it('should be able to parse a tag field', () => {
+ const parser = new RowParser(undefined);
+
+ const rowModel = parser.parse(submissionId, row8, scopeUUID, initFormValues, submissionScope, readOnly);
+
+ expect(rowModel).toBeDefined();
+ });
+
+ it('should be able to parse a textarea field', () => {
+ const parser = new RowParser(undefined);
+
+ const rowModel = parser.parse(submissionId, row9, scopeUUID, initFormValues, submissionScope, readOnly);
+
+ expect(rowModel).toBeDefined();
+ });
+
+ it('should be able to parse a group field', () => {
+ const parser = new RowParser(undefined);
+
+ const rowModel = parser.parse(submissionId, row10, scopeUUID, initFormValues, submissionScope, readOnly);
+
+ expect(rowModel).toBeDefined();
+ });
});
});
diff --git a/src/app/shared/form/builder/parsers/row-parser.ts b/src/app/shared/form/builder/parsers/row-parser.ts
index 7291b62322..72737cfaa9 100644
--- a/src/app/shared/form/builder/parsers/row-parser.ts
+++ b/src/app/shared/form/builder/parsers/row-parser.ts
@@ -1,32 +1,42 @@
-import { DYNAMIC_FORM_CONTROL_TYPE_ARRAY, DynamicFormGroupModelConfig } from '@ng-dynamic-forms/core';
+import { Injectable, Injector } from '@angular/core';
+import {
+ DYNAMIC_FORM_CONTROL_TYPE_ARRAY,
+ DynamicFormGroupModelConfig
+} from '@ng-dynamic-forms/core';
import { uniqueId } from 'lodash';
import { IntegrationSearchOptions } from '../../../../core/integration/models/integration-options.model';
-import { DYNAMIC_FORM_CONTROL_TYPE_RELATION_GROUP } from '../ds-dynamic-form-ui/models/relation-group/dynamic-relation-group.model';
-import { DynamicRowGroupModel } from '../ds-dynamic-form-ui/models/ds-dynamic-row-group-model';
import { isEmpty } from '../../../empty.util';
-import { setLayout } from './parser.utils';
+import { DynamicRowGroupModel } from '../ds-dynamic-form-ui/models/ds-dynamic-row-group-model';
+import { DYNAMIC_FORM_CONTROL_TYPE_RELATION_GROUP } from '../ds-dynamic-form-ui/models/relation-group/dynamic-relation-group.model';
import { FormFieldModel } from '../models/form-field.model';
-import { ParserType } from './parser-type';
-import { ParserOptions } from './parser-options';
+import {
+ CONFIG_DATA,
+ FieldParser,
+ INIT_FORM_VALUES,
+ PARSER_OPTIONS,
+ SUBMISSION_ID
+} from './field-parser';
import { ParserFactory } from './parser-factory';
-import { WorkspaceItem } from '../../../../core/submission/models/workspaceitem.model';
+import { ParserOptions } from './parser-options';
+import { ParserType } from './parser-type';
+import { setLayout } from './parser.utils';
export const ROW_ID_PREFIX = 'df-row-group-config-';
+@Injectable({
+ providedIn: 'root'
+})
export class RowParser {
- protected authorityOptions: IntegrationSearchOptions;
-
- constructor(protected rowData,
- protected scopeUUID,
- protected initFormValues: any,
- protected wsi: WorkspaceItem,
- protected submissionScope,
- protected readOnly: boolean) {
- this.authorityOptions = new IntegrationSearchOptions(scopeUUID);
+ constructor(private parentInjector: Injector) {
}
- public parse(): DynamicRowGroupModel {
+ public parse(submissionId: string,
+ rowData,
+ scopeUUID,
+ initFormValues: any,
+ submissionScope,
+ readOnly: boolean): DynamicRowGroupModel {
let fieldModel: any = null;
let parsedResult = null;
const config: DynamicFormGroupModelConfig = {
@@ -34,31 +44,44 @@ export class RowParser {
group: [],
};
- const scopedFields: FormFieldModel[] = this.filterScopedFields(this.rowData.fields);
+ const authorityOptions = new IntegrationSearchOptions(scopeUUID);
+
+ const scopedFields: FormFieldModel[] = this.filterScopedFields(rowData.fields, submissionScope);
const layoutDefaultGridClass = ' col-sm-' + Math.trunc(12 / scopedFields.length);
const layoutClass = ' d-flex flex-column justify-content-start';
const parserOptions: ParserOptions = {
- readOnly: this.readOnly,
- submissionScope: this.submissionScope,
- authorityUuid: this.authorityOptions.uuid
+ readOnly: readOnly,
+ submissionScope: submissionScope,
+ authorityUuid: authorityOptions.uuid
};
// Iterate over row's fields
scopedFields.forEach((fieldData: FormFieldModel) => {
const layoutFieldClass = (fieldData.style || layoutDefaultGridClass) + layoutClass;
- const parserCo = ParserFactory.getConstructor(fieldData.input.type as ParserType);
- if (parserCo) {
- fieldModel = new parserCo(fieldData, this.initFormValues, parserOptions, this.wsi).parse();
+ const parserProvider = ParserFactory.getProvider(fieldData.input.type as ParserType);
+ if (parserProvider) {
+ const fieldInjector = Injector.create({
+ providers: [
+ parserProvider,
+ { provide: SUBMISSION_ID, useValue: submissionId },
+ { provide: CONFIG_DATA, useValue: fieldData },
+ { provide: INIT_FORM_VALUES, useValue: initFormValues },
+ { provide: PARSER_OPTIONS, useValue: parserOptions }
+ ],
+ parent: this.parentInjector
+ });
+
+ fieldModel = fieldInjector.get(FieldParser).parse();
} else {
- throw new Error(`unknown form control model type "${fieldData.input.type}" defined for Input field with label "${fieldData.label}".`, );
+ throw new Error(`unknown form control model type "${fieldData.input.type}" defined for Input field with label "${fieldData.label}".`,);
}
if (fieldModel) {
if (fieldModel.type === DYNAMIC_FORM_CONTROL_TYPE_ARRAY || fieldModel.type === DYNAMIC_FORM_CONTROL_TYPE_RELATION_GROUP) {
- if (this.rowData.fields.length > 1) {
+ if (rowData.fields.length > 1) {
setLayout(fieldModel, 'grid', 'host', layoutFieldClass);
config.group.push(fieldModel);
// if (isEmpty(parsedResult)) {
@@ -100,15 +123,15 @@ export class RowParser {
return parsedResult;
}
- checksFieldScope(fieldScope) {
- return (isEmpty(fieldScope) || isEmpty(this.submissionScope) || fieldScope === this.submissionScope);
+ checksFieldScope(fieldScope, submissionScope) {
+ return (isEmpty(fieldScope) || isEmpty(submissionScope) || fieldScope === submissionScope);
}
- filterScopedFields(fields: FormFieldModel[]): FormFieldModel[] {
+ filterScopedFields(fields: FormFieldModel[], submissionScope): FormFieldModel[] {
const filteredFields: FormFieldModel[] = [];
fields.forEach((field: FormFieldModel) => {
// Whether field scope doesn't match the submission scope, skip it
- if (this.checksFieldScope(field.scope)) {
+ if (this.checksFieldScope(field.scope, submissionScope)) {
filteredFields.push(field);
}
});
diff --git a/src/app/shared/form/builder/parsers/series-field-parser.spec.ts b/src/app/shared/form/builder/parsers/series-field-parser.spec.ts
index 7b0f8a3bb3..ceb4e96320 100644
--- a/src/app/shared/form/builder/parsers/series-field-parser.spec.ts
+++ b/src/app/shared/form/builder/parsers/series-field-parser.spec.ts
@@ -3,12 +3,12 @@ import { DynamicConcatModel } from '../ds-dynamic-form-ui/models/ds-dynamic-conc
import { SeriesFieldParser } from './series-field-parser';
import { FormFieldMetadataValueObject } from '../models/form-field-metadata-value.model';
import { ParserOptions } from './parser-options';
-import { WorkspaceItem } from '../../../../core/submission/models/workspaceitem.model';
describe('SeriesFieldParser test suite', () => {
let field: FormFieldModel;
let initFormValues: any = {};
+ const submissionId = '1234';
const parserOptions: ParserOptions = {
readOnly: false,
submissionScope: 'testScopeUUID',
@@ -33,13 +33,13 @@ describe('SeriesFieldParser test suite', () => {
});
it('should init parser properly', () => {
- const parser = new SeriesFieldParser(field, initFormValues, parserOptions, new WorkspaceItem());
+ const parser = new SeriesFieldParser(submissionId, field, initFormValues, parserOptions);
expect(parser instanceof SeriesFieldParser).toBe(true);
});
it('should return a DynamicConcatModel object when repeatable option is false', () => {
- const parser = new SeriesFieldParser(field, initFormValues, parserOptions, new WorkspaceItem());
+ const parser = new SeriesFieldParser(submissionId, field, initFormValues, parserOptions);
const fieldModel = parser.parse();
@@ -47,7 +47,7 @@ describe('SeriesFieldParser test suite', () => {
});
it('should return a DynamicConcatModel object with the correct separator', () => {
- const parser = new SeriesFieldParser(field, initFormValues, parserOptions, new WorkspaceItem());
+ const parser = new SeriesFieldParser(submissionId, field, initFormValues, parserOptions);
const fieldModel = parser.parse();
@@ -60,7 +60,7 @@ describe('SeriesFieldParser test suite', () => {
};
const expectedValue = new FormFieldMetadataValueObject('test; series');
- const parser = new SeriesFieldParser(field, initFormValues, parserOptions, new WorkspaceItem());
+ const parser = new SeriesFieldParser(submissionId, field, initFormValues, parserOptions);
const fieldModel = parser.parse();
diff --git a/src/app/shared/form/builder/parsers/series-field-parser.ts b/src/app/shared/form/builder/parsers/series-field-parser.ts
index 37db1cd15c..36ee9c36c1 100644
--- a/src/app/shared/form/builder/parsers/series-field-parser.ts
+++ b/src/app/shared/form/builder/parsers/series-field-parser.ts
@@ -1,11 +1,17 @@
+import { Inject } from '@angular/core';
import { FormFieldModel } from '../models/form-field.model';
import { ConcatFieldParser } from './concat-field-parser';
+import { CONFIG_DATA, INIT_FORM_VALUES, PARSER_OPTIONS, SUBMISSION_ID } from './field-parser';
import { ParserOptions } from './parser-options';
-import { WorkspaceItem } from '../../../../core/submission/models/workspaceitem.model';
export class SeriesFieldParser extends ConcatFieldParser {
- constructor(protected configData: FormFieldModel, protected initFormValues, protected parserOptions: ParserOptions, wsi: WorkspaceItem) {
- super(configData, initFormValues, parserOptions, ';', wsi);
+ constructor(
+ @Inject(SUBMISSION_ID) submissionId: string,
+ @Inject(CONFIG_DATA) configData: FormFieldModel,
+ @Inject(INIT_FORM_VALUES) initFormValues,
+ @Inject(PARSER_OPTIONS) parserOptions: ParserOptions
+ ) {
+ super(submissionId, configData, initFormValues, parserOptions, ';');
}
}
diff --git a/src/app/shared/form/builder/parsers/tag-field-parser.spec.ts b/src/app/shared/form/builder/parsers/tag-field-parser.spec.ts
index 7466dd456f..90449e62e5 100644
--- a/src/app/shared/form/builder/parsers/tag-field-parser.spec.ts
+++ b/src/app/shared/form/builder/parsers/tag-field-parser.spec.ts
@@ -3,12 +3,12 @@ import { FormFieldMetadataValueObject } from '../models/form-field-metadata-valu
import { TagFieldParser } from './tag-field-parser';
import { DynamicTagModel } from '../ds-dynamic-form-ui/models/tag/dynamic-tag.model';
import { ParserOptions } from './parser-options';
-import { WorkspaceItem } from '../../../../core/submission/models/workspaceitem.model';
describe('TagFieldParser test suite', () => {
let field: FormFieldModel;
let initFormValues: any = {};
+ const submissionId = '1234';
const parserOptions: ParserOptions = {
readOnly: false,
submissionScope: 'testScopeUUID',
@@ -37,13 +37,13 @@ describe('TagFieldParser test suite', () => {
});
it('should init parser properly', () => {
- const parser = new TagFieldParser(field, initFormValues, parserOptions, new WorkspaceItem());
+ const parser = new TagFieldParser(submissionId, field, initFormValues, parserOptions);
expect(parser instanceof TagFieldParser).toBe(true);
});
it('should return a DynamicTagModel object when repeatable option is false', () => {
- const parser = new TagFieldParser(field, initFormValues, parserOptions, new WorkspaceItem());
+ const parser = new TagFieldParser(submissionId, field, initFormValues, parserOptions);
const fieldModel = parser.parse();
@@ -58,7 +58,7 @@ describe('TagFieldParser test suite', () => {
],
};
- const parser = new TagFieldParser(field, initFormValues, parserOptions, new WorkspaceItem());
+ const parser = new TagFieldParser(submissionId, field, initFormValues, parserOptions);
const fieldModel = parser.parse();
diff --git a/src/app/shared/form/builder/parsers/textarea-field-parser.spec.ts b/src/app/shared/form/builder/parsers/textarea-field-parser.spec.ts
index 056ab29b6a..167f126cf2 100644
--- a/src/app/shared/form/builder/parsers/textarea-field-parser.spec.ts
+++ b/src/app/shared/form/builder/parsers/textarea-field-parser.spec.ts
@@ -3,12 +3,12 @@ import { FormFieldMetadataValueObject } from '../models/form-field-metadata-valu
import { TextareaFieldParser } from './textarea-field-parser';
import { DsDynamicTextAreaModel } from '../ds-dynamic-form-ui/models/ds-dynamic-textarea.model';
import { ParserOptions } from './parser-options';
-import { WorkspaceItem } from '../../../../core/submission/models/workspaceitem.model';
describe('TextareaFieldParser test suite', () => {
let field: FormFieldModel;
let initFormValues: any = {};
+ const submissionId = '1234';
const parserOptions: ParserOptions = {
readOnly: false,
submissionScope: null,
@@ -35,13 +35,13 @@ describe('TextareaFieldParser test suite', () => {
});
it('should init parser properly', () => {
- const parser = new TextareaFieldParser(field, initFormValues, parserOptions, new WorkspaceItem());
+ const parser = new TextareaFieldParser(submissionId, field, initFormValues, parserOptions);
expect(parser instanceof TextareaFieldParser).toBe(true);
});
it('should return a DsDynamicTextAreaModel object when repeatable option is false', () => {
- const parser = new TextareaFieldParser(field, initFormValues, parserOptions, new WorkspaceItem());
+ const parser = new TextareaFieldParser(submissionId, field, initFormValues, parserOptions);
const fieldModel = parser.parse();
@@ -56,7 +56,7 @@ describe('TextareaFieldParser test suite', () => {
};
const expectedValue ='test description';
- const parser = new TextareaFieldParser(field, initFormValues, parserOptions, new WorkspaceItem());
+ const parser = new TextareaFieldParser(submissionId, field, initFormValues, parserOptions);
const fieldModel = parser.parse();
diff --git a/src/app/shared/mocks/mock-form-models.ts b/src/app/shared/mocks/mock-form-models.ts
index 96647d654e..ae5a97ca65 100644
--- a/src/app/shared/mocks/mock-form-models.ts
+++ b/src/app/shared/mocks/mock-form-models.ts
@@ -118,6 +118,7 @@ const mockFormRowModel = {
} as FormRowModel;
const relationGroupConfig = {
+ submissionId: '1234',
id: 'relationGroup',
formConfiguration: [mockFormRowModel],
mandatoryField: 'false',
diff --git a/src/app/shared/shared.module.ts b/src/app/shared/shared.module.ts
index e21291dabd..a28a35c99d 100644
--- a/src/app/shared/shared.module.ts
+++ b/src/app/shared/shared.module.ts
@@ -30,6 +30,7 @@ import { AbstractListableElementComponent } from './object-collection/shared/obj
import { ObjectGridComponent } from './object-grid/object-grid.component';
import { ObjectCollectionComponent } from './object-collection/object-collection.component';
import { ComcolPageContentComponent } from './comcol-page-content/comcol-page-content.component';
+import { ComcolPageHandleComponent } from './comcol-page-handle/comcol-page-handle.component';
import { ComcolPageHeaderComponent } from './comcol-page-header/comcol-page-header.component';
import { ComcolPageLogoComponent } from './comcol-page-logo/comcol-page-logo.component';
import { ErrorComponent } from './error/error.component';
@@ -215,6 +216,7 @@ const COMPONENTS = [
UserMenuComponent,
ChipsComponent,
ComcolPageContentComponent,
+ ComcolPageHandleComponent,
ComcolPageHeaderComponent,
ComcolPageLogoComponent,
ComColFormComponent,
diff --git a/src/app/submission/form/submission-form.component.ts b/src/app/submission/form/submission-form.component.ts
index b592972839..1732075bf8 100644
--- a/src/app/submission/form/submission-form.component.ts
+++ b/src/app/submission/form/submission-form.component.ts
@@ -1,7 +1,7 @@
import { ChangeDetectorRef, Component, Input, OnChanges, OnDestroy, SimpleChanges } from '@angular/core';
import { of as observableOf, Observable, Subscription } from 'rxjs';
-import { distinctUntilChanged, filter, flatMap, map } from 'rxjs/operators';
+import { distinctUntilChanged, filter, flatMap, map, switchMap } from 'rxjs/operators';
import { hasValue, isNotEmpty } from '../../shared/empty.util';
import { SubmissionObjectEntry } from '../objects/submission-objects.reducer';
@@ -125,7 +125,7 @@ export class SubmissionFormComponent implements OnChanges, OnDestroy {
map((submission: SubmissionObjectEntry) => submission.isLoading),
map((isLoading: boolean) => isLoading),
distinctUntilChanged(),
- flatMap((isLoading: boolean) => {
+ switchMap((isLoading: boolean) => {
if (!isLoading) {
return this.getSectionsList();
} else {
diff --git a/src/app/submission/sections/form/section-form.component.ts b/src/app/submission/sections/form/section-form.component.ts
index f9b3ff78b0..dcf1aac29d 100644
--- a/src/app/submission/sections/form/section-form.component.ts
+++ b/src/app/submission/sections/form/section-form.component.ts
@@ -229,6 +229,7 @@ export class SubmissionSectionformComponent extends SectionModelComponent {
initForm(sectionData: WorkspaceitemSectionFormObject): void {
try {
this.formModel = this.formBuilderService.modelFromConfiguration(
+ this.submissionId,
this.formConfig,
this.collectionId,
sectionData,
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 8040b7d818..cde004f4b6 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
@@ -166,6 +166,7 @@ export class SubmissionSectionUploadFileEditComponent implements OnChanges {
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,