diff --git a/resources/i18n/en.json b/resources/i18n/en.json index 76e925f1a2..2aeac293e4 100644 --- a/resources/i18n/en.json +++ b/resources/i18n/en.json @@ -42,7 +42,20 @@ }, "source": { "title": "Collection Edit - Content Source", - "head": "Content Source" + "head": "Content Source", + "external": "This collection harvests its content from an external source", + "form": { + "head": "Configure an external source", + "provider": "OAI Provider", + "set": "OAI specific set id", + "format": "Metadata Format", + "harvest": "Content being harvested", + "errors": { + "provider": { + "required": "You must provide a set id of the target collection." + } + } + } }, "curate": { "title": "Collection Edit - Curate", diff --git a/src/app/+collection-page/edit-collection-page/collection-source/collection-source.component.html b/src/app/+collection-page/edit-collection-page/collection-source/collection-source.component.html index 5837a9ed72..51a652056b 100644 --- a/src/app/+collection-page/edit-collection-page/collection-source/collection-source.component.html +++ b/src/app/+collection-page/edit-collection-page/collection-source/collection-source.component.html @@ -1,7 +1,16 @@ -

Content source

-
- - +
+

{{ 'collection.edit.tabs.source.head' | translate }}

+
+ + +
+

{{ 'collection.edit.tabs.source.form.head' | translate }}

-

Configure an external source

- + diff --git a/src/app/+collection-page/edit-collection-page/collection-source/collection-source.component.ts b/src/app/+collection-page/edit-collection-page/collection-source/collection-source.component.ts index 7e167805c1..cdff87c6ac 100644 --- a/src/app/+collection-page/edit-collection-page/collection-source/collection-source.component.ts +++ b/src/app/+collection-page/edit-collection-page/collection-source/collection-source.component.ts @@ -1,6 +1,23 @@ -import { Component } from '@angular/core'; +import { Component, OnInit } from '@angular/core'; import { AbstractTrackableComponent } from '../../../shared/trackable/abstract-trackable.component'; -import { DynamicFormControlModel, DynamicInputModel, DynamicTextAreaModel } from '@ng-dynamic-forms/core'; +import { + DynamicFormControlModel, DynamicFormGroupModel, DynamicFormLayout, DynamicFormService, + DynamicInputModel, DynamicRadioGroupModel, + DynamicSelectModel, + DynamicTextAreaModel +} from '@ng-dynamic-forms/core'; +import { Location } from '@angular/common'; +import { TranslateService } from '@ngx-translate/core'; +import { ObjectUpdatesService } from '../../../core/data/object-updates/object-updates.service'; +import { NotificationsService } from '../../../shared/notifications/notifications.service'; +import { FormGroup } from '@angular/forms'; +import { isNotEmpty } from '../../../shared/empty.util'; +import { ContentSource } from '../../../core/shared/content-source.model'; +import { Observable } from 'rxjs/internal/Observable'; +import { RemoteData } from '../../../core/data/remote-data'; +import { Collection } from '../../../core/shared/collection.model'; +import { first, map } from 'rxjs/operators'; +import { ActivatedRoute } from '@angular/router'; /** * Component for managing the content source of the collection @@ -9,28 +26,225 @@ import { DynamicFormControlModel, DynamicInputModel, DynamicTextAreaModel } from selector: 'ds-collection-source', templateUrl: './collection-source.component.html', }) -export class CollectionSourceComponent extends AbstractTrackableComponent { - externalSource = false; +export class CollectionSourceComponent extends AbstractTrackableComponent implements OnInit { + /** + * The current collection's remote data + */ + collectionRD$: Observable>; /** - * The dynamic form fields used for creating/editing a collection + * The current collection's content source + */ + contentSource: ContentSource; + + /** + * @type {string} Key prefix used to generate form labels + */ + LABEL_KEY_PREFIX = 'collection.edit.tabs.source.form.'; + + /** + * @type {string} Key prefix used to generate form error messages + */ + ERROR_KEY_PREFIX = 'collection.edit.tabs.source.form.errors.'; + + /** + * The dynamic form fields used for editing the content source of a collection * @type {(DynamicInputModel | DynamicTextAreaModel)[]} */ formModel: DynamicFormControlModel[] = [ - new DynamicInputModel({ - id: 'title', - name: 'dc.title', - required: true, - validators: { - required: null - }, - errorMessages: { - required: 'Please enter a name for this title' - }, + new DynamicFormGroupModel({ + id: 'providerContainer', + group: [ + new DynamicInputModel({ + id: 'provider', + name: 'provider', + required: true, + validators: { + required: null + }, + errorMessages: { + required: 'You must provide a set id of the target collection.' + }, + disabled: true + }) + ] }), - new DynamicTextAreaModel({ - id: 'provider', - name: 'provider', + new DynamicFormGroupModel({ + id: 'setContainer', + group: [ + new DynamicInputModel({ + id: 'set', + name: 'set', + disabled: true + }), + new DynamicSelectModel({ + id: 'format', + name: 'format', + value: 'dc', + options: [ + { + value: 'dc', + label: 'Simple Dublin Core' + }, + { + value: 'qdc', + label: 'Qualified Dublin Core' + }, + { + value: 'dim', + label: 'DSpace Intermediate Metadata' + } + ], + disabled: true + }) + ] + }), + new DynamicFormGroupModel({ + id: 'harvestContainer', + group: [ + new DynamicRadioGroupModel({ + id: 'harvest', + name: 'harvest', + value: 3, + options: [ + { + value: 1, + label: 'Harvest metadata only.' + }, + { + value: 2, + label: 'Harvest metadata and references to bitstreams (requires ORE support).' + }, + { + value: 3, + label: 'Harvest metadata and bitstreams (requires ORE support).' + } + ] + }) + ] }) ]; + + /** + * Layout used for structuring the form inputs + */ + formLayout: DynamicFormLayout = { + provider: { + grid: { + host: 'col-12 d-inline-block' + } + }, + set: { + grid: { + host: 'col col-sm-6 d-inline-block' + } + }, + format: { + grid: { + host: 'col col-sm-6 d-inline-block' + } + }, + harvest: { + grid: { + host: 'col-12' + } + }, + setContainer: { + grid: { + host: 'row' + } + }, + providerContainer: { + grid: { + host: 'row' + } + }, + harvestContainer: { + grid: { + host: 'row' + } + } + }; + + /** + * The form group of this form + */ + formGroup: FormGroup; + + public constructor(public objectUpdatesService: ObjectUpdatesService, + public notificationsService: NotificationsService, + protected location: Location, + protected formService: DynamicFormService, + protected translate: TranslateService, + protected route: ActivatedRoute) { + super(objectUpdatesService, notificationsService, translate); + } + + ngOnInit(): void { + this.formGroup = this.formService.createFormGroup(this.formModel); + this.collectionRD$ = this.route.parent.data.pipe(first(), map((data) => data.dso)); + + /* Create a new ContentSource object - TODO: Update to be fetched from the collection */ + this.contentSource = new ContentSource(); + + this.updateFieldTranslations(); + this.translate.onLangChange + .subscribe(() => { + this.updateFieldTranslations(); + }); + } + + /** + * Used the update translations of errors and labels on init and on language change + */ + private updateFieldTranslations() { + this.formModel.forEach( + (fieldModel: DynamicFormControlModel) => { + if (fieldModel instanceof DynamicFormGroupModel) { + fieldModel.group.forEach((childModel: DynamicFormControlModel) => { + this.updateFieldTranslation(childModel); + }); + } else { + this.updateFieldTranslation(fieldModel); + } + } + ); + } + + /** + * Update the translations of a DynamicInputModel + * @param fieldModel + */ + private updateFieldTranslation(fieldModel: DynamicFormControlModel) { + fieldModel.label = this.translate.instant(this.LABEL_KEY_PREFIX + fieldModel.id); + if (isNotEmpty(fieldModel.validators)) { + fieldModel.errorMessages = {}; + Object.keys(fieldModel.validators).forEach((key) => { + fieldModel.errorMessages[key] = this.translate.instant(this.ERROR_KEY_PREFIX + fieldModel.id + '.' + key); + }); + } + } + + onChange(event) { + // TODO: Update ContentSource object and add to field update + console.log(event); + } + + onSubmit() { + // TODO: Fetch field update and send to REST API + console.log('submit'); + } + + onCancel() { + this.location.back(); + } + + changeExternalSource() { + this.contentSource.enabled = !this.contentSource.enabled; + if (this.contentSource.enabled) { + this.formGroup.enable(); + } else { + this.formGroup.disable(); + } + } } diff --git a/src/app/core/shared/content-source.model.ts b/src/app/core/shared/content-source.model.ts new file mode 100644 index 0000000000..10f0986b1b --- /dev/null +++ b/src/app/core/shared/content-source.model.ts @@ -0,0 +1,19 @@ +import { v4 as uuid } from 'uuid'; + +export class ContentSource { + uuid: string; + + enabled = false; + + provider: string; + + set: string; + + format: string; + + harvestType: number; + + constructor() { + this.uuid = uuid(); + } +}