mirror of
https://github.com/DSpace/dspace-angular.git
synced 2025-10-08 02:24:11 +00:00
Added more comments
This commit is contained in:
@@ -743,7 +743,7 @@
|
|||||||
"upload-successful": "Upload successful",
|
"upload-successful": "Upload successful",
|
||||||
"upload-failed": "Upload failed",
|
"upload-failed": "Upload failed",
|
||||||
"header.policy.default.nolist": "Uploaded files in the {{collectionName}} collection will be accessible according to the following group(s):",
|
"header.policy.default.nolist": "Uploaded files in the {{collectionName}} collection will be accessible according to the following group(s):",
|
||||||
"header.policy.default.withlist": "Please note that uploaded files in the {{collectionName}} collection will be accessible, in addition to what is explicity decided for the single file, with the following group(s):",
|
"header.policy.default.withlist": "Please note that uploaded files in the {{collectionName}} collection will be accessible, in addition to what is explicitly decided for the single file, with the following group(s):",
|
||||||
"form": {
|
"form": {
|
||||||
"access-condition-label": "Access condition type",
|
"access-condition-label": "Access condition type",
|
||||||
"from-label": "Access grant from",
|
"from-label": "Access grant from",
|
||||||
|
@@ -14,17 +14,44 @@ import { SubmissionObject } from '../../core/submission/models/submission-object
|
|||||||
import { Collection } from '../../core/shared/collection.model';
|
import { Collection } from '../../core/shared/collection.model';
|
||||||
import { RemoteData } from '../../core/data/remote-data';
|
import { RemoteData } from '../../core/data/remote-data';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This component allows to edit an existing workspaceitem/workflowitem.
|
||||||
|
*/
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'ds-submission-edit',
|
selector: 'ds-submission-edit',
|
||||||
styleUrls: ['./submission-edit.component.scss'],
|
styleUrls: ['./submission-edit.component.scss'],
|
||||||
templateUrl: './submission-edit.component.html'
|
templateUrl: './submission-edit.component.html'
|
||||||
})
|
})
|
||||||
|
|
||||||
export class SubmissionEditComponent implements OnDestroy, OnInit {
|
export class SubmissionEditComponent implements OnDestroy, OnInit {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The collection id this submission belonging to
|
||||||
|
* @type {string}
|
||||||
|
*/
|
||||||
public collectionId: string;
|
public collectionId: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The list of submission's sections
|
||||||
|
* @type {WorkspaceitemSectionsObject}
|
||||||
|
*/
|
||||||
public sections: WorkspaceitemSectionsObject;
|
public sections: WorkspaceitemSectionsObject;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The submission self url
|
||||||
|
* @type {string}
|
||||||
|
*/
|
||||||
public selfUrl: string;
|
public selfUrl: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The configuration object that define this submission
|
||||||
|
* @type {SubmissionDefinitionsModel}
|
||||||
|
*/
|
||||||
public submissionDefinition: SubmissionDefinitionsModel;
|
public submissionDefinition: SubmissionDefinitionsModel;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The submission id
|
||||||
|
* @type {string}
|
||||||
|
*/
|
||||||
public submissionId: string;
|
public submissionId: string;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -33,6 +60,16 @@ export class SubmissionEditComponent implements OnDestroy, OnInit {
|
|||||||
*/
|
*/
|
||||||
private subs: Subscription[] = [];
|
private subs: Subscription[] = [];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize instance variables
|
||||||
|
*
|
||||||
|
* @param {ChangeDetectorRef} changeDetectorRef
|
||||||
|
* @param {NotificationsService} notificationsService
|
||||||
|
* @param {ActivatedRoute} route
|
||||||
|
* @param {Router} router
|
||||||
|
* @param {SubmissionService} submissionService
|
||||||
|
* @param {TranslateService} translate
|
||||||
|
*/
|
||||||
constructor(private changeDetectorRef: ChangeDetectorRef,
|
constructor(private changeDetectorRef: ChangeDetectorRef,
|
||||||
private notificationsService: NotificationsService,
|
private notificationsService: NotificationsService,
|
||||||
private route: ActivatedRoute,
|
private route: ActivatedRoute,
|
||||||
@@ -41,6 +78,9 @@ export class SubmissionEditComponent implements OnDestroy, OnInit {
|
|||||||
private translate: TranslateService) {
|
private translate: TranslateService) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve workspaceitem/workflowitem from server and initialize all instance variables
|
||||||
|
*/
|
||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
this.subs.push(this.route.paramMap.pipe(
|
this.subs.push(this.route.paramMap.pipe(
|
||||||
switchMap((params: ParamMap) => this.submissionService.retrieveSubmission(params.get('id'))),
|
switchMap((params: ParamMap) => this.submissionService.retrieveSubmission(params.get('id'))),
|
||||||
@@ -70,7 +110,7 @@ export class SubmissionEditComponent implements OnDestroy, OnInit {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Method provided by Angular. Invoked when the instance is destroyed.
|
* Unsubscribe from all subscriptions
|
||||||
*/
|
*/
|
||||||
ngOnDestroy() {
|
ngOnDestroy() {
|
||||||
this.subs
|
this.subs
|
||||||
|
@@ -36,24 +36,48 @@ import { SubmissionService } from '../../submission.service';
|
|||||||
import { SubmissionObject } from '../../../core/submission/models/submission-object.model';
|
import { SubmissionObject } from '../../../core/submission/models/submission-object.model';
|
||||||
import { SubmissionJsonPatchOperationsService } from '../../../core/submission/submission-json-patch-operations.service';
|
import { SubmissionJsonPatchOperationsService } from '../../../core/submission/submission-json-patch-operations.service';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An interface to represent a collection entry
|
||||||
|
*/
|
||||||
interface CollectionListEntryItem {
|
interface CollectionListEntryItem {
|
||||||
id: string;
|
id: string;
|
||||||
name: string;
|
name: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An interface to represent an entry in the collection list
|
||||||
|
*/
|
||||||
interface CollectionListEntry {
|
interface CollectionListEntry {
|
||||||
communities: CollectionListEntryItem[],
|
communities: CollectionListEntryItem[],
|
||||||
collection: CollectionListEntryItem
|
collection: CollectionListEntryItem
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This component allows to show the current collection the submission belonging to and to change it.
|
||||||
|
*/
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'ds-submission-form-collection',
|
selector: 'ds-submission-form-collection',
|
||||||
styleUrls: ['./submission-form-collection.component.scss'],
|
styleUrls: ['./submission-form-collection.component.scss'],
|
||||||
templateUrl: './submission-form-collection.component.html'
|
templateUrl: './submission-form-collection.component.html'
|
||||||
})
|
})
|
||||||
export class SubmissionFormCollectionComponent implements OnChanges, OnInit {
|
export class SubmissionFormCollectionComponent implements OnChanges, OnInit {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The current collection id this submission belonging to
|
||||||
|
* @type {string}
|
||||||
|
*/
|
||||||
@Input() currentCollectionId: string;
|
@Input() currentCollectionId: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The current configuration object that define this submission
|
||||||
|
* @type {SubmissionDefinitionsModel}
|
||||||
|
*/
|
||||||
@Input() currentDefinition: string;
|
@Input() currentDefinition: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The submission id
|
||||||
|
* @type {string}
|
||||||
|
*/
|
||||||
@Input() submissionId;
|
@Input() submissionId;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -62,18 +86,69 @@ export class SubmissionFormCollectionComponent implements OnChanges, OnInit {
|
|||||||
*/
|
*/
|
||||||
@Output() collectionChange: EventEmitter<SubmissionObject> = new EventEmitter<SubmissionObject>();
|
@Output() collectionChange: EventEmitter<SubmissionObject> = new EventEmitter<SubmissionObject>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A boolean representing if this dropdown button is disabled
|
||||||
|
* @type {BehaviorSubject<boolean>}
|
||||||
|
*/
|
||||||
public disabled$ = new BehaviorSubject<boolean>(true);
|
public disabled$ = new BehaviorSubject<boolean>(true);
|
||||||
public model: any;
|
|
||||||
|
/**
|
||||||
|
* The search form control
|
||||||
|
* @type {FormControl}
|
||||||
|
*/
|
||||||
public searchField: FormControl = new FormControl();
|
public searchField: FormControl = new FormControl();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The collection list obtained from a search
|
||||||
|
* @type {Observable<CollectionListEntry[]>}
|
||||||
|
*/
|
||||||
public searchListCollection$: Observable<CollectionListEntry[]>;
|
public searchListCollection$: Observable<CollectionListEntry[]>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The selected collection id
|
||||||
|
* @type {string}
|
||||||
|
*/
|
||||||
public selectedCollectionId: string;
|
public selectedCollectionId: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The selected collection name
|
||||||
|
* @type {Observable<string>}
|
||||||
|
*/
|
||||||
public selectedCollectionName$: Observable<string>;
|
public selectedCollectionName$: Observable<string>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The JsonPatchOperationPathCombiner object
|
||||||
|
* @type {JsonPatchOperationPathCombiner}
|
||||||
|
*/
|
||||||
protected pathCombiner: JsonPatchOperationPathCombiner;
|
protected pathCombiner: JsonPatchOperationPathCombiner;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A boolean representing if dropdown list is scrollable to the bottom
|
||||||
|
* @type {boolean}
|
||||||
|
*/
|
||||||
private scrollableBottom = false;
|
private scrollableBottom = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A boolean representing if dropdown list is scrollable to the top
|
||||||
|
* @type {boolean}
|
||||||
|
*/
|
||||||
private scrollableTop = false;
|
private scrollableTop = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Array to track all subscriptions and unsubscribe them onDestroy
|
||||||
|
* @type {Array}
|
||||||
|
*/
|
||||||
private subs: Subscription[] = [];
|
private subs: Subscription[] = [];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize instance variables
|
||||||
|
*
|
||||||
|
* @param {ChangeDetectorRef} cdr
|
||||||
|
* @param {CommunityDataService} communityDataService
|
||||||
|
* @param {JsonPatchOperationsBuilder} operationsBuilder
|
||||||
|
* @param {SubmissionJsonPatchOperationsService} operationsService
|
||||||
|
* @param {SubmissionService} submissionService
|
||||||
|
*/
|
||||||
constructor(protected cdr: ChangeDetectorRef,
|
constructor(protected cdr: ChangeDetectorRef,
|
||||||
private communityDataService: CommunityDataService,
|
private communityDataService: CommunityDataService,
|
||||||
private operationsBuilder: JsonPatchOperationsBuilder,
|
private operationsBuilder: JsonPatchOperationsBuilder,
|
||||||
@@ -81,6 +156,13 @@ export class SubmissionFormCollectionComponent implements OnChanges, OnInit {
|
|||||||
private submissionService: SubmissionService) {
|
private submissionService: SubmissionService) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method called on mousewheel event, it prevent the page scroll
|
||||||
|
* when arriving at the top/bottom of dropdown menu
|
||||||
|
*
|
||||||
|
* @param event
|
||||||
|
* mousewheel event
|
||||||
|
*/
|
||||||
@HostListener('mousewheel', ['$event']) onMousewheel(event) {
|
@HostListener('mousewheel', ['$event']) onMousewheel(event) {
|
||||||
if (event.wheelDelta > 0 && this.scrollableTop) {
|
if (event.wheelDelta > 0 && this.scrollableTop) {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
@@ -90,11 +172,19 @@ export class SubmissionFormCollectionComponent implements OnChanges, OnInit {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if dropdown scrollbar is at the top or bottom of the dropdown list
|
||||||
|
*
|
||||||
|
* @param event
|
||||||
|
*/
|
||||||
onScroll(event) {
|
onScroll(event) {
|
||||||
this.scrollableBottom = (event.target.scrollTop + event.target.clientHeight === event.target.scrollHeight);
|
this.scrollableBottom = (event.target.scrollTop + event.target.clientHeight === event.target.scrollHeight);
|
||||||
this.scrollableTop = (event.target.scrollTop === 0);
|
this.scrollableTop = (event.target.scrollTop === 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize collection list
|
||||||
|
*/
|
||||||
ngOnChanges(changes: SimpleChanges) {
|
ngOnChanges(changes: SimpleChanges) {
|
||||||
if (hasValue(changes.currentCollectionId)
|
if (hasValue(changes.currentCollectionId)
|
||||||
&& hasValue(changes.currentCollectionId.currentValue)) {
|
&& hasValue(changes.currentCollectionId.currentValue)) {
|
||||||
@@ -153,14 +243,26 @@ export class SubmissionFormCollectionComponent implements OnChanges, OnInit {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize all instance variables
|
||||||
|
*/
|
||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
this.pathCombiner = new JsonPatchOperationPathCombiner('sections', 'collection');
|
this.pathCombiner = new JsonPatchOperationPathCombiner('sections', 'collection');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unsubscribe from all subscriptions
|
||||||
|
*/
|
||||||
ngOnDestroy(): void {
|
ngOnDestroy(): void {
|
||||||
this.subs.filter((sub) => hasValue(sub)).forEach((sub) => sub.unsubscribe());
|
this.subs.filter((sub) => hasValue(sub)).forEach((sub) => sub.unsubscribe());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Emit a [collectionChange] event when a new collection is selected from list
|
||||||
|
*
|
||||||
|
* @param event
|
||||||
|
* the selected [CollectionListEntryItem]
|
||||||
|
*/
|
||||||
onSelect(event) {
|
onSelect(event) {
|
||||||
this.searchField.reset();
|
this.searchField.reset();
|
||||||
this.disabled$.next(true);
|
this.disabled$.next(true);
|
||||||
@@ -181,10 +283,19 @@ export class SubmissionFormCollectionComponent implements OnChanges, OnInit {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reset search form control on dropdown menu close
|
||||||
|
*/
|
||||||
onClose() {
|
onClose() {
|
||||||
this.searchField.reset();
|
this.searchField.reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reset search form control when dropdown menu is closed
|
||||||
|
*
|
||||||
|
* @param isOpen
|
||||||
|
* Representing if the dropdown menu is open or not.
|
||||||
|
*/
|
||||||
toggled(isOpen: boolean) {
|
toggled(isOpen: boolean) {
|
||||||
if (!isOpen) {
|
if (!isOpen) {
|
||||||
this.searchField.reset();
|
this.searchField.reset();
|
||||||
|
@@ -9,6 +9,9 @@ import { SubmissionService } from '../../submission.service';
|
|||||||
import { SubmissionScopeType } from '../../../core/submission/submission-scope-type';
|
import { SubmissionScopeType } from '../../../core/submission/submission-scope-type';
|
||||||
import { isNotEmpty } from '../../../shared/empty.util';
|
import { isNotEmpty } from '../../../shared/empty.util';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This component represents submission form footer bar.
|
||||||
|
*/
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'ds-submission-form-footer',
|
selector: 'ds-submission-form-footer',
|
||||||
styleUrls: ['./submission-form-footer.component.scss'],
|
styleUrls: ['./submission-form-footer.component.scss'],
|
||||||
@@ -16,18 +19,51 @@ import { isNotEmpty } from '../../../shared/empty.util';
|
|||||||
})
|
})
|
||||||
export class SubmissionFormFooterComponent implements OnChanges {
|
export class SubmissionFormFooterComponent implements OnChanges {
|
||||||
|
|
||||||
@Input() submissionId;
|
/**
|
||||||
|
* The submission id
|
||||||
|
* @type {string}
|
||||||
|
*/
|
||||||
|
@Input() submissionId: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A boolean representing if a submission deposit operation is pending
|
||||||
|
* @type {Observable<boolean>}
|
||||||
|
*/
|
||||||
public processingDepositStatus: Observable<boolean>;
|
public processingDepositStatus: Observable<boolean>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A boolean representing if a submission save operation is pending
|
||||||
|
* @type {Observable<boolean>}
|
||||||
|
*/
|
||||||
public processingSaveStatus: Observable<boolean>;
|
public processingSaveStatus: Observable<boolean>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A boolean representing if showing deposit and discard buttons
|
||||||
|
* @type {Observable<boolean>}
|
||||||
|
*/
|
||||||
public showDepositAndDiscard: Observable<boolean>;
|
public showDepositAndDiscard: Observable<boolean>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A boolean representing if submission form is valid or not
|
||||||
|
* @type {Observable<boolean>}
|
||||||
|
*/
|
||||||
private submissionIsInvalid: Observable<boolean> = observableOf(true);
|
private submissionIsInvalid: Observable<boolean> = observableOf(true);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize instance variables
|
||||||
|
*
|
||||||
|
* @param {NgbModal} modalService
|
||||||
|
* @param {SubmissionRestService} restService
|
||||||
|
* @param {SubmissionService} submissionService
|
||||||
|
*/
|
||||||
constructor(private modalService: NgbModal,
|
constructor(private modalService: NgbModal,
|
||||||
private restService: SubmissionRestService,
|
private restService: SubmissionRestService,
|
||||||
private submissionService: SubmissionService) {
|
private submissionService: SubmissionService) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize all instance variables
|
||||||
|
*/
|
||||||
ngOnChanges(changes: SimpleChanges) {
|
ngOnChanges(changes: SimpleChanges) {
|
||||||
if (isNotEmpty(this.submissionId)) {
|
if (isNotEmpty(this.submissionId)) {
|
||||||
this.submissionIsInvalid = this.submissionService.getSubmissionStatus(this.submissionId).pipe(
|
this.submissionIsInvalid = this.submissionService.getSubmissionStatus(this.submissionId).pipe(
|
||||||
@@ -40,18 +76,30 @@ export class SubmissionFormFooterComponent implements OnChanges {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Dispatch a submission save action
|
||||||
|
*/
|
||||||
save(event) {
|
save(event) {
|
||||||
this.submissionService.dispatchSave(this.submissionId);
|
this.submissionService.dispatchSave(this.submissionId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Dispatch a submission save for later action
|
||||||
|
*/
|
||||||
saveLater(event) {
|
saveLater(event) {
|
||||||
this.submissionService.dispatchSaveForLater(this.submissionId);
|
this.submissionService.dispatchSaveForLater(this.submissionId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Dispatch a submission deposit action
|
||||||
|
*/
|
||||||
public deposit(event) {
|
public deposit(event) {
|
||||||
this.submissionService.dispatchDeposit(this.submissionId);
|
this.submissionService.dispatchDeposit(this.submissionId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Dispatch a submission discard action
|
||||||
|
*/
|
||||||
public confirmDiscard(content) {
|
public confirmDiscard(content) {
|
||||||
this.modalService.open(content).result.then(
|
this.modalService.open(content).result.then(
|
||||||
(result) => {
|
(result) => {
|
||||||
|
@@ -1,30 +1,62 @@
|
|||||||
import { Component, Input, OnInit, } from '@angular/core';
|
import { Component, Input, OnInit, } from '@angular/core';
|
||||||
|
|
||||||
import { Observable } from 'rxjs';
|
import { Observable } from 'rxjs';
|
||||||
|
import { map } from 'rxjs/operators';
|
||||||
|
|
||||||
import { SectionsService } from '../../sections/sections.service';
|
import { SectionsService } from '../../sections/sections.service';
|
||||||
import { HostWindowService } from '../../../shared/host-window.service';
|
import { HostWindowService } from '../../../shared/host-window.service';
|
||||||
import { SubmissionService } from '../../submission.service';
|
import { SubmissionService } from '../../submission.service';
|
||||||
import { SectionDataObject } from '../../sections/models/section-data.model';
|
import { SectionDataObject } from '../../sections/models/section-data.model';
|
||||||
import { map } from 'rxjs/operators';
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This component allow to add any new section to submission form
|
||||||
|
*/
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'ds-submission-form-section-add',
|
selector: 'ds-submission-form-section-add',
|
||||||
styleUrls: [ './submission-form-section-add.component.scss' ],
|
styleUrls: [ './submission-form-section-add.component.scss' ],
|
||||||
templateUrl: './submission-form-section-add.component.html'
|
templateUrl: './submission-form-section-add.component.html'
|
||||||
})
|
})
|
||||||
export class SubmissionFormSectionAddComponent implements OnInit {
|
export class SubmissionFormSectionAddComponent implements OnInit {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The collection id this submission belonging to
|
||||||
|
* @type {string}
|
||||||
|
*/
|
||||||
@Input() collectionId: string;
|
@Input() collectionId: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The submission id
|
||||||
|
* @type {string}
|
||||||
|
*/
|
||||||
@Input() submissionId: string;
|
@Input() submissionId: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The possible section list to add
|
||||||
|
* @type {Observable<SectionDataObject[]>}
|
||||||
|
*/
|
||||||
public sectionList$: Observable<SectionDataObject[]>;
|
public sectionList$: Observable<SectionDataObject[]>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A boolean representing if there are available sections to add
|
||||||
|
* @type {Observable<boolean>}
|
||||||
|
*/
|
||||||
public hasSections$: Observable<boolean>;
|
public hasSections$: Observable<boolean>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize instance variables
|
||||||
|
*
|
||||||
|
* @param {SectionsService} sectionService
|
||||||
|
* @param {SubmissionService} submissionService
|
||||||
|
* @param {HostWindowService} windowService
|
||||||
|
*/
|
||||||
constructor(private sectionService: SectionsService,
|
constructor(private sectionService: SectionsService,
|
||||||
private submissionService: SubmissionService,
|
private submissionService: SubmissionService,
|
||||||
public windowService: HostWindowService) {
|
public windowService: HostWindowService) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize all instance variables
|
||||||
|
*/
|
||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
this.sectionList$ = this.submissionService.getDisabledSectionsList(this.submissionId);
|
this.sectionList$ = this.submissionService.getDisabledSectionsList(this.submissionId);
|
||||||
this.hasSections$ = this.sectionList$.pipe(
|
this.hasSections$ = this.sectionList$.pipe(
|
||||||
@@ -32,6 +64,9 @@ export class SubmissionFormSectionAddComponent implements OnInit {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Dispatch an action to add a new section
|
||||||
|
*/
|
||||||
addSection(sectionId) {
|
addSection(sectionId) {
|
||||||
this.sectionService.addSection(this.submissionId, sectionId);
|
this.sectionService.addSection(this.submissionId, sectionId);
|
||||||
}
|
}
|
||||||
|
@@ -15,22 +15,68 @@ import { HALEndpointService } from '../../core/shared/hal-endpoint.service';
|
|||||||
import { Collection } from '../../core/shared/collection.model';
|
import { Collection } from '../../core/shared/collection.model';
|
||||||
import { SubmissionObject } from '../../core/submission/models/submission-object.model';
|
import { SubmissionObject } from '../../core/submission/models/submission-object.model';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This component represents the submission form.
|
||||||
|
*/
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'ds-submission-submit-form',
|
selector: 'ds-submission-submit-form',
|
||||||
styleUrls: ['./submission-form.component.scss'],
|
styleUrls: ['./submission-form.component.scss'],
|
||||||
templateUrl: './submission-form.component.html',
|
templateUrl: './submission-form.component.html',
|
||||||
})
|
})
|
||||||
export class SubmissionFormComponent implements OnChanges, OnDestroy {
|
export class SubmissionFormComponent implements OnChanges, OnDestroy {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The collection id this submission belonging to
|
||||||
|
* @type {string}
|
||||||
|
*/
|
||||||
@Input() collectionId: string;
|
@Input() collectionId: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The list of submission's sections
|
||||||
|
* @type {WorkspaceitemSectionsObject}
|
||||||
|
*/
|
||||||
@Input() sections: WorkspaceitemSectionsObject;
|
@Input() sections: WorkspaceitemSectionsObject;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The submission self url
|
||||||
|
* @type {string}
|
||||||
|
*/
|
||||||
@Input() selfUrl: string;
|
@Input() selfUrl: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The configuration object that define this submission
|
||||||
|
* @type {SubmissionDefinitionsModel}
|
||||||
|
*/
|
||||||
@Input() submissionDefinition: SubmissionDefinitionsModel;
|
@Input() submissionDefinition: SubmissionDefinitionsModel;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The submission id
|
||||||
|
* @type {string}
|
||||||
|
*/
|
||||||
@Input() submissionId: string;
|
@Input() submissionId: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The configuration id that define this submission
|
||||||
|
* @type {string}
|
||||||
|
*/
|
||||||
public definitionId: string;
|
public definitionId: string;
|
||||||
public test = true;
|
|
||||||
|
/**
|
||||||
|
* A boolean representing if a submission form is pending
|
||||||
|
* @type {Observable<boolean>}
|
||||||
|
*/
|
||||||
public loading: Observable<boolean> = observableOf(true);
|
public loading: Observable<boolean> = observableOf(true);
|
||||||
public submissionSections: Observable<any>;
|
|
||||||
|
/**
|
||||||
|
* Observable of the list of submission's sections
|
||||||
|
* @type {Observable<WorkspaceitemSectionsObject>}
|
||||||
|
*/
|
||||||
|
public submissionSections: Observable<WorkspaceitemSectionsObject>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The uploader configuration options
|
||||||
|
* @type {UploaderOptions}
|
||||||
|
*/
|
||||||
public uploadFilesOptions: UploaderOptions = {
|
public uploadFilesOptions: UploaderOptions = {
|
||||||
url: '',
|
url: '',
|
||||||
authToken: null,
|
authToken: null,
|
||||||
@@ -38,9 +84,26 @@ export class SubmissionFormComponent implements OnChanges, OnDestroy {
|
|||||||
itemAlias: null
|
itemAlias: null
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A boolean representing if component is active
|
||||||
|
* @type {boolean}
|
||||||
|
*/
|
||||||
protected isActive: boolean;
|
protected isActive: boolean;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Array to track all subscriptions and unsubscribe them onDestroy
|
||||||
|
* @type {Array}
|
||||||
|
*/
|
||||||
protected subs: Subscription[] = [];
|
protected subs: Subscription[] = [];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize instance variables
|
||||||
|
*
|
||||||
|
* @param {AuthService} authService
|
||||||
|
* @param {ChangeDetectorRef} changeDetectorRef
|
||||||
|
* @param {HALEndpointService} halService
|
||||||
|
* @param {SubmissionService} submissionService
|
||||||
|
*/
|
||||||
constructor(
|
constructor(
|
||||||
private authService: AuthService,
|
private authService: AuthService,
|
||||||
private changeDetectorRef: ChangeDetectorRef,
|
private changeDetectorRef: ChangeDetectorRef,
|
||||||
@@ -49,9 +112,14 @@ export class SubmissionFormComponent implements OnChanges, OnDestroy {
|
|||||||
this.isActive = true;
|
this.isActive = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize all instance variables and retrieve form configuration
|
||||||
|
*/
|
||||||
ngOnChanges(changes: SimpleChanges) {
|
ngOnChanges(changes: SimpleChanges) {
|
||||||
if (this.collectionId && this.submissionId) {
|
if (this.collectionId && this.submissionId) {
|
||||||
this.isActive = true;
|
this.isActive = true;
|
||||||
|
|
||||||
|
// retrieve submission's section list
|
||||||
this.submissionSections = this.submissionService.getSubmissionObject(this.submissionId).pipe(
|
this.submissionSections = this.submissionService.getSubmissionObject(this.submissionId).pipe(
|
||||||
filter(() => this.isActive),
|
filter(() => this.isActive),
|
||||||
map((submission: SubmissionObjectEntry) => submission.isLoading),
|
map((submission: SubmissionObjectEntry) => submission.isLoading),
|
||||||
@@ -65,12 +133,14 @@ export class SubmissionFormComponent implements OnChanges, OnDestroy {
|
|||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
// check if is submission loading
|
||||||
this.loading = this.submissionService.getSubmissionObject(this.submissionId).pipe(
|
this.loading = this.submissionService.getSubmissionObject(this.submissionId).pipe(
|
||||||
filter(() => this.isActive),
|
filter(() => this.isActive),
|
||||||
map((submission: SubmissionObjectEntry) => submission.isLoading),
|
map((submission: SubmissionObjectEntry) => submission.isLoading),
|
||||||
map((isLoading: boolean) => isLoading),
|
map((isLoading: boolean) => isLoading),
|
||||||
distinctUntilChanged());
|
distinctUntilChanged());
|
||||||
|
|
||||||
|
// init submission state
|
||||||
this.subs.push(
|
this.subs.push(
|
||||||
this.halService.getEndpoint('workspaceitems').pipe(
|
this.halService.getEndpoint('workspaceitems').pipe(
|
||||||
filter((href: string) => isNotEmpty(href)),
|
filter((href: string) => isNotEmpty(href)),
|
||||||
@@ -89,10 +159,16 @@ export class SubmissionFormComponent implements OnChanges, OnDestroy {
|
|||||||
this.changeDetectorRef.detectChanges();
|
this.changeDetectorRef.detectChanges();
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// start auto save
|
||||||
this.submissionService.startAutoSave(this.submissionId);
|
this.submissionService.startAutoSave(this.submissionId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unsubscribe from all subscriptions, destroy instance variables
|
||||||
|
* and reset submission state
|
||||||
|
*/
|
||||||
ngOnDestroy() {
|
ngOnDestroy() {
|
||||||
this.isActive = false;
|
this.isActive = false;
|
||||||
this.submissionService.stopAutoSave();
|
this.submissionService.stopAutoSave();
|
||||||
@@ -102,6 +178,13 @@ export class SubmissionFormComponent implements OnChanges, OnDestroy {
|
|||||||
.forEach((subscription) => subscription.unsubscribe());
|
.forEach((subscription) => subscription.unsubscribe());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* On collection change reset submission state in case of it has a different
|
||||||
|
* submission definition
|
||||||
|
*
|
||||||
|
* @param submissionObject
|
||||||
|
* new submission object
|
||||||
|
*/
|
||||||
onCollectionChange(submissionObject: SubmissionObject) {
|
onCollectionChange(submissionObject: SubmissionObject) {
|
||||||
this.collectionId = (submissionObject.collection as Collection).id;
|
this.collectionId = (submissionObject.collection as Collection).id;
|
||||||
if (this.definitionId !== (submissionObject.submissionDefinition as SubmissionDefinitionsModel).name) {
|
if (this.definitionId !== (submissionObject.submissionDefinition as SubmissionDefinitionsModel).name) {
|
||||||
@@ -119,10 +202,16 @@ export class SubmissionFormComponent implements OnChanges, OnDestroy {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if submission form is loading
|
||||||
|
*/
|
||||||
isLoading(): Observable<boolean> {
|
isLoading(): Observable<boolean> {
|
||||||
return this.loading;
|
return this.loading;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if submission form is loading
|
||||||
|
*/
|
||||||
protected getSectionsList(): Observable<any> {
|
protected getSectionsList(): Observable<any> {
|
||||||
return this.submissionService.getSubmissionSections(this.submissionId).pipe(
|
return this.submissionService.getSubmissionSections(this.submissionId).pipe(
|
||||||
filter((sections: SectionDataObject[]) => isNotEmpty(sections)),
|
filter((sections: SectionDataObject[]) => isNotEmpty(sections)),
|
||||||
|
@@ -14,24 +14,72 @@ import { UploaderOptions } from '../../../shared/uploader/uploader-options.model
|
|||||||
import parseSectionErrors from '../../utils/parseSectionErrors';
|
import parseSectionErrors from '../../utils/parseSectionErrors';
|
||||||
import { SubmissionJsonPatchOperationsService } from '../../../core/submission/submission-json-patch-operations.service';
|
import { SubmissionJsonPatchOperationsService } from '../../../core/submission/submission-json-patch-operations.service';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This component represents the drop zone that provides to add files to the submission.
|
||||||
|
*/
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'ds-submission-upload-files',
|
selector: 'ds-submission-upload-files',
|
||||||
templateUrl: './submission-upload-files.component.html',
|
templateUrl: './submission-upload-files.component.html',
|
||||||
})
|
})
|
||||||
export class SubmissionUploadFilesComponent implements OnChanges {
|
export class SubmissionUploadFilesComponent implements OnChanges {
|
||||||
|
|
||||||
@Input() collectionId;
|
/**
|
||||||
@Input() submissionId;
|
* The collection id this submission belonging to
|
||||||
@Input() sectionId;
|
* @type {string}
|
||||||
|
*/
|
||||||
|
@Input() collectionId: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The submission id
|
||||||
|
* @type {string}
|
||||||
|
*/
|
||||||
|
@Input() submissionId: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The upload section id
|
||||||
|
* @type {string}
|
||||||
|
*/
|
||||||
|
@Input() sectionId: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The uploader configuration options
|
||||||
|
* @type {UploaderOptions}
|
||||||
|
*/
|
||||||
@Input() uploadFilesOptions: UploaderOptions;
|
@Input() uploadFilesOptions: UploaderOptions;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A boolean representing if is possible to active drop zone over the document page
|
||||||
|
* @type {boolean}
|
||||||
|
*/
|
||||||
public enableDragOverDocument = true;
|
public enableDragOverDocument = true;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* i18n message label
|
||||||
|
* @type {string}
|
||||||
|
*/
|
||||||
public dropOverDocumentMsg = 'submission.sections.upload.drop-message';
|
public dropOverDocumentMsg = 'submission.sections.upload.drop-message';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* i18n message label
|
||||||
|
* @type {string}
|
||||||
|
*/
|
||||||
public dropMsg = 'submission.sections.upload.drop-message';
|
public dropMsg = 'submission.sections.upload.drop-message';
|
||||||
|
|
||||||
private subs = [];
|
/**
|
||||||
|
* Array to track all subscriptions and unsubscribe them onDestroy
|
||||||
|
* @type {Array}
|
||||||
|
*/
|
||||||
|
private subs: Subscription[] = [];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A boolean representing if upload functionality is enabled
|
||||||
|
* @type {boolean}
|
||||||
|
*/
|
||||||
private uploadEnabled: Observable<boolean> = observableOf(false);
|
private uploadEnabled: Observable<boolean> = observableOf(false);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Save submission before to upload a file
|
||||||
|
*/
|
||||||
public onBeforeUpload = () => {
|
public onBeforeUpload = () => {
|
||||||
const sub: Subscription = this.operationsService.jsonPatchByResourceType(
|
const sub: Subscription = this.operationsService.jsonPatchByResourceType(
|
||||||
this.submissionService.getSubmissionObjectLinkName(),
|
this.submissionService.getSubmissionObjectLinkName(),
|
||||||
@@ -42,6 +90,15 @@ export class SubmissionUploadFilesComponent implements OnChanges {
|
|||||||
return sub;
|
return sub;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize instance variables
|
||||||
|
*
|
||||||
|
* @param {NotificationsService} notificationsService
|
||||||
|
* @param {SubmissionJsonPatchOperationsService} operationsService
|
||||||
|
* @param {SectionsService} sectionService
|
||||||
|
* @param {SubmissionService} submissionService
|
||||||
|
* @param {TranslateService} translate
|
||||||
|
*/
|
||||||
constructor(private notificationsService: NotificationsService,
|
constructor(private notificationsService: NotificationsService,
|
||||||
private operationsService: SubmissionJsonPatchOperationsService,
|
private operationsService: SubmissionJsonPatchOperationsService,
|
||||||
private sectionService: SectionsService,
|
private sectionService: SectionsService,
|
||||||
@@ -49,10 +106,19 @@ export class SubmissionUploadFilesComponent implements OnChanges {
|
|||||||
private translate: TranslateService) {
|
private translate: TranslateService) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if upload functionality is enabled
|
||||||
|
*/
|
||||||
ngOnChanges() {
|
ngOnChanges() {
|
||||||
this.uploadEnabled = this.sectionService.isSectionAvailable(this.submissionId, this.sectionId);
|
this.uploadEnabled = this.sectionService.isSectionAvailable(this.submissionId, this.sectionId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parse the submission object retrieved from REST after upload
|
||||||
|
*
|
||||||
|
* @param workspaceitem
|
||||||
|
* The submission object retrieved from REST
|
||||||
|
*/
|
||||||
public onCompleteItem(workspaceitem: Workspaceitem) {
|
public onCompleteItem(workspaceitem: Workspaceitem) {
|
||||||
// Checks if upload section is enabled so do upload
|
// Checks if upload section is enabled so do upload
|
||||||
this.subs.push(
|
this.subs.push(
|
||||||
@@ -61,8 +127,8 @@ export class SubmissionUploadFilesComponent implements OnChanges {
|
|||||||
.subscribe((isUploadEnabled) => {
|
.subscribe((isUploadEnabled) => {
|
||||||
if (isUploadEnabled) {
|
if (isUploadEnabled) {
|
||||||
|
|
||||||
const {sections} = workspaceitem;
|
const { sections } = workspaceitem;
|
||||||
const {errors} = workspaceitem;
|
const { errors } = workspaceitem;
|
||||||
|
|
||||||
const errorsList = parseSectionErrors(errors);
|
const errorsList = parseSectionErrors(errors);
|
||||||
if (sections && isNotEmpty(sections)) {
|
if (sections && isNotEmpty(sections)) {
|
||||||
@@ -87,12 +153,15 @@ export class SubmissionUploadFilesComponent implements OnChanges {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Show error notification on upload fails
|
||||||
|
*/
|
||||||
public onUploadError() {
|
public onUploadError() {
|
||||||
this.notificationsService.error(null, this.translate.get('submission.sections.upload.upload-failed'));
|
this.notificationsService.error(null, this.translate.get('submission.sections.upload.upload-failed'));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Method provided by Angular. Invoked when the instance is destroyed.
|
* Unsubscribe from all subscriptions
|
||||||
*/
|
*/
|
||||||
ngOnDestroy() {
|
ngOnDestroy() {
|
||||||
this.subs
|
this.subs
|
||||||
|
@@ -277,7 +277,7 @@ export class SubmissionObjectEffects {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parse the submission object retrieved from REST haven't section errors and return actions to dispatch
|
* Parse the submission object retrieved from REST and return actions to dispatch
|
||||||
*
|
*
|
||||||
* @param currentState
|
* @param currentState
|
||||||
* The current SubmissionObjectEntry
|
* The current SubmissionObjectEntry
|
||||||
|
@@ -138,7 +138,7 @@ export interface SubmissionObjectEntry {
|
|||||||
collection?: string,
|
collection?: string,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The configuration name tha define this submission
|
* The configuration name that define this submission
|
||||||
*/
|
*/
|
||||||
definition?: string,
|
definition?: string,
|
||||||
|
|
||||||
|
@@ -3,29 +3,64 @@ import { Component, Injector, Input, OnInit, ViewChild } from '@angular/core';
|
|||||||
import { SectionsDirective } from '../sections.directive';
|
import { SectionsDirective } from '../sections.directive';
|
||||||
import { SectionDataObject } from '../models/section-data.model';
|
import { SectionDataObject } from '../models/section-data.model';
|
||||||
import { rendersSectionType } from '../sections-decorator';
|
import { rendersSectionType } from '../sections-decorator';
|
||||||
import { SectionsType } from '../sections-type';
|
|
||||||
import { AlertType } from '../../../shared/alerts/aletrs-type';
|
import { AlertType } from '../../../shared/alerts/aletrs-type';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This component represents a section that contains the submission license form.
|
||||||
|
*/
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'ds-submission-form-section-container',
|
selector: 'ds-submission-form-section-container',
|
||||||
templateUrl: './section-container.component.html',
|
templateUrl: './section-container.component.html',
|
||||||
styleUrls: ['./section-container.component.scss']
|
styleUrls: ['./section-container.component.scss']
|
||||||
})
|
})
|
||||||
export class SectionContainerComponent implements OnInit {
|
export class SectionContainerComponent implements OnInit {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The collection id this submission belonging to
|
||||||
|
* @type {string}
|
||||||
|
*/
|
||||||
@Input() collectionId: string;
|
@Input() collectionId: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The section data
|
||||||
|
* @type {SectionDataObject}
|
||||||
|
*/
|
||||||
@Input() sectionData: SectionDataObject;
|
@Input() sectionData: SectionDataObject;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The submission id
|
||||||
|
* @type {string}
|
||||||
|
*/
|
||||||
@Input() submissionId: string;
|
@Input() submissionId: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The AlertType enumeration
|
||||||
|
* @type {AlertType}
|
||||||
|
*/
|
||||||
public AlertTypeEnum = AlertType;
|
public AlertTypeEnum = AlertType;
|
||||||
public active = true;
|
|
||||||
public objectInjector: Injector;
|
|
||||||
public sectionComponentType: SectionsType;
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Injector to inject a section component with the @Input parameters
|
||||||
|
* @type {Injector}
|
||||||
|
*/
|
||||||
|
public objectInjector: Injector;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The SectionsDirective reference
|
||||||
|
*/
|
||||||
@ViewChild('sectionRef') sectionRef: SectionsDirective;
|
@ViewChild('sectionRef') sectionRef: SectionsDirective;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize instance variables
|
||||||
|
*
|
||||||
|
* @param {Injector} injector
|
||||||
|
*/
|
||||||
constructor(private injector: Injector) {
|
constructor(private injector: Injector) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize all instance variables
|
||||||
|
*/
|
||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
this.objectInjector = Injector.create({
|
this.objectInjector = Injector.create({
|
||||||
providers: [
|
providers: [
|
||||||
@@ -37,12 +72,21 @@ export class SectionContainerComponent implements OnInit {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove section from submission form
|
||||||
|
*
|
||||||
|
* @param event
|
||||||
|
* the event emitted
|
||||||
|
*/
|
||||||
public removeSection(event) {
|
public removeSection(event) {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
event.stopPropagation();
|
event.stopPropagation();
|
||||||
this.sectionRef.removeSection(this.submissionId, this.sectionData.id);
|
this.sectionRef.removeSection(this.submissionId, this.sectionData.id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Find the correct component based on the section's type
|
||||||
|
*/
|
||||||
getSectionContent(): string {
|
getSectionContent(): string {
|
||||||
return rendersSectionType(this.sectionData.sectionType);
|
return rendersSectionType(this.sectionData.sectionType);
|
||||||
}
|
}
|
||||||
|
@@ -156,7 +156,7 @@ describe('SectionFormOperationsService test suite', () => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
expect(service.isPartOfArrayOfGroup(model)).toBeTruthy();
|
expect(service.isPartOfArrayOfGroup(model as any)).toBeTruthy();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should return false when parent element doesn\'t belong to an array group element', () => {
|
it('should return false when parent element doesn\'t belong to an array group element', () => {
|
||||||
@@ -164,7 +164,7 @@ describe('SectionFormOperationsService test suite', () => {
|
|||||||
parent: null
|
parent: null
|
||||||
};
|
};
|
||||||
|
|
||||||
expect(service.isPartOfArrayOfGroup(model)).toBeFalsy();
|
expect(service.isPartOfArrayOfGroup(model as any)).toBeFalsy();
|
||||||
});
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
@@ -21,12 +21,35 @@ import { FormFieldMetadataValueObject } from '../../../shared/form/builder/model
|
|||||||
import { DynamicQualdropModel } from '../../../shared/form/builder/ds-dynamic-form-ui/models/ds-dynamic-qualdrop.model';
|
import { DynamicQualdropModel } from '../../../shared/form/builder/ds-dynamic-form-ui/models/ds-dynamic-qualdrop.model';
|
||||||
import { DynamicRelationGroupModel } from '../../../shared/form/builder/ds-dynamic-form-ui/models/relation-group/dynamic-relation-group.model';
|
import { DynamicRelationGroupModel } from '../../../shared/form/builder/ds-dynamic-form-ui/models/relation-group/dynamic-relation-group.model';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The service handling all form section operations
|
||||||
|
*/
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class SectionFormOperationsService {
|
export class SectionFormOperationsService {
|
||||||
|
|
||||||
constructor(private formBuilder: FormBuilderService, private operationsBuilder: JsonPatchOperationsBuilder) {
|
/**
|
||||||
|
* Initialize service variables
|
||||||
|
*
|
||||||
|
* @param {FormBuilderService} formBuilder
|
||||||
|
* @param {JsonPatchOperationsBuilder} operationsBuilder
|
||||||
|
*/
|
||||||
|
constructor(
|
||||||
|
private formBuilder: FormBuilderService,
|
||||||
|
private operationsBuilder: JsonPatchOperationsBuilder) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Dispatch properly method based on form operation type
|
||||||
|
*
|
||||||
|
* @param pathCombiner
|
||||||
|
* the [[JsonPatchOperationPathCombiner]] object for the specified operation
|
||||||
|
* @param event
|
||||||
|
* the [[DynamicFormControlEvent]] for the specified operation
|
||||||
|
* @param previousValue
|
||||||
|
* the [[FormFieldPreviousValueObject]] for the specified operation
|
||||||
|
* @param hasStoredValue
|
||||||
|
* representing if field value related to the specified operation has stored value
|
||||||
|
*/
|
||||||
public dispatchOperationsFromEvent(pathCombiner: JsonPatchOperationPathCombiner,
|
public dispatchOperationsFromEvent(pathCombiner: JsonPatchOperationPathCombiner,
|
||||||
event: DynamicFormControlEvent,
|
event: DynamicFormControlEvent,
|
||||||
previousValue: FormFieldPreviousValueObject,
|
previousValue: FormFieldPreviousValueObject,
|
||||||
@@ -43,6 +66,14 @@ export class SectionFormOperationsService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return index if specified field is part of fields array
|
||||||
|
*
|
||||||
|
* @param event
|
||||||
|
* the [[DynamicFormControlEvent]] for the specified operation
|
||||||
|
* @return number
|
||||||
|
* the array index is part of array, zero otherwise
|
||||||
|
*/
|
||||||
public getArrayIndexFromEvent(event: DynamicFormControlEvent): number {
|
public getArrayIndexFromEvent(event: DynamicFormControlEvent): number {
|
||||||
let fieldIndex: number;
|
let fieldIndex: number;
|
||||||
if (isNotEmpty(event)) {
|
if (isNotEmpty(event)) {
|
||||||
@@ -60,7 +91,15 @@ export class SectionFormOperationsService {
|
|||||||
return isNotUndefined(fieldIndex) ? fieldIndex : 0;
|
return isNotUndefined(fieldIndex) ? fieldIndex : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public isPartOfArrayOfGroup(model: any): boolean {
|
/**
|
||||||
|
* Check if specified model is part of array of group
|
||||||
|
*
|
||||||
|
* @param model
|
||||||
|
* the [[DynamicFormControlModel]] model
|
||||||
|
* @return boolean
|
||||||
|
* true if is part of array, false otherwise
|
||||||
|
*/
|
||||||
|
public isPartOfArrayOfGroup(model: DynamicFormControlModel): boolean {
|
||||||
return (isNotNull(model.parent)
|
return (isNotNull(model.parent)
|
||||||
&& (model.parent as any).type === DYNAMIC_FORM_CONTROL_TYPE_GROUP
|
&& (model.parent as any).type === DYNAMIC_FORM_CONTROL_TYPE_GROUP
|
||||||
&& (model.parent as any).parent
|
&& (model.parent as any).parent
|
||||||
@@ -68,7 +107,15 @@ export class SectionFormOperationsService {
|
|||||||
&& (model.parent as any).parent.context.type === DYNAMIC_FORM_CONTROL_TYPE_ARRAY);
|
&& (model.parent as any).parent.context.type === DYNAMIC_FORM_CONTROL_TYPE_ARRAY);
|
||||||
}
|
}
|
||||||
|
|
||||||
public getQualdropValueMap(event): Map<string, any> {
|
/**
|
||||||
|
* Return a map for the values of a Qualdrop field
|
||||||
|
*
|
||||||
|
* @param event
|
||||||
|
* the [[DynamicFormControlEvent]] for the specified operation
|
||||||
|
* @return Map<string, any>
|
||||||
|
* the map of values
|
||||||
|
*/
|
||||||
|
public getQualdropValueMap(event: DynamicFormControlEvent): Map<string, any> {
|
||||||
const metadataValueMap = new Map();
|
const metadataValueMap = new Map();
|
||||||
|
|
||||||
const context = this.formBuilder.isQualdropGroup(event.model)
|
const context = this.formBuilder.isQualdropGroup(event.model)
|
||||||
@@ -87,12 +134,28 @@ export class SectionFormOperationsService {
|
|||||||
return metadataValueMap;
|
return metadataValueMap;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the absolute path for the field interesting in the specified operation
|
||||||
|
*
|
||||||
|
* @param event
|
||||||
|
* the [[DynamicFormControlEvent]] for the specified operation
|
||||||
|
* @return string
|
||||||
|
* the field path
|
||||||
|
*/
|
||||||
public getFieldPathFromEvent(event: DynamicFormControlEvent): string {
|
public getFieldPathFromEvent(event: DynamicFormControlEvent): string {
|
||||||
const fieldIndex = this.getArrayIndexFromEvent(event);
|
const fieldIndex = this.getArrayIndexFromEvent(event);
|
||||||
const fieldId = this.getFieldPathSegmentedFromChangeEvent(event);
|
const fieldId = this.getFieldPathSegmentedFromChangeEvent(event);
|
||||||
return (isNotUndefined(fieldIndex)) ? fieldId + '/' + fieldIndex : fieldId;
|
return (isNotUndefined(fieldIndex)) ? fieldId + '/' + fieldIndex : fieldId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the absolute path for the Qualdrop field interesting in the specified operation
|
||||||
|
*
|
||||||
|
* @param event
|
||||||
|
* the [[DynamicFormControlEvent]] for the specified operation
|
||||||
|
* @return string
|
||||||
|
* the field path
|
||||||
|
*/
|
||||||
public getQualdropItemPathFromEvent(event: DynamicFormControlEvent): string {
|
public getQualdropItemPathFromEvent(event: DynamicFormControlEvent): string {
|
||||||
const fieldIndex = this.getArrayIndexFromEvent(event);
|
const fieldIndex = this.getArrayIndexFromEvent(event);
|
||||||
const metadataValueMap = new Map();
|
const metadataValueMap = new Map();
|
||||||
@@ -117,6 +180,14 @@ export class SectionFormOperationsService {
|
|||||||
return path;
|
return path;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the segmented path for the field interesting in the specified change operation
|
||||||
|
*
|
||||||
|
* @param event
|
||||||
|
* the [[DynamicFormControlEvent]] for the specified operation
|
||||||
|
* @return string
|
||||||
|
* the field path
|
||||||
|
*/
|
||||||
public getFieldPathSegmentedFromChangeEvent(event: DynamicFormControlEvent): string {
|
public getFieldPathSegmentedFromChangeEvent(event: DynamicFormControlEvent): string {
|
||||||
let fieldId;
|
let fieldId;
|
||||||
if (this.formBuilder.isQualdropGroup(event.model as DynamicFormControlModel)) {
|
if (this.formBuilder.isQualdropGroup(event.model as DynamicFormControlModel)) {
|
||||||
@@ -129,6 +200,14 @@ export class SectionFormOperationsService {
|
|||||||
return fieldId;
|
return fieldId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the value of the field interesting in the specified change operation
|
||||||
|
*
|
||||||
|
* @param event
|
||||||
|
* the [[DynamicFormControlEvent]] for the specified operation
|
||||||
|
* @return any
|
||||||
|
* the field value
|
||||||
|
*/
|
||||||
public getFieldValueFromChangeEvent(event: DynamicFormControlEvent): any {
|
public getFieldValueFromChangeEvent(event: DynamicFormControlEvent): any {
|
||||||
let fieldValue;
|
let fieldValue;
|
||||||
const value = (event.model as any).value;
|
const value = (event.model as any).value;
|
||||||
@@ -142,12 +221,12 @@ export class SectionFormOperationsService {
|
|||||||
if ((event.model as DsDynamicInputModel).hasAuthority) {
|
if ((event.model as DsDynamicInputModel).hasAuthority) {
|
||||||
if (Array.isArray(value)) {
|
if (Array.isArray(value)) {
|
||||||
value.forEach((authority, index) => {
|
value.forEach((authority, index) => {
|
||||||
authority = Object.assign(new AuthorityValue(), authority, {language});
|
authority = Object.assign(new AuthorityValue(), authority, { language });
|
||||||
value[index] = authority;
|
value[index] = authority;
|
||||||
});
|
});
|
||||||
fieldValue = value;
|
fieldValue = value;
|
||||||
} else {
|
} else {
|
||||||
fieldValue = Object.assign(new AuthorityValue(), value, {language});
|
fieldValue = Object.assign(new AuthorityValue(), value, { language });
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Language without Authority (input, textArea)
|
// Language without Authority (input, textArea)
|
||||||
@@ -162,6 +241,14 @@ export class SectionFormOperationsService {
|
|||||||
return fieldValue;
|
return fieldValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return a map for the values of an array of field
|
||||||
|
*
|
||||||
|
* @param items
|
||||||
|
* the list of items
|
||||||
|
* @return Map<string, any>
|
||||||
|
* the map of values
|
||||||
|
*/
|
||||||
public getValueMap(items: any[]): Map<string, any> {
|
public getValueMap(items: any[]): Map<string, any> {
|
||||||
const metadataValueMap = new Map();
|
const metadataValueMap = new Map();
|
||||||
|
|
||||||
@@ -177,6 +264,16 @@ export class SectionFormOperationsService {
|
|||||||
return metadataValueMap;
|
return metadataValueMap;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle form remove operations
|
||||||
|
*
|
||||||
|
* @param pathCombiner
|
||||||
|
* the [[JsonPatchOperationPathCombiner]] object for the specified operation
|
||||||
|
* @param event
|
||||||
|
* the [[DynamicFormControlEvent]] for the specified operation
|
||||||
|
* @param previousValue
|
||||||
|
* the [[FormFieldPreviousValueObject]] for the specified operation
|
||||||
|
*/
|
||||||
protected dispatchOperationsFromRemoveEvent(pathCombiner: JsonPatchOperationPathCombiner,
|
protected dispatchOperationsFromRemoveEvent(pathCombiner: JsonPatchOperationPathCombiner,
|
||||||
event: DynamicFormControlEvent,
|
event: DynamicFormControlEvent,
|
||||||
previousValue: FormFieldPreviousValueObject): void {
|
previousValue: FormFieldPreviousValueObject): void {
|
||||||
@@ -189,6 +286,18 @@ export class SectionFormOperationsService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle form change operations
|
||||||
|
*
|
||||||
|
* @param pathCombiner
|
||||||
|
* the [[JsonPatchOperationPathCombiner]] object for the specified operation
|
||||||
|
* @param event
|
||||||
|
* the [[DynamicFormControlEvent]] for the specified operation
|
||||||
|
* @param previousValue
|
||||||
|
* the [[FormFieldPreviousValueObject]] for the specified operation
|
||||||
|
* @param hasStoredValue
|
||||||
|
* representing if field value related to the specified operation has stored value
|
||||||
|
*/
|
||||||
protected dispatchOperationsFromChangeEvent(pathCombiner: JsonPatchOperationPathCombiner,
|
protected dispatchOperationsFromChangeEvent(pathCombiner: JsonPatchOperationPathCombiner,
|
||||||
event: DynamicFormControlEvent,
|
event: DynamicFormControlEvent,
|
||||||
previousValue: FormFieldPreviousValueObject,
|
previousValue: FormFieldPreviousValueObject,
|
||||||
@@ -243,6 +352,18 @@ export class SectionFormOperationsService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle form operations interesting a field with a map as value
|
||||||
|
*
|
||||||
|
* @param valueMap
|
||||||
|
* map of values
|
||||||
|
* @param pathCombiner
|
||||||
|
* the [[JsonPatchOperationPathCombiner]] object for the specified operation
|
||||||
|
* @param event
|
||||||
|
* the [[DynamicFormControlEvent]] for the specified operation
|
||||||
|
* @param previousValue
|
||||||
|
* the [[FormFieldPreviousValueObject]] for the specified operation
|
||||||
|
*/
|
||||||
protected dispatchOperationsFromMap(valueMap: Map<string, any>,
|
protected dispatchOperationsFromMap(valueMap: Map<string, any>,
|
||||||
pathCombiner: JsonPatchOperationPathCombiner,
|
pathCombiner: JsonPatchOperationPathCombiner,
|
||||||
event: DynamicFormControlEvent,
|
event: DynamicFormControlEvent,
|
||||||
|
@@ -42,46 +42,55 @@ export class FormSectionComponent extends SectionModelComponent {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* The form id
|
* The form id
|
||||||
|
* @type {string}
|
||||||
*/
|
*/
|
||||||
public formId;
|
public formId: string;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The form model
|
* The form model
|
||||||
|
* @type {DynamicFormControlModel[]}
|
||||||
*/
|
*/
|
||||||
public formModel: DynamicFormControlModel[];
|
public formModel: DynamicFormControlModel[];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A boolean representing if this section is updating
|
* A boolean representing if this section is updating
|
||||||
|
* @type {boolean}
|
||||||
*/
|
*/
|
||||||
public isUpdating = false;
|
public isUpdating = false;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A boolean representing if this section is loading
|
* A boolean representing if this section is loading
|
||||||
|
* @type {boolean}
|
||||||
*/
|
*/
|
||||||
public isLoading = true;
|
public isLoading = true;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The form config
|
* The form config
|
||||||
|
* @type {SubmissionFormsModel}
|
||||||
*/
|
*/
|
||||||
protected formConfig: SubmissionFormsModel;
|
protected formConfig: SubmissionFormsModel;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The form data
|
* The form data
|
||||||
|
* @type {any}
|
||||||
*/
|
*/
|
||||||
protected formData: any = Object.create({});
|
protected formData: any = Object.create({});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The [JsonPatchOperationPathCombiner] object
|
* The [JsonPatchOperationPathCombiner] object
|
||||||
|
* @type {JsonPatchOperationPathCombiner}
|
||||||
*/
|
*/
|
||||||
protected pathCombiner: JsonPatchOperationPathCombiner;
|
protected pathCombiner: JsonPatchOperationPathCombiner;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The [FormFieldPreviousValueObject] object
|
* The [FormFieldPreviousValueObject] object
|
||||||
|
* @type {FormFieldPreviousValueObject}
|
||||||
*/
|
*/
|
||||||
protected previousValue: FormFieldPreviousValueObject = new FormFieldPreviousValueObject();
|
protected previousValue: FormFieldPreviousValueObject = new FormFieldPreviousValueObject();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The list of Subscription
|
* The list of Subscription
|
||||||
|
* @type {Array}
|
||||||
*/
|
*/
|
||||||
protected subs: Subscription[] = [];
|
protected subs: Subscription[] = [];
|
||||||
|
|
||||||
@@ -92,6 +101,7 @@ export class FormSectionComponent extends SectionModelComponent {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Initialize instance variables
|
* Initialize instance variables
|
||||||
|
*
|
||||||
* @param {ChangeDetectorRef} cdr
|
* @param {ChangeDetectorRef} cdr
|
||||||
* @param {FormBuilderService} formBuilderService
|
* @param {FormBuilderService} formBuilderService
|
||||||
* @param {SectionFormOperationsService} formOperationsService
|
* @param {SectionFormOperationsService} formOperationsService
|
||||||
@@ -158,6 +168,9 @@ export class FormSectionComponent extends SectionModelComponent {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Get section status
|
* Get section status
|
||||||
|
*
|
||||||
|
* @return Observable<boolean>
|
||||||
|
* the section status
|
||||||
*/
|
*/
|
||||||
protected getSectionStatus(): Observable<boolean> {
|
protected getSectionStatus(): Observable<boolean> {
|
||||||
return this.formService.isValid(this.formId);
|
return this.formService.isValid(this.formId);
|
||||||
@@ -290,6 +303,9 @@ export class FormSectionComponent extends SectionModelComponent {
|
|||||||
/**
|
/**
|
||||||
* Method called when a form dfChange event is fired.
|
* Method called when a form dfChange event is fired.
|
||||||
* Dispatch form operations based on changes.
|
* Dispatch form operations based on changes.
|
||||||
|
*
|
||||||
|
* @param event
|
||||||
|
* the [[DynamicFormControlEvent]] emitted
|
||||||
*/
|
*/
|
||||||
onChange(event: DynamicFormControlEvent): void {
|
onChange(event: DynamicFormControlEvent): void {
|
||||||
this.formOperationsService.dispatchOperationsFromEvent(
|
this.formOperationsService.dispatchOperationsFromEvent(
|
||||||
@@ -308,6 +324,9 @@ export class FormSectionComponent extends SectionModelComponent {
|
|||||||
/**
|
/**
|
||||||
* Method called when a form dfFocus event is fired.
|
* Method called when a form dfFocus event is fired.
|
||||||
* Initialize [FormFieldPreviousValueObject] instance.
|
* Initialize [FormFieldPreviousValueObject] instance.
|
||||||
|
*
|
||||||
|
* @param event
|
||||||
|
* the [[DynamicFormControlEvent]] emitted
|
||||||
*/
|
*/
|
||||||
onFocus(event: DynamicFormControlEvent): void {
|
onFocus(event: DynamicFormControlEvent): void {
|
||||||
const value = this.formOperationsService.getFieldValueFromChangeEvent(event);
|
const value = this.formOperationsService.getFieldValueFromChangeEvent(event);
|
||||||
@@ -324,6 +343,9 @@ export class FormSectionComponent extends SectionModelComponent {
|
|||||||
/**
|
/**
|
||||||
* Method called when a form remove event is fired.
|
* Method called when a form remove event is fired.
|
||||||
* Dispatch form operations based on changes.
|
* Dispatch form operations based on changes.
|
||||||
|
*
|
||||||
|
* @param event
|
||||||
|
* the [[DynamicFormControlEvent]] emitted
|
||||||
*/
|
*/
|
||||||
onRemove(event: DynamicFormControlEvent): void {
|
onRemove(event: DynamicFormControlEvent): void {
|
||||||
this.formOperationsService.dispatchOperationsFromEvent(
|
this.formOperationsService.dispatchOperationsFromEvent(
|
||||||
|
@@ -29,6 +29,9 @@ import { SectionsService } from '../sections.service';
|
|||||||
import { SectionFormOperationsService } from '../form/section-form-operations.service';
|
import { SectionFormOperationsService } from '../form/section-form-operations.service';
|
||||||
import { FormComponent } from '../../../shared/form/form.component';
|
import { FormComponent } from '../../../shared/form/form.component';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This component represents a section that contains the submission license form.
|
||||||
|
*/
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'ds-submission-section-license',
|
selector: 'ds-submission-section-license',
|
||||||
styleUrls: ['./section-license.component.scss'],
|
styleUrls: ['./section-license.component.scss'],
|
||||||
@@ -37,17 +40,68 @@ import { FormComponent } from '../../../shared/form/form.component';
|
|||||||
@renderSectionFor(SectionsType.License)
|
@renderSectionFor(SectionsType.License)
|
||||||
export class LicenseSectionComponent extends SectionModelComponent {
|
export class LicenseSectionComponent extends SectionModelComponent {
|
||||||
|
|
||||||
public formId;
|
/**
|
||||||
|
* The form id
|
||||||
|
* @type {string}
|
||||||
|
*/
|
||||||
|
public formId: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The form model
|
||||||
|
* @type {DynamicFormControlModel[]}
|
||||||
|
*/
|
||||||
public formModel: DynamicFormControlModel[];
|
public formModel: DynamicFormControlModel[];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The [[DynamicFormLayout]] object
|
||||||
|
* @type {DynamicFormLayout}
|
||||||
|
*/
|
||||||
public formLayout: DynamicFormLayout = SECTION_LICENSE_FORM_LAYOUT;
|
public formLayout: DynamicFormLayout = SECTION_LICENSE_FORM_LAYOUT;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A boolean representing if to show form submit and cancel buttons
|
||||||
|
* @type {boolean}
|
||||||
|
*/
|
||||||
public displaySubmit = false;
|
public displaySubmit = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The submission license text
|
||||||
|
* @type {Array}
|
||||||
|
*/
|
||||||
public licenseText$: Observable<string>;
|
public licenseText$: Observable<string>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The [[JsonPatchOperationPathCombiner]] object
|
||||||
|
* @type {JsonPatchOperationPathCombiner}
|
||||||
|
*/
|
||||||
protected pathCombiner: JsonPatchOperationPathCombiner;
|
protected pathCombiner: JsonPatchOperationPathCombiner;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Array to track all subscriptions and unsubscribe them onDestroy
|
||||||
|
* @type {Array}
|
||||||
|
*/
|
||||||
protected subs: Subscription[] = [];
|
protected subs: Subscription[] = [];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The FormComponent reference
|
||||||
|
*/
|
||||||
@ViewChild('formRef') private formRef: FormComponent;
|
@ViewChild('formRef') private formRef: FormComponent;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize instance variables
|
||||||
|
*
|
||||||
|
* @param {ChangeDetectorRef} changeDetectorRef
|
||||||
|
* @param {CollectionDataService} collectionDataService
|
||||||
|
* @param {FormBuilderService} formBuilderService
|
||||||
|
* @param {SectionFormOperationsService} formOperationsService
|
||||||
|
* @param {FormService} formService
|
||||||
|
* @param {JsonPatchOperationsBuilder} operationsBuilder
|
||||||
|
* @param {SectionsService} sectionService
|
||||||
|
* @param {SubmissionService} submissionService
|
||||||
|
* @param {string} injectedCollectionId
|
||||||
|
* @param {SectionDataObject} injectedSectionData
|
||||||
|
* @param {string} injectedSubmissionId
|
||||||
|
*/
|
||||||
constructor(protected changeDetectorRef: ChangeDetectorRef,
|
constructor(protected changeDetectorRef: ChangeDetectorRef,
|
||||||
protected collectionDataService: CollectionDataService,
|
protected collectionDataService: CollectionDataService,
|
||||||
protected formBuilderService: FormBuilderService,
|
protected formBuilderService: FormBuilderService,
|
||||||
@@ -62,6 +116,9 @@ export class LicenseSectionComponent extends SectionModelComponent {
|
|||||||
super(injectedCollectionId, injectedSectionData, injectedSubmissionId);
|
super(injectedCollectionId, injectedSectionData, injectedSubmissionId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize all instance variables and retrieve submission license
|
||||||
|
*/
|
||||||
onSectionInit() {
|
onSectionInit() {
|
||||||
this.pathCombiner = new JsonPatchOperationPathCombiner('sections', this.sectionData.id);
|
this.pathCombiner = new JsonPatchOperationPathCombiner('sections', this.sectionData.id);
|
||||||
this.formId = this.formService.getUniqueId(this.sectionData.id);
|
this.formId = this.formService.getUniqueId(this.sectionData.id);
|
||||||
@@ -126,6 +183,12 @@ export class LicenseSectionComponent extends SectionModelComponent {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get section status
|
||||||
|
*
|
||||||
|
* @return Observable<boolean>
|
||||||
|
* the section status
|
||||||
|
*/
|
||||||
protected getSectionStatus(): Observable<boolean> {
|
protected getSectionStatus(): Observable<boolean> {
|
||||||
const model = this.formBuilderService.findById('granted', this.formModel);
|
const model = this.formBuilderService.findById('granted', this.formModel);
|
||||||
return (model as DynamicCheckboxModel).valueUpdates.pipe(
|
return (model as DynamicCheckboxModel).valueUpdates.pipe(
|
||||||
@@ -133,6 +196,10 @@ export class LicenseSectionComponent extends SectionModelComponent {
|
|||||||
startWith((model as DynamicCheckboxModel).value));
|
startWith((model as DynamicCheckboxModel).value));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method called when a form dfChange event is fired.
|
||||||
|
* Dispatch form operations based on changes.
|
||||||
|
*/
|
||||||
onChange(event: DynamicFormControlEvent) {
|
onChange(event: DynamicFormControlEvent) {
|
||||||
const path = this.formOperationsService.getFieldPathSegmentedFromChangeEvent(event);
|
const path = this.formOperationsService.getFieldPathSegmentedFromChangeEvent(event);
|
||||||
const value = this.formOperationsService.getFieldValueFromChangeEvent(event);
|
const value = this.formOperationsService.getFieldValueFromChangeEvent(event);
|
||||||
@@ -145,6 +212,9 @@ export class LicenseSectionComponent extends SectionModelComponent {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unsubscribe from all subscriptions
|
||||||
|
*/
|
||||||
onSectionDestroy() {
|
onSectionDestroy() {
|
||||||
this.subs
|
this.subs
|
||||||
.filter((subscription) => hasValue(subscription))
|
.filter((subscription) => hasValue(subscription))
|
||||||
|
@@ -2,14 +2,48 @@ import { SubmissionSectionError } from '../../objects/submission-objects.reducer
|
|||||||
import { WorkspaceitemSectionDataType } from '../../../core/submission/models/workspaceitem-sections.model';
|
import { WorkspaceitemSectionDataType } from '../../../core/submission/models/workspaceitem-sections.model';
|
||||||
import { SectionsType } from '../sections-type';
|
import { SectionsType } from '../sections-type';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An interface to represent section model
|
||||||
|
*/
|
||||||
export interface SectionDataObject {
|
export interface SectionDataObject {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The section configuration url
|
||||||
|
*/
|
||||||
config: string;
|
config: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The section data object
|
||||||
|
*/
|
||||||
data: WorkspaceitemSectionDataType;
|
data: WorkspaceitemSectionDataType;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The list of the section errors
|
||||||
|
*/
|
||||||
errors: SubmissionSectionError[];
|
errors: SubmissionSectionError[];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The section header
|
||||||
|
*/
|
||||||
header: string;
|
header: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The section id
|
||||||
|
*/
|
||||||
id: string;
|
id: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A boolean representing if this section is mandatory
|
||||||
|
*/
|
||||||
mandatory: boolean;
|
mandatory: boolean;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The section type
|
||||||
|
*/
|
||||||
sectionType: SectionsType;
|
sectionType: SectionsType;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Eventually additional fields
|
||||||
|
*/
|
||||||
[propName: string]: any;
|
[propName: string]: any;
|
||||||
}
|
}
|
||||||
|
@@ -16,12 +16,44 @@ export interface SectionDataModel {
|
|||||||
*/
|
*/
|
||||||
export abstract class SectionModelComponent implements OnDestroy, OnInit, SectionDataModel {
|
export abstract class SectionModelComponent implements OnDestroy, OnInit, SectionDataModel {
|
||||||
protected abstract sectionService: SectionsService;
|
protected abstract sectionService: SectionsService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The collection id this submission belonging to
|
||||||
|
* @type {string}
|
||||||
|
*/
|
||||||
collectionId: string;
|
collectionId: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The section data
|
||||||
|
* @type {SectionDataObject}
|
||||||
|
*/
|
||||||
sectionData: SectionDataObject;
|
sectionData: SectionDataObject;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The submission id
|
||||||
|
* @type {string}
|
||||||
|
*/
|
||||||
submissionId: string;
|
submissionId: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A boolean representing if this section is valid
|
||||||
|
* @type {boolean}
|
||||||
|
*/
|
||||||
protected valid: boolean;
|
protected valid: boolean;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The Subscription to section status observable
|
||||||
|
* @type {Subscription}
|
||||||
|
*/
|
||||||
private sectionStatusSub: Subscription;
|
private sectionStatusSub: Subscription;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize instance variables
|
||||||
|
*
|
||||||
|
* @param {string} injectedCollectionId
|
||||||
|
* @param {SectionDataObject} injectedSectionData
|
||||||
|
* @param {string} injectedSubmissionId
|
||||||
|
*/
|
||||||
public constructor(@Inject('collectionIdProvider') public injectedCollectionId: string,
|
public constructor(@Inject('collectionIdProvider') public injectedCollectionId: string,
|
||||||
@Inject('sectionDataProvider') public injectedSectionData: SectionDataObject,
|
@Inject('sectionDataProvider') public injectedSectionData: SectionDataObject,
|
||||||
@Inject('submissionIdProvider') public injectedSubmissionId: string) {
|
@Inject('submissionIdProvider') public injectedSubmissionId: string) {
|
||||||
@@ -30,15 +62,43 @@ export abstract class SectionModelComponent implements OnDestroy, OnInit, Sectio
|
|||||||
this.submissionId = injectedSubmissionId;
|
this.submissionId = injectedSubmissionId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Call abstract methods on component init
|
||||||
|
*/
|
||||||
ngOnInit(): void {
|
ngOnInit(): void {
|
||||||
this.onSectionInit();
|
this.onSectionInit();
|
||||||
this.updateSectionStatus();
|
this.updateSectionStatus();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Abstract method to implement to get section status
|
||||||
|
*
|
||||||
|
* @return Observable<boolean>
|
||||||
|
* the section status
|
||||||
|
*/
|
||||||
protected abstract getSectionStatus(): Observable<boolean>;
|
protected abstract getSectionStatus(): Observable<boolean>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Abstract method called on component init.
|
||||||
|
* It must be used instead of ngOnInit on the component that extend this abstract class
|
||||||
|
*
|
||||||
|
* @return Observable<boolean>
|
||||||
|
* the section status
|
||||||
|
*/
|
||||||
protected abstract onSectionInit(): void;
|
protected abstract onSectionInit(): void;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Abstract method called on component destroy.
|
||||||
|
* It must be used instead of ngOnDestroy on the component that extend this abstract class
|
||||||
|
*
|
||||||
|
* @return Observable<boolean>
|
||||||
|
* the section status
|
||||||
|
*/
|
||||||
protected abstract onSectionDestroy(): void;
|
protected abstract onSectionDestroy(): void;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Subscribe to section status
|
||||||
|
*/
|
||||||
protected updateSectionStatus(): void {
|
protected updateSectionStatus(): void {
|
||||||
this.sectionStatusSub = this.getSectionStatus().pipe(
|
this.sectionStatusSub = this.getSectionStatus().pipe(
|
||||||
filter((sectionStatus: boolean) => isNotUndefined(sectionStatus)),
|
filter((sectionStatus: boolean) => isNotUndefined(sectionStatus)),
|
||||||
@@ -48,6 +108,9 @@ export abstract class SectionModelComponent implements OnDestroy, OnInit, Sectio
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unsubscribe from all subscriptions and Call abstract methods on component destroy
|
||||||
|
*/
|
||||||
ngOnDestroy(): void {
|
ngOnDestroy(): void {
|
||||||
if (hasValue(this.sectionStatusSub)) {
|
if (hasValue(this.sectionStatusSub)) {
|
||||||
this.sectionStatusSub.unsubscribe();
|
this.sectionStatusSub.unsubscribe();
|
||||||
|
@@ -10,28 +10,90 @@ import { SubmissionSectionError, SubmissionSectionObject } from '../objects/subm
|
|||||||
import parseSectionErrorPaths, { SectionErrorPath } from '../utils/parseSectionErrorPaths';
|
import parseSectionErrorPaths, { SectionErrorPath } from '../utils/parseSectionErrorPaths';
|
||||||
import { SubmissionService } from '../submission.service';
|
import { SubmissionService } from '../submission.service';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Directive for handling generic section functionality
|
||||||
|
*/
|
||||||
@Directive({
|
@Directive({
|
||||||
selector: '[dsSection]',
|
selector: '[dsSection]',
|
||||||
exportAs: 'sectionRef'
|
exportAs: 'sectionRef'
|
||||||
})
|
})
|
||||||
export class SectionsDirective implements OnDestroy, OnInit {
|
export class SectionsDirective implements OnDestroy, OnInit {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A boolean representing if section is mandatory
|
||||||
|
* @type {boolean}
|
||||||
|
*/
|
||||||
@Input() mandatory = true;
|
@Input() mandatory = true;
|
||||||
@Input() sectionId;
|
|
||||||
@Input() submissionId;
|
/**
|
||||||
|
* The section id
|
||||||
|
* @type {string}
|
||||||
|
*/
|
||||||
|
@Input() sectionId: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The submission id
|
||||||
|
* @type {string}
|
||||||
|
*/
|
||||||
|
@Input() submissionId: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The list of generic errors related to the section
|
||||||
|
* @type {Array}
|
||||||
|
*/
|
||||||
public genericSectionErrors: string[] = [];
|
public genericSectionErrors: string[] = [];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The list of all errors related to the element belonging to this section
|
||||||
|
* @type {Array}
|
||||||
|
*/
|
||||||
public allSectionErrors: string[] = [];
|
public allSectionErrors: string[] = [];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A boolean representing if section is active
|
||||||
|
* @type {boolean}
|
||||||
|
*/
|
||||||
private active = true;
|
private active = true;
|
||||||
private animation = !this.mandatory;
|
|
||||||
|
/**
|
||||||
|
* A boolean representing if section is enabled
|
||||||
|
* @type {boolean}
|
||||||
|
*/
|
||||||
private enabled: Observable<boolean>;
|
private enabled: Observable<boolean>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A boolean representing the panel collapsible state: opened (true) or closed (false)
|
||||||
|
* @type {boolean}
|
||||||
|
*/
|
||||||
private sectionState = this.mandatory;
|
private sectionState = this.mandatory;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Array to track all subscriptions and unsubscribe them onDestroy
|
||||||
|
* @type {Array}
|
||||||
|
*/
|
||||||
private subs: Subscription[] = [];
|
private subs: Subscription[] = [];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A boolean representing if section is valid
|
||||||
|
* @type {boolean}
|
||||||
|
*/
|
||||||
private valid: Observable<boolean>;
|
private valid: Observable<boolean>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize instance variables
|
||||||
|
*
|
||||||
|
* @param {ChangeDetectorRef} changeDetectorRef
|
||||||
|
* @param {SubmissionService} submissionService
|
||||||
|
* @param {SectionsService} sectionService
|
||||||
|
*/
|
||||||
constructor(private changeDetectorRef: ChangeDetectorRef,
|
constructor(private changeDetectorRef: ChangeDetectorRef,
|
||||||
private submissionService: SubmissionService,
|
private submissionService: SubmissionService,
|
||||||
private sectionService: SectionsService) {
|
private sectionService: SectionsService) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize instance variables
|
||||||
|
*/
|
||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
this.valid = this.sectionService.isSectionValid(this.submissionId, this.sectionId).pipe(
|
this.valid = this.sectionService.isSectionValid(this.submissionId, this.sectionId).pipe(
|
||||||
map((valid: boolean) => {
|
map((valid: boolean) => {
|
||||||
@@ -78,67 +140,145 @@ export class SectionsDirective implements OnDestroy, OnInit {
|
|||||||
this.enabled = this.sectionService.isSectionEnabled(this.submissionId, this.sectionId);
|
this.enabled = this.sectionService.isSectionEnabled(this.submissionId, this.sectionId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unsubscribe from all subscriptions
|
||||||
|
*/
|
||||||
ngOnDestroy() {
|
ngOnDestroy() {
|
||||||
this.subs
|
this.subs
|
||||||
.filter((subscription) => hasValue(subscription))
|
.filter((subscription) => hasValue(subscription))
|
||||||
.forEach((subscription) => subscription.unsubscribe());
|
.forEach((subscription) => subscription.unsubscribe());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Change section state
|
||||||
|
*
|
||||||
|
* @param event
|
||||||
|
* the event emitted
|
||||||
|
*/
|
||||||
public sectionChange(event) {
|
public sectionChange(event) {
|
||||||
this.sectionState = event.nextState;
|
this.sectionState = event.nextState;
|
||||||
}
|
}
|
||||||
|
|
||||||
public isOpen() {
|
/**
|
||||||
|
* Check if section panel is open
|
||||||
|
*
|
||||||
|
* @returns {boolean}
|
||||||
|
* Returns true when section panel is open
|
||||||
|
*/
|
||||||
|
public isOpen(): boolean {
|
||||||
return this.sectionState;
|
return this.sectionState;
|
||||||
}
|
}
|
||||||
|
|
||||||
public isMandatory() {
|
/**
|
||||||
|
* Check if section is mandatory
|
||||||
|
*
|
||||||
|
* @returns {boolean}
|
||||||
|
* Returns true when section is mandatory
|
||||||
|
*/
|
||||||
|
public isMandatory(): boolean {
|
||||||
return this.mandatory;
|
return this.mandatory;
|
||||||
}
|
}
|
||||||
|
|
||||||
public isAnimationsActive() {
|
/**
|
||||||
return this.animation;
|
* Check if section panel is active
|
||||||
}
|
*
|
||||||
|
* @returns {boolean}
|
||||||
|
* Returns true when section panel is active
|
||||||
|
*/
|
||||||
public isSectionActive(): boolean {
|
public isSectionActive(): boolean {
|
||||||
return this.active;
|
return this.active;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if section is enabled
|
||||||
|
*
|
||||||
|
* @returns {Observable<boolean>}
|
||||||
|
* Emits true whenever section is enabled
|
||||||
|
*/
|
||||||
public isEnabled(): Observable<boolean> {
|
public isEnabled(): Observable<boolean> {
|
||||||
return this.enabled;
|
return this.enabled;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if section is valid
|
||||||
|
*
|
||||||
|
* @returns {Observable<boolean>}
|
||||||
|
* Emits true whenever section is valid
|
||||||
|
*/
|
||||||
public isValid(): Observable<boolean> {
|
public isValid(): Observable<boolean> {
|
||||||
return this.valid;
|
return this.valid;
|
||||||
}
|
}
|
||||||
|
|
||||||
public removeSection(submissionId, sectionId) {
|
/**
|
||||||
|
* Remove section panel from submission form
|
||||||
|
*
|
||||||
|
* @param submissionId
|
||||||
|
* the submission id
|
||||||
|
* @param sectionId
|
||||||
|
* the section id
|
||||||
|
* @returns {Observable<boolean>}
|
||||||
|
* Emits true whenever section is valid
|
||||||
|
*/
|
||||||
|
public removeSection(submissionId: string, sectionId: string) {
|
||||||
this.sectionService.removeSection(submissionId, sectionId)
|
this.sectionService.removeSection(submissionId, sectionId)
|
||||||
}
|
}
|
||||||
|
|
||||||
public hasGenericErrors() {
|
/**
|
||||||
|
* Check if section has only generic errors
|
||||||
|
*
|
||||||
|
* @returns {boolean}
|
||||||
|
* Returns true when section has only generic errors
|
||||||
|
*/
|
||||||
|
public hasGenericErrors(): boolean {
|
||||||
return this.genericSectionErrors && this.genericSectionErrors.length > 0
|
return this.genericSectionErrors && this.genericSectionErrors.length > 0
|
||||||
}
|
}
|
||||||
|
|
||||||
public hasErrors() {
|
/**
|
||||||
|
* Check if section has errors
|
||||||
|
*
|
||||||
|
* @returns {boolean}
|
||||||
|
* Returns true when section has errors
|
||||||
|
*/
|
||||||
|
public hasErrors(): boolean {
|
||||||
return (this.genericSectionErrors && this.genericSectionErrors.length > 0) ||
|
return (this.genericSectionErrors && this.genericSectionErrors.length > 0) ||
|
||||||
(this.allSectionErrors && this.allSectionErrors.length > 0)
|
(this.allSectionErrors && this.allSectionErrors.length > 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
public getErrors() {
|
/**
|
||||||
|
* Return section errors
|
||||||
|
*
|
||||||
|
* @returns {Array}
|
||||||
|
* Returns section errors list
|
||||||
|
*/
|
||||||
|
public getErrors(): string[] {
|
||||||
return this.genericSectionErrors;
|
return this.genericSectionErrors;
|
||||||
}
|
}
|
||||||
|
|
||||||
public setFocus(event) {
|
/**
|
||||||
|
* Set form focus to this section panel
|
||||||
|
*
|
||||||
|
* @param event
|
||||||
|
* The event emitted
|
||||||
|
*/
|
||||||
|
public setFocus(event): void {
|
||||||
if (!this.active) {
|
if (!this.active) {
|
||||||
this.submissionService.setActiveSection(this.submissionId, this.sectionId);
|
this.submissionService.setActiveSection(this.submissionId, this.sectionId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public removeError(index) {
|
/**
|
||||||
|
* Remove error from list
|
||||||
|
*
|
||||||
|
* @param index
|
||||||
|
* The error array key
|
||||||
|
*/
|
||||||
|
public removeError(index): void {
|
||||||
this.genericSectionErrors.splice(index);
|
this.genericSectionErrors.splice(index);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove all errors from list
|
||||||
|
*/
|
||||||
public resetErrors() {
|
public resetErrors() {
|
||||||
if (isNotEmpty(this.genericSectionErrors)) {
|
if (isNotEmpty(this.genericSectionErrors)) {
|
||||||
this.sectionService.dispatchRemoveSectionErrors(this.submissionId, this.sectionId);
|
this.sectionService.dispatchRemoveSectionErrors(this.submissionId, this.sectionId);
|
||||||
|
@@ -8,18 +8,37 @@ import { isEmpty } from '../../../../shared/empty.util';
|
|||||||
import { Group } from '../../../../core/eperson/models/group.model';
|
import { Group } from '../../../../core/eperson/models/group.model';
|
||||||
import { RemoteData } from '../../../../core/data/remote-data';
|
import { RemoteData } from '../../../../core/data/remote-data';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This component represents a badge that describe an access condition
|
||||||
|
*/
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'ds-section-upload-access-conditions',
|
selector: 'ds-section-upload-access-conditions',
|
||||||
templateUrl: './section-upload-access-conditions.component.html',
|
templateUrl: './section-upload-access-conditions.component.html',
|
||||||
})
|
})
|
||||||
export class SectionUploadAccessConditionsComponent implements OnInit {
|
export class SectionUploadAccessConditionsComponent implements OnInit {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The list of resource policy
|
||||||
|
* @type {Array}
|
||||||
|
*/
|
||||||
@Input() accessConditions: ResourcePolicy[];
|
@Input() accessConditions: ResourcePolicy[];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The list of access conditions
|
||||||
|
* @type {Array}
|
||||||
|
*/
|
||||||
public accessConditionsList = [];
|
public accessConditionsList = [];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize instance variables
|
||||||
|
*
|
||||||
|
* @param {GroupEpersonService} groupService
|
||||||
|
*/
|
||||||
constructor(private groupService: GroupEpersonService) {}
|
constructor(private groupService: GroupEpersonService) {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve access conditions list
|
||||||
|
*/
|
||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
this.accessConditions.forEach((accessCondition: ResourcePolicy) => {
|
this.accessConditions.forEach((accessCondition: ResourcePolicy) => {
|
||||||
if (isEmpty(accessCondition.name)) {
|
if (isEmpty(accessCondition.name)) {
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
import { ChangeDetectorRef, Component, Input, OnChanges, ViewChild } from '@angular/core';
|
import { ChangeDetectorRef, Component, Input, OnChanges, ViewChild } from '@angular/core';
|
||||||
|
import { FormControl } from '@angular/forms';
|
||||||
|
|
||||||
import { WorkspaceitemSectionUploadFileObject } from '../../../../../core/submission/models/workspaceitem-section-upload-file.model';
|
|
||||||
import {
|
import {
|
||||||
DYNAMIC_FORM_CONTROL_TYPE_DATEPICKER,
|
DYNAMIC_FORM_CONTROL_TYPE_DATEPICKER,
|
||||||
DynamicDateControlModel,
|
DynamicDateControlModel,
|
||||||
@@ -12,6 +12,8 @@ import {
|
|||||||
DynamicFormGroupModel,
|
DynamicFormGroupModel,
|
||||||
DynamicSelectModel
|
DynamicSelectModel
|
||||||
} from '@ng-dynamic-forms/core';
|
} from '@ng-dynamic-forms/core';
|
||||||
|
|
||||||
|
import { WorkspaceitemSectionUploadFileObject } from '../../../../../core/submission/models/workspaceitem-section-upload-file.model';
|
||||||
import { FormBuilderService } from '../../../../../shared/form/builder/form-builder.service';
|
import { FormBuilderService } from '../../../../../shared/form/builder/form-builder.service';
|
||||||
import {
|
import {
|
||||||
BITSTREAM_ACCESS_CONDITIONS_FORM_ARRAY_CONFIG,
|
BITSTREAM_ACCESS_CONDITIONS_FORM_ARRAY_CONFIG,
|
||||||
@@ -35,37 +37,113 @@ import { AccessConditionOption } from '../../../../../core/config/models/config-
|
|||||||
import { SubmissionService } from '../../../../submission.service';
|
import { SubmissionService } from '../../../../submission.service';
|
||||||
import { FormService } from '../../../../../shared/form/form.service';
|
import { FormService } from '../../../../../shared/form/form.service';
|
||||||
import { FormComponent } from '../../../../../shared/form/form.component';
|
import { FormComponent } from '../../../../../shared/form/form.component';
|
||||||
import { FormControl } from '@angular/forms';
|
|
||||||
import { Group } from '../../../../../core/eperson/models/group.model';
|
import { Group } from '../../../../../core/eperson/models/group.model';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This component represents the edit form for bitstream
|
||||||
|
*/
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'ds-submission-upload-section-file-edit',
|
selector: 'ds-submission-upload-section-file-edit',
|
||||||
templateUrl: './section-upload-file-edit.component.html',
|
templateUrl: './section-upload-file-edit.component.html',
|
||||||
})
|
})
|
||||||
export class UploadSectionFileEditComponent implements OnChanges {
|
export class UploadSectionFileEditComponent implements OnChanges {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The list of available access condition
|
||||||
|
* @type {Array}
|
||||||
|
*/
|
||||||
@Input() availableAccessConditionOptions: any[];
|
@Input() availableAccessConditionOptions: any[];
|
||||||
@Input() availableAccessConditionGroups: Map<string, Group[]>;
|
|
||||||
@Input() collectionId;
|
|
||||||
@Input() collectionPolicyType;
|
|
||||||
@Input() configMetadataForm: SubmissionFormsModel;
|
|
||||||
@Input() fileData: WorkspaceitemSectionUploadFileObject;
|
|
||||||
@Input() fileId;
|
|
||||||
@Input() fileIndex;
|
|
||||||
@Input() formId;
|
|
||||||
@Input() sectionId;
|
|
||||||
@Input() submissionId;
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The list of available groups for an access condition
|
||||||
|
* @type {Array}
|
||||||
|
*/
|
||||||
|
@Input() availableAccessConditionGroups: Map<string, Group[]>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The submission id
|
||||||
|
* @type {string}
|
||||||
|
*/
|
||||||
|
@Input() collectionId: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Define if collection access conditions policy type :
|
||||||
|
* POLICY_DEFAULT_NO_LIST : is not possible to define additional access group/s for the single file
|
||||||
|
* POLICY_DEFAULT_WITH_LIST : is possible to define additional access group/s for the single file
|
||||||
|
* @type {number}
|
||||||
|
*/
|
||||||
|
@Input() collectionPolicyType: number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The configuration for the bitstream's metadata form
|
||||||
|
* @type {SubmissionFormsModel}
|
||||||
|
*/
|
||||||
|
@Input() configMetadataForm: SubmissionFormsModel;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The bitstream's metadata data
|
||||||
|
* @type {WorkspaceitemSectionUploadFileObject}
|
||||||
|
*/
|
||||||
|
@Input() fileData: WorkspaceitemSectionUploadFileObject;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The bitstream id
|
||||||
|
* @type {string}
|
||||||
|
*/
|
||||||
|
@Input() fileId: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The bitstream array key
|
||||||
|
* @type {string}
|
||||||
|
*/
|
||||||
|
@Input() fileIndex: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The form id
|
||||||
|
* @type {string}
|
||||||
|
*/
|
||||||
|
@Input() formId: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The section id
|
||||||
|
* @type {string}
|
||||||
|
*/
|
||||||
|
@Input() sectionId: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The submission id
|
||||||
|
* @type {string}
|
||||||
|
*/
|
||||||
|
@Input() submissionId: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The form model
|
||||||
|
* @type {DynamicFormControlModel[]}
|
||||||
|
*/
|
||||||
public formModel: DynamicFormControlModel[];
|
public formModel: DynamicFormControlModel[];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The FormComponent reference
|
||||||
|
*/
|
||||||
@ViewChild('formRef') public formRef: FormComponent;
|
@ViewChild('formRef') public formRef: FormComponent;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize instance variables
|
||||||
|
*
|
||||||
|
* @param {ChangeDetectorRef} cdr
|
||||||
|
* @param {FormBuilderService} formBuilderService
|
||||||
|
* @param {FormService} formService
|
||||||
|
* @param {SubmissionService} submissionService
|
||||||
|
*/
|
||||||
constructor(private cdr: ChangeDetectorRef,
|
constructor(private cdr: ChangeDetectorRef,
|
||||||
private formBuilderService: FormBuilderService,
|
private formBuilderService: FormBuilderService,
|
||||||
private formService: FormService,
|
private formService: FormService,
|
||||||
private submissionService: SubmissionService) {
|
private submissionService: SubmissionService) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Dispatch form model init
|
||||||
|
*/
|
||||||
ngOnChanges() {
|
ngOnChanges() {
|
||||||
if (this.fileData && this.formId) {
|
if (this.fileData && this.formId) {
|
||||||
this.formModel = this.buildFileEditForm();
|
this.formModel = this.buildFileEditForm();
|
||||||
@@ -73,8 +151,10 @@ export class UploadSectionFileEditComponent implements OnChanges {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize form model
|
||||||
|
*/
|
||||||
protected buildFileEditForm() {
|
protected buildFileEditForm() {
|
||||||
// TODO check in the rest server configuration whether dc.description may be repeatable
|
|
||||||
const configDescr: FormFieldModel = Object.assign({}, this.configMetadataForm.rows[0].fields[0]);
|
const configDescr: FormFieldModel = Object.assign({}, this.configMetadataForm.rows[0].fields[0]);
|
||||||
configDescr.repeatable = false;
|
configDescr.repeatable = false;
|
||||||
const configForm = Object.assign({}, this.configMetadataForm, {
|
const configForm = Object.assign({}, this.configMetadataForm, {
|
||||||
@@ -107,7 +187,7 @@ export class UploadSectionFileEditComponent implements OnChanges {
|
|||||||
}
|
}
|
||||||
accessConditionTypeModelConfig.options = accessConditionTypeOptions;
|
accessConditionTypeModelConfig.options = accessConditionTypeOptions;
|
||||||
|
|
||||||
// Dynamic assign of relation in config. For startdate, endDate, groups.
|
// Dynamically assign of relation in config. For startdate, endDate, groups.
|
||||||
const hasStart = [];
|
const hasStart = [];
|
||||||
const hasEnd = [];
|
const hasEnd = [];
|
||||||
const hasGroups = [];
|
const hasGroups = [];
|
||||||
@@ -153,6 +233,12 @@ export class UploadSectionFileEditComponent implements OnChanges {
|
|||||||
return formModel;
|
return formModel;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize form model values
|
||||||
|
*
|
||||||
|
* @param formModel
|
||||||
|
* The form model
|
||||||
|
*/
|
||||||
public initModelData(formModel: DynamicFormControlModel[]) {
|
public initModelData(formModel: DynamicFormControlModel[]) {
|
||||||
this.fileData.accessConditions.forEach((accessCondition, index) => {
|
this.fileData.accessConditions.forEach((accessCondition, index) => {
|
||||||
Array.of('name', 'groupUUID', 'startDate', 'endDate')
|
Array.of('name', 'groupUUID', 'startDate', 'endDate')
|
||||||
@@ -183,22 +269,36 @@ export class UploadSectionFileEditComponent implements OnChanges {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Dispatch form model update when changing an access condition
|
||||||
|
*
|
||||||
|
* @param formModel
|
||||||
|
* The form model
|
||||||
|
*/
|
||||||
public onChange(event: DynamicFormControlEvent) {
|
public onChange(event: DynamicFormControlEvent) {
|
||||||
if (event.model.id === 'name') {
|
if (event.model.id === 'name') {
|
||||||
this.setOptions(event.model, event.control);
|
this.setOptions(event.model, event.control);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public setOptions(model, control) {
|
/**
|
||||||
|
* Update `startDate`, 'groupUUID' and 'endDate' model
|
||||||
|
*
|
||||||
|
* @param model
|
||||||
|
* The [[DynamicFormControlModel]] object
|
||||||
|
* @param control
|
||||||
|
* The [[FormControl]] object
|
||||||
|
*/
|
||||||
|
public setOptions(model: DynamicFormControlModel, control: FormControl) {
|
||||||
let accessCondition: AccessConditionOption = null;
|
let accessCondition: AccessConditionOption = null;
|
||||||
this.availableAccessConditionOptions.filter((element) => element.name === control.value)
|
this.availableAccessConditionOptions.filter((element) => element.name === control.value)
|
||||||
.forEach((element) => accessCondition = element);
|
.forEach((element) => accessCondition = element);
|
||||||
if (isNotEmpty(accessCondition)) {
|
if (isNotEmpty(accessCondition)) {
|
||||||
const showGroups: boolean = accessCondition.hasStartDate === true || accessCondition.hasEndDate === true;
|
const showGroups: boolean = accessCondition.hasStartDate === true || accessCondition.hasEndDate === true;
|
||||||
|
|
||||||
const groupControl: FormControl = control.parent.get('groupUUID');
|
const groupControl: FormControl = control.parent.get('groupUUID') as FormControl;
|
||||||
const startDateControl: FormControl = control.parent.get('startDate');
|
const startDateControl: FormControl = control.parent.get('startDate') as FormControl;
|
||||||
const endDateControl: FormControl = control.parent.get('endDate');
|
const endDateControl: FormControl = control.parent.get('endDate') as FormControl;
|
||||||
|
|
||||||
// Clear previous state
|
// Clear previous state
|
||||||
groupControl.markAsUntouched();
|
groupControl.markAsUntouched();
|
||||||
@@ -236,8 +336,8 @@ export class UploadSectionFileEditComponent implements OnChanges {
|
|||||||
const confGroup = { relation: groupModel.relation };
|
const confGroup = { relation: groupModel.relation };
|
||||||
const groupsConfig = Object.assign({}, BITSTREAM_FORM_ACCESS_CONDITION_GROUPS_CONFIG, confGroup);
|
const groupsConfig = Object.assign({}, BITSTREAM_FORM_ACCESS_CONDITION_GROUPS_CONFIG, confGroup);
|
||||||
groupsConfig.options = groupOptions;
|
groupsConfig.options = groupOptions;
|
||||||
model.parent.group.pop();
|
(model.parent as DynamicFormGroupModel).group.pop();
|
||||||
model.parent.group.push(new DynamicSelectModel(groupsConfig, BITSTREAM_FORM_ACCESS_CONDITION_GROUPS_LAYOUT));
|
(model.parent as DynamicFormGroupModel).group.push(new DynamicSelectModel(groupsConfig, BITSTREAM_FORM_ACCESS_CONDITION_GROUPS_LAYOUT));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
import { ChangeDetectorRef, Component, Input, OnChanges, OnInit, ViewChild } from '@angular/core';
|
import { ChangeDetectorRef, Component, Input, OnChanges, OnInit, ViewChild } from '@angular/core';
|
||||||
|
|
||||||
import { BehaviorSubject } from 'rxjs';
|
import { BehaviorSubject, Subscription } from 'rxjs';
|
||||||
import { filter, first, flatMap, take } from 'rxjs/operators';
|
import { filter, first, flatMap, take } from 'rxjs/operators';
|
||||||
import { DynamicFormControlModel, } from '@ng-dynamic-forms/core';
|
import { DynamicFormControlModel, } from '@ng-dynamic-forms/core';
|
||||||
import { NgbModal } from '@ng-bootstrap/ng-bootstrap';
|
import { NgbModal } from '@ng-bootstrap/ng-bootstrap';
|
||||||
@@ -23,6 +23,9 @@ import { WorkspaceitemSectionUploadObject } from '../../../../core/submission/mo
|
|||||||
import { UploadSectionFileEditComponent } from './edit/section-upload-file-edit.component';
|
import { UploadSectionFileEditComponent } from './edit/section-upload-file-edit.component';
|
||||||
import { Group } from '../../../../core/eperson/models/group.model';
|
import { Group } from '../../../../core/eperson/models/group.model';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This component represents a single bitstream contained in the submission
|
||||||
|
*/
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'ds-submission-upload-section-file',
|
selector: 'ds-submission-upload-section-file',
|
||||||
styleUrls: ['./section-upload-file.component.scss'],
|
styleUrls: ['./section-upload-file.component.scss'],
|
||||||
@@ -30,28 +33,129 @@ import { Group } from '../../../../core/eperson/models/group.model';
|
|||||||
})
|
})
|
||||||
export class UploadSectionFileComponent implements OnChanges, OnInit {
|
export class UploadSectionFileComponent implements OnChanges, OnInit {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The list of available access condition
|
||||||
|
* @type {Array}
|
||||||
|
*/
|
||||||
@Input() availableAccessConditionOptions: any[];
|
@Input() availableAccessConditionOptions: any[];
|
||||||
@Input() availableAccessConditionGroups: Map<string, Group[]>;
|
|
||||||
@Input() collectionId;
|
|
||||||
@Input() collectionPolicyType;
|
|
||||||
@Input() configMetadataForm: SubmissionFormsModel;
|
|
||||||
@Input() fileId;
|
|
||||||
@Input() fileIndex;
|
|
||||||
@Input() fileName;
|
|
||||||
@Input() sectionId;
|
|
||||||
@Input() submissionId;
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The list of available groups for an access condition
|
||||||
|
* @type {Array}
|
||||||
|
*/
|
||||||
|
@Input() availableAccessConditionGroups: Map<string, Group[]>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The submission id
|
||||||
|
* @type {string}
|
||||||
|
*/
|
||||||
|
@Input() collectionId: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Define if collection access conditions policy type :
|
||||||
|
* POLICY_DEFAULT_NO_LIST : is not possible to define additional access group/s for the single file
|
||||||
|
* POLICY_DEFAULT_WITH_LIST : is possible to define additional access group/s for the single file
|
||||||
|
* @type {number}
|
||||||
|
*/
|
||||||
|
@Input() collectionPolicyType: number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The configuration for the bitstream's metadata form
|
||||||
|
* @type {SubmissionFormsModel}
|
||||||
|
*/
|
||||||
|
@Input() configMetadataForm: SubmissionFormsModel;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The bitstream id
|
||||||
|
* @type {string}
|
||||||
|
*/
|
||||||
|
@Input() fileId: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The bitstream array key
|
||||||
|
* @type {string}
|
||||||
|
*/
|
||||||
|
@Input() fileIndex: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The bitstream id
|
||||||
|
* @type {string}
|
||||||
|
*/
|
||||||
|
@Input() fileName: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The section id
|
||||||
|
* @type {string}
|
||||||
|
*/
|
||||||
|
@Input() sectionId: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The submission id
|
||||||
|
* @type {string}
|
||||||
|
*/
|
||||||
|
@Input() submissionId: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The bitstream's metadata data
|
||||||
|
* @type {WorkspaceitemSectionUploadFileObject}
|
||||||
|
*/
|
||||||
public fileData: WorkspaceitemSectionUploadFileObject;
|
public fileData: WorkspaceitemSectionUploadFileObject;
|
||||||
public formId;
|
|
||||||
public readMode;
|
/**
|
||||||
|
* The form id
|
||||||
|
* @type {string}
|
||||||
|
*/
|
||||||
|
public formId: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A boolean representing if to show bitstream edit form
|
||||||
|
* @type {boolean}
|
||||||
|
*/
|
||||||
|
public readMode: boolean;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The form model
|
||||||
|
* @type {DynamicFormControlModel[]}
|
||||||
|
*/
|
||||||
public formModel: DynamicFormControlModel[];
|
public formModel: DynamicFormControlModel[];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A boolean representing if a submission delete operation is pending
|
||||||
|
* @type {BehaviorSubject<boolean>}
|
||||||
|
*/
|
||||||
public processingDelete$ = new BehaviorSubject<boolean>(false);
|
public processingDelete$ = new BehaviorSubject<boolean>(false);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The [JsonPatchOperationPathCombiner] object
|
||||||
|
* @type {JsonPatchOperationPathCombiner}
|
||||||
|
*/
|
||||||
protected pathCombiner: JsonPatchOperationPathCombiner;
|
protected pathCombiner: JsonPatchOperationPathCombiner;
|
||||||
protected subscriptions = [];
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Array to track all subscriptions and unsubscribe them onDestroy
|
||||||
|
* @type {Array}
|
||||||
|
*/
|
||||||
|
protected subscriptions: Subscription[] = [];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The [[UploadSectionFileEditComponent]] reference
|
||||||
|
* @type {UploadSectionFileEditComponent}
|
||||||
|
*/
|
||||||
@ViewChild(UploadSectionFileEditComponent) fileEditComp: UploadSectionFileEditComponent;
|
@ViewChild(UploadSectionFileEditComponent) fileEditComp: UploadSectionFileEditComponent;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize instance variables
|
||||||
|
*
|
||||||
|
* @param {ChangeDetectorRef} cdr
|
||||||
|
* @param {FileService} fileService
|
||||||
|
* @param {FormService} formService
|
||||||
|
* @param {HALEndpointService} halService
|
||||||
|
* @param {NgbModal} modalService
|
||||||
|
* @param {JsonPatchOperationsBuilder} operationsBuilder
|
||||||
|
* @param {SubmissionJsonPatchOperationsService} operationsService
|
||||||
|
* @param {SubmissionService} submissionService
|
||||||
|
* @param {SectionUploadService} uploadService
|
||||||
|
*/
|
||||||
constructor(private cdr: ChangeDetectorRef,
|
constructor(private cdr: ChangeDetectorRef,
|
||||||
private fileService: FileService,
|
private fileService: FileService,
|
||||||
private formService: FormService,
|
private formService: FormService,
|
||||||
@@ -64,6 +168,9 @@ export class UploadSectionFileComponent implements OnChanges, OnInit {
|
|||||||
this.readMode = true;
|
this.readMode = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve bitstream's metadata
|
||||||
|
*/
|
||||||
ngOnChanges() {
|
ngOnChanges() {
|
||||||
if (this.availableAccessConditionOptions && this.availableAccessConditionGroups) {
|
if (this.availableAccessConditionOptions && this.availableAccessConditionGroups) {
|
||||||
// Retrieve file state
|
// Retrieve file state
|
||||||
@@ -79,11 +186,17 @@ export class UploadSectionFileComponent implements OnChanges, OnInit {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize instance variables
|
||||||
|
*/
|
||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
this.formId = this.formService.getUniqueId(this.fileId);
|
this.formId = this.formService.getUniqueId(this.fileId);
|
||||||
this.pathCombiner = new JsonPatchOperationPathCombiner('sections', this.sectionId, 'files', this.fileIndex);
|
this.pathCombiner = new JsonPatchOperationPathCombiner('sections', this.sectionId, 'files', this.fileIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delete bitstream from submission
|
||||||
|
*/
|
||||||
protected deleteFile() {
|
protected deleteFile() {
|
||||||
this.operationsBuilder.remove(this.pathCombiner.getPath());
|
this.operationsBuilder.remove(this.pathCombiner.getPath());
|
||||||
this.subscriptions.push(this.operationsService.jsonPatchByResourceID(
|
this.subscriptions.push(this.operationsService.jsonPatchByResourceID(
|
||||||
@@ -97,6 +210,9 @@ export class UploadSectionFileComponent implements OnChanges, OnInit {
|
|||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Show confirmation dialog for delete
|
||||||
|
*/
|
||||||
public confirmDelete(content) {
|
public confirmDelete(content) {
|
||||||
this.modalService.open(content).result.then(
|
this.modalService.open(content).result.then(
|
||||||
(result) => {
|
(result) => {
|
||||||
@@ -108,6 +224,9 @@ export class UploadSectionFileComponent implements OnChanges, OnInit {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Perform bitstream download
|
||||||
|
*/
|
||||||
public downloadBitstreamFile() {
|
public downloadBitstreamFile() {
|
||||||
this.halService.getEndpoint('bitstreams').pipe(
|
this.halService.getEndpoint('bitstreams').pipe(
|
||||||
first())
|
first())
|
||||||
@@ -117,9 +236,16 @@ export class UploadSectionFileComponent implements OnChanges, OnInit {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Save bitstream metadata
|
||||||
|
*
|
||||||
|
* @param event
|
||||||
|
* the click event emitted
|
||||||
|
*/
|
||||||
public saveBitstreamData(event) {
|
public saveBitstreamData(event) {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
|
|
||||||
|
// validate form
|
||||||
this.formService.validateAllFormFields(this.fileEditComp.formRef.formGroup);
|
this.formService.validateAllFormFields(this.fileEditComp.formRef.formGroup);
|
||||||
this.subscriptions.push(this.formService.isValid(this.formId).pipe(
|
this.subscriptions.push(this.formService.isValid(this.formId).pipe(
|
||||||
take(1),
|
take(1),
|
||||||
@@ -127,6 +253,7 @@ export class UploadSectionFileComponent implements OnChanges, OnInit {
|
|||||||
flatMap(() => this.formService.getFormData(this.formId)),
|
flatMap(() => this.formService.getFormData(this.formId)),
|
||||||
take(1),
|
take(1),
|
||||||
flatMap((formData: any) => {
|
flatMap((formData: any) => {
|
||||||
|
// collect bitstream metadata
|
||||||
Object.keys((formData.metadata))
|
Object.keys((formData.metadata))
|
||||||
.filter((key) => isNotEmpty(formData.metadata[key]))
|
.filter((key) => isNotEmpty(formData.metadata[key]))
|
||||||
.forEach((key) => {
|
.forEach((key) => {
|
||||||
@@ -174,6 +301,7 @@ export class UploadSectionFileComponent implements OnChanges, OnInit {
|
|||||||
this.operationsBuilder.add(this.pathCombiner.getPath('accessConditions'), accessConditionsToSave, true);
|
this.operationsBuilder.add(this.pathCombiner.getPath('accessConditions'), accessConditionsToSave, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// dispatch a PATCH request to save metadata
|
||||||
return this.operationsService.jsonPatchByResourceID(
|
return this.operationsService.jsonPatchByResourceID(
|
||||||
this.submissionService.getSubmissionObjectLinkName(),
|
this.submissionService.getSubmissionObjectLinkName(),
|
||||||
this.submissionId,
|
this.submissionId,
|
||||||
@@ -194,11 +322,20 @@ export class UploadSectionFileComponent implements OnChanges, OnInit {
|
|||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
private retrieveValueFromField(field) {
|
/**
|
||||||
|
* Retrieve field value
|
||||||
|
*
|
||||||
|
* @param field
|
||||||
|
* the specified field object
|
||||||
|
*/
|
||||||
|
private retrieveValueFromField(field: any) {
|
||||||
const temp = Array.isArray(field) ? field[0] : field;
|
const temp = Array.isArray(field) ? field[0] : field;
|
||||||
return (temp) ? temp.value : undefined;
|
return (temp) ? temp.value : undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Switch from edit form to metadata view
|
||||||
|
*/
|
||||||
public switchMode() {
|
public switchMode() {
|
||||||
this.readMode = !this.readMode;
|
this.readMode = !this.readMode;
|
||||||
this.cdr.detectChanges();
|
this.cdr.detectChanges();
|
||||||
|
@@ -5,17 +5,42 @@ import { isNotEmpty } from '../../../../../shared/empty.util';
|
|||||||
import { Metadata } from '../../../../../core/shared/metadata.utils';
|
import { Metadata } from '../../../../../core/shared/metadata.utils';
|
||||||
import { MetadataMap, MetadataValue } from '../../../../../core/shared/metadata.models';
|
import { MetadataMap, MetadataValue } from '../../../../../core/shared/metadata.models';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This component allow to show bitstream's metadata
|
||||||
|
*/
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'ds-submission-upload-section-file-view',
|
selector: 'ds-submission-upload-section-file-view',
|
||||||
templateUrl: './section-upload-file-view.component.html',
|
templateUrl: './section-upload-file-view.component.html',
|
||||||
})
|
})
|
||||||
export class UploadSectionFileViewComponent implements OnInit {
|
export class UploadSectionFileViewComponent implements OnInit {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The bitstream's metadata data
|
||||||
|
* @type {WorkspaceitemSectionUploadFileObject}
|
||||||
|
*/
|
||||||
@Input() fileData: WorkspaceitemSectionUploadFileObject;
|
@Input() fileData: WorkspaceitemSectionUploadFileObject;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The [[MetadataMap]] object
|
||||||
|
* @type {MetadataMap}
|
||||||
|
*/
|
||||||
public metadata: MetadataMap = Object.create({});
|
public metadata: MetadataMap = Object.create({});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The bitstream's title key
|
||||||
|
* @type {string}
|
||||||
|
*/
|
||||||
public fileTitleKey = 'Title';
|
public fileTitleKey = 'Title';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The bitstream's description key
|
||||||
|
* @type {string}
|
||||||
|
*/
|
||||||
public fileDescrKey = 'Description';
|
public fileDescrKey = 'Description';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize instance variables
|
||||||
|
*/
|
||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
if (isNotEmpty(this.fileData.metadata)) {
|
if (isNotEmpty(this.fileData.metadata)) {
|
||||||
this.metadata[this.fileTitleKey] = Metadata.all(this.fileData.metadata, 'dc.title');
|
this.metadata[this.fileTitleKey] = Metadata.all(this.fileData.metadata, 'dc.title');
|
||||||
@@ -23,7 +48,15 @@ export class UploadSectionFileViewComponent implements OnInit {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
getAllMetadataValue(metadataKey): MetadataValue[] {
|
/**
|
||||||
|
* Gets all matching metadata in the map(s)
|
||||||
|
*
|
||||||
|
* @param metadataKey
|
||||||
|
* The metadata key(s) in scope
|
||||||
|
* @returns {MetadataValue[]}
|
||||||
|
* The matching values
|
||||||
|
*/
|
||||||
|
getAllMetadataValue(metadataKey: string): MetadataValue[] {
|
||||||
return Metadata.all(this.metadata, metadataKey);
|
return Metadata.all(this.metadata, metadataKey);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -15,13 +15,10 @@
|
|||||||
<div *ngIf="collectionDefaultAccessConditions.length > 0" class="row">
|
<div *ngIf="collectionDefaultAccessConditions.length > 0" class="row">
|
||||||
<div class="col-sm-12" >
|
<div class="col-sm-12" >
|
||||||
<ds-alert [type]="AlertTypeEnum.Warning">
|
<ds-alert [type]="AlertTypeEnum.Warning">
|
||||||
<!-- no def , no banner -->
|
|
||||||
<ng-container *ngIf="collectionPolicyType === 1">
|
<ng-container *ngIf="collectionPolicyType === 1">
|
||||||
<!-- def e no scelta -->
|
|
||||||
{{ 'submission.sections.upload.header.policy.default.nolist' | translate:{ "collectionName": collectionName } }}
|
{{ 'submission.sections.upload.header.policy.default.nolist' | translate:{ "collectionName": collectionName } }}
|
||||||
</ng-container>
|
</ng-container>
|
||||||
<ng-container *ngIf="collectionPolicyType === 2">
|
<ng-container *ngIf="collectionPolicyType === 2">
|
||||||
<!-- def e scelta -->
|
|
||||||
{{ 'submission.sections.upload.header.policy.default.withlist' | translate:{ "collectionName": collectionName } }}
|
{{ 'submission.sections.upload.header.policy.default.withlist' | translate:{ "collectionName": collectionName } }}
|
||||||
</ng-container>
|
</ng-container>
|
||||||
<span class="clearfix"></span>
|
<span class="clearfix"></span>
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
import { ChangeDetectorRef, Component, Inject } from '@angular/core';
|
import { ChangeDetectorRef, Component, Inject } from '@angular/core';
|
||||||
|
|
||||||
import { combineLatest, Observable } from 'rxjs';
|
import { combineLatest, Observable, Subscription } from 'rxjs';
|
||||||
import { distinctUntilChanged, filter, find, flatMap, map, reduce, take, tap } from 'rxjs/operators';
|
import { distinctUntilChanged, filter, find, flatMap, map, reduce, take, tap } from 'rxjs/operators';
|
||||||
|
|
||||||
import { SectionModelComponent } from '../models/section.model';
|
import { SectionModelComponent } from '../models/section.model';
|
||||||
@@ -33,6 +33,9 @@ export interface AccessConditionGroupsMapEntry {
|
|||||||
groups: Group[]
|
groups: Group[]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This component represents a section that contains submission's bitstreams
|
||||||
|
*/
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'ds-submission-section-upload',
|
selector: 'ds-submission-section-upload',
|
||||||
styleUrls: ['./section-upload.component.scss'],
|
styleUrls: ['./section-upload.component.scss'],
|
||||||
@@ -41,37 +44,84 @@ export interface AccessConditionGroupsMapEntry {
|
|||||||
@renderSectionFor(SectionsType.Upload)
|
@renderSectionFor(SectionsType.Upload)
|
||||||
export class UploadSectionComponent extends SectionModelComponent {
|
export class UploadSectionComponent extends SectionModelComponent {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The AlertType enumeration
|
||||||
|
* @type {AlertType}
|
||||||
|
*/
|
||||||
public AlertTypeEnum = AlertType;
|
public AlertTypeEnum = AlertType;
|
||||||
public fileIndexes = [];
|
|
||||||
public fileList = [];
|
|
||||||
public fileNames = [];
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The array containing the keys of file list array
|
||||||
|
* @type {Array}
|
||||||
|
*/
|
||||||
|
public fileIndexes: string[] = [];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The file list
|
||||||
|
* @type {Array}
|
||||||
|
*/
|
||||||
|
public fileList: any[] = [];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The array containing the name of the files
|
||||||
|
* @type {Array}
|
||||||
|
*/
|
||||||
|
public fileNames: string[] = [];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The collection name this submission belonging to
|
||||||
|
* @type {string}
|
||||||
|
*/
|
||||||
public collectionName: string;
|
public collectionName: string;
|
||||||
|
|
||||||
/*
|
/**
|
||||||
* Default access conditions of this collection
|
* Default access conditions of this collection
|
||||||
|
* @type {Array}
|
||||||
*/
|
*/
|
||||||
public collectionDefaultAccessConditions: any[] = [];
|
public collectionDefaultAccessConditions: any[] = [];
|
||||||
|
|
||||||
/*
|
/**
|
||||||
* The collection access conditions policy
|
* Define if collection access conditions policy type :
|
||||||
|
* POLICY_DEFAULT_NO_LIST : is not possible to define additional access group/s for the single file
|
||||||
|
* POLICY_DEFAULT_WITH_LIST : is possible to define additional access group/s for the single file
|
||||||
|
* @type {number}
|
||||||
*/
|
*/
|
||||||
public collectionPolicyType;
|
public collectionPolicyType: number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The configuration for the bitstream's metadata form
|
||||||
|
*/
|
||||||
public configMetadataForm$: Observable<SubmissionFormsModel>;
|
public configMetadataForm$: Observable<SubmissionFormsModel>;
|
||||||
|
|
||||||
/*
|
/**
|
||||||
* List of available access conditions that could be setted to files
|
* List of available access conditions that could be setted to files
|
||||||
*/
|
*/
|
||||||
public availableAccessConditionOptions: AccessConditionOption[]; // List of accessConditions that an user can select
|
public availableAccessConditionOptions: AccessConditionOption[]; // List of accessConditions that an user can select
|
||||||
|
|
||||||
/*
|
/**
|
||||||
* List of Groups available for every access condition
|
* List of Groups available for every access condition
|
||||||
*/
|
*/
|
||||||
protected availableGroups: Map<string, Group[]>; // Groups for any policy
|
protected availableGroups: Map<string, Group[]>; // Groups for any policy
|
||||||
|
|
||||||
protected subs = [];
|
/**
|
||||||
|
* Array to track all subscriptions and unsubscribe them onDestroy
|
||||||
|
* @type {Array}
|
||||||
|
*/
|
||||||
|
protected subs: Subscription[] = [];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize instance variables
|
||||||
|
*
|
||||||
|
* @param {SectionUploadService} bitstreamService
|
||||||
|
* @param {ChangeDetectorRef} changeDetectorRef
|
||||||
|
* @param {CollectionDataService} collectionDataService
|
||||||
|
* @param {GroupEpersonService} groupService
|
||||||
|
* @param {SectionsService} sectionService
|
||||||
|
* @param {SubmissionService} submissionService
|
||||||
|
* @param {SubmissionUploadsConfigService} uploadsConfigService
|
||||||
|
* @param {SectionDataObject} injectedSectionData
|
||||||
|
* @param {string} injectedSubmissionId
|
||||||
|
*/
|
||||||
constructor(private bitstreamService: SectionUploadService,
|
constructor(private bitstreamService: SectionUploadService,
|
||||||
private changeDetectorRef: ChangeDetectorRef,
|
private changeDetectorRef: ChangeDetectorRef,
|
||||||
private collectionDataService: CollectionDataService,
|
private collectionDataService: CollectionDataService,
|
||||||
@@ -84,10 +134,14 @@ export class UploadSectionComponent extends SectionModelComponent {
|
|||||||
super(undefined, injectedSectionData, injectedSubmissionId);
|
super(undefined, injectedSectionData, injectedSubmissionId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize all instance variables and retrieve collection default access conditions
|
||||||
|
*/
|
||||||
onSectionInit() {
|
onSectionInit() {
|
||||||
const config$ = this.uploadsConfigService.getConfigByHref(this.sectionData.config).pipe(
|
const config$ = this.uploadsConfigService.getConfigByHref(this.sectionData.config).pipe(
|
||||||
map((config) => config.payload));
|
map((config) => config.payload));
|
||||||
|
|
||||||
|
// retrieve configuration for the bitstream's metadata form
|
||||||
this.configMetadataForm$ = config$.pipe(
|
this.configMetadataForm$ = config$.pipe(
|
||||||
take(1),
|
take(1),
|
||||||
map((config: SubmissionUploadsModel) => config.metadata));
|
map((config: SubmissionUploadsModel) => config.metadata));
|
||||||
@@ -124,7 +178,7 @@ export class UploadSectionComponent extends SectionModelComponent {
|
|||||||
|
|
||||||
this.availableGroups = new Map();
|
this.availableGroups = new Map();
|
||||||
const mapGroups$: Array<Observable<AccessConditionGroupsMapEntry>> = [];
|
const mapGroups$: Array<Observable<AccessConditionGroupsMapEntry>> = [];
|
||||||
// Retrieve Groups for accessConditionPolicies
|
// Retrieve Groups for accessCondition Policies
|
||||||
this.availableAccessConditionOptions.forEach((accessCondition: AccessConditionOption) => {
|
this.availableAccessConditionOptions.forEach((accessCondition: AccessConditionOption) => {
|
||||||
if (accessCondition.hasEndDate === true || accessCondition.hasStartDate === true) {
|
if (accessCondition.hasEndDate === true || accessCondition.hasStartDate === true) {
|
||||||
if (accessCondition.groupUUID) {
|
if (accessCondition.groupUUID) {
|
||||||
@@ -148,7 +202,7 @@ export class UploadSectionComponent extends SectionModelComponent {
|
|||||||
accessCondition: accessCondition.name,
|
accessCondition: accessCondition.name,
|
||||||
groups: rd.payload.page
|
groups: rd.payload.page
|
||||||
} as AccessConditionGroupsMapEntry))
|
} as AccessConditionGroupsMapEntry))
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -164,8 +218,9 @@ export class UploadSectionComponent extends SectionModelComponent {
|
|||||||
this.availableGroups.set(entry.accessCondition, entry.groups);
|
this.availableGroups.set(entry.accessCondition, entry.groups);
|
||||||
});
|
});
|
||||||
this.changeDetectorRef.detectChanges();
|
this.changeDetectorRef.detectChanges();
|
||||||
})
|
}),
|
||||||
,
|
|
||||||
|
// retrieve submission's bitstreams from state
|
||||||
combineLatest(this.configMetadataForm$,
|
combineLatest(this.configMetadataForm$,
|
||||||
this.bitstreamService.getUploadedFileList(this.submissionId, this.sectionData.id)).pipe(
|
this.bitstreamService.getUploadedFileList(this.submissionId, this.sectionData.id)).pipe(
|
||||||
filter(([configMetadataForm, fileList]: [SubmissionFormsModel, any[]]) => {
|
filter(([configMetadataForm, fileList]: [SubmissionFormsModel, any[]]) => {
|
||||||
@@ -173,24 +228,32 @@ export class UploadSectionComponent extends SectionModelComponent {
|
|||||||
}),
|
}),
|
||||||
distinctUntilChanged())
|
distinctUntilChanged())
|
||||||
.subscribe(([configMetadataForm, fileList]: [SubmissionFormsModel, any[]]) => {
|
.subscribe(([configMetadataForm, fileList]: [SubmissionFormsModel, any[]]) => {
|
||||||
this.fileList = [];
|
this.fileList = [];
|
||||||
this.fileIndexes = [];
|
this.fileIndexes = [];
|
||||||
this.fileNames = [];
|
this.fileNames = [];
|
||||||
this.changeDetectorRef.detectChanges();
|
this.changeDetectorRef.detectChanges();
|
||||||
if (isNotUndefined(fileList) && fileList.length > 0) {
|
if (isNotUndefined(fileList) && fileList.length > 0) {
|
||||||
fileList.forEach((file) => {
|
fileList.forEach((file) => {
|
||||||
this.fileList.push(file);
|
this.fileList.push(file);
|
||||||
this.fileIndexes.push(file.uuid);
|
this.fileIndexes.push(file.uuid);
|
||||||
this.fileNames.push(this.getFileName(configMetadataForm, file));
|
this.fileNames.push(this.getFileName(configMetadataForm, file));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
this.changeDetectorRef.detectChanges();
|
this.changeDetectorRef.detectChanges();
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return file name from metadata
|
||||||
|
*
|
||||||
|
* @param configMetadataForm
|
||||||
|
* the bitstream's form configuration
|
||||||
|
* @param fileData
|
||||||
|
* the file metadata
|
||||||
|
*/
|
||||||
private getFileName(configMetadataForm: SubmissionFormsModel, fileData: any): string {
|
private getFileName(configMetadataForm: SubmissionFormsModel, fileData: any): string {
|
||||||
const metadataName: string = configMetadataForm.rows[0].fields[0].selectableMetadata[0].metadata;
|
const metadataName: string = configMetadataForm.rows[0].fields[0].selectableMetadata[0].metadata;
|
||||||
let title: string;
|
let title: string;
|
||||||
@@ -203,6 +266,12 @@ export class UploadSectionComponent extends SectionModelComponent {
|
|||||||
return title;
|
return title;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get section status
|
||||||
|
*
|
||||||
|
* @return Observable<boolean>
|
||||||
|
* the section status
|
||||||
|
*/
|
||||||
protected getSectionStatus(): Observable<boolean> {
|
protected getSectionStatus(): Observable<boolean> {
|
||||||
return this.bitstreamService.getUploadedFileList(this.submissionId, this.sectionData.id).pipe(
|
return this.bitstreamService.getUploadedFileList(this.submissionId, this.sectionData.id).pipe(
|
||||||
map((fileList: any[]) => (isNotUndefined(fileList) && fileList.length > 0)));
|
map((fileList: any[]) => (isNotUndefined(fileList) && fileList.length > 0)));
|
||||||
|
@@ -14,51 +14,127 @@ import { submissionUploadedFileFromUuidSelector, submissionUploadedFilesFromIdSe
|
|||||||
import { isUndefined } from '../../../shared/empty.util';
|
import { isUndefined } from '../../../shared/empty.util';
|
||||||
import { WorkspaceitemSectionUploadFileObject } from '../../../core/submission/models/workspaceitem-section-upload-file.model';
|
import { WorkspaceitemSectionUploadFileObject } from '../../../core/submission/models/workspaceitem-section-upload-file.model';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A service that provides methods to handle submission's bitstream state.
|
||||||
|
*/
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class SectionUploadService {
|
export class SectionUploadService {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize service variables
|
||||||
|
*
|
||||||
|
* @param {Store<SubmissionState>} store
|
||||||
|
*/
|
||||||
constructor(private store: Store<SubmissionState>) {}
|
constructor(private store: Store<SubmissionState>) {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return submission's bitstream list from state
|
||||||
|
*
|
||||||
|
* @param submissionId
|
||||||
|
* The submission id
|
||||||
|
* @param sectionId
|
||||||
|
* The section id
|
||||||
|
* @returns {Array}
|
||||||
|
* Returns submission's bitstream list
|
||||||
|
*/
|
||||||
public getUploadedFileList(submissionId: string, sectionId: string): Observable<any> {
|
public getUploadedFileList(submissionId: string, sectionId: string): Observable<any> {
|
||||||
return this.store.select(submissionUploadedFilesFromIdSelector(submissionId, sectionId)).pipe(
|
return this.store.select(submissionUploadedFilesFromIdSelector(submissionId, sectionId)).pipe(
|
||||||
map((state) => state),
|
map((state) => state),
|
||||||
distinctUntilChanged());
|
distinctUntilChanged());
|
||||||
}
|
}
|
||||||
|
|
||||||
public getFileData(submissionId: string, sectionId: string, fileUuid: string): Observable<any> {
|
/**
|
||||||
|
* Return bitstream's metadata
|
||||||
|
*
|
||||||
|
* @param submissionId
|
||||||
|
* The submission id
|
||||||
|
* @param sectionId
|
||||||
|
* The section id
|
||||||
|
* @param fileUUID
|
||||||
|
* The bitstream UUID
|
||||||
|
* @returns {Observable}
|
||||||
|
* Emits bitstream's metadata
|
||||||
|
*/
|
||||||
|
public getFileData(submissionId: string, sectionId: string, fileUUID: string): Observable<any> {
|
||||||
return this.store.select(submissionUploadedFilesFromIdSelector(submissionId, sectionId)).pipe(
|
return this.store.select(submissionUploadedFilesFromIdSelector(submissionId, sectionId)).pipe(
|
||||||
filter((state) => !isUndefined(state)),
|
filter((state) => !isUndefined(state)),
|
||||||
map((state) => {
|
map((state) => {
|
||||||
let fileState;
|
let fileState;
|
||||||
Object.keys(state)
|
Object.keys(state)
|
||||||
.filter((key) => state[key].uuid === fileUuid)
|
.filter((key) => state[key].uuid === fileUUID)
|
||||||
.forEach((key) => fileState = state[key]);
|
.forEach((key) => fileState = state[key]);
|
||||||
return fileState;
|
return fileState;
|
||||||
}),
|
}),
|
||||||
distinctUntilChanged());
|
distinctUntilChanged());
|
||||||
}
|
}
|
||||||
|
|
||||||
public getDefaultPolicies(submissionId: string, sectionId: string, fileId: string): Observable<any> {
|
/**
|
||||||
return this.store.select(submissionUploadedFileFromUuidSelector(submissionId, sectionId, fileId)).pipe(
|
* Return bitstream's default policies
|
||||||
|
*
|
||||||
|
* @param submissionId
|
||||||
|
* The submission id
|
||||||
|
* @param sectionId
|
||||||
|
* The section id
|
||||||
|
* @param fileUUID
|
||||||
|
* The bitstream UUID
|
||||||
|
* @returns {Observable}
|
||||||
|
* Emits bitstream's default policies
|
||||||
|
*/
|
||||||
|
public getDefaultPolicies(submissionId: string, sectionId: string, fileUUID: string): Observable<any> {
|
||||||
|
return this.store.select(submissionUploadedFileFromUuidSelector(submissionId, sectionId, fileUUID)).pipe(
|
||||||
map((state) => state),
|
map((state) => state),
|
||||||
distinctUntilChanged());
|
distinctUntilChanged());
|
||||||
}
|
}
|
||||||
|
|
||||||
public addUploadedFile(submissionId: string, sectionId: string, fileId: string, data: WorkspaceitemSectionUploadFileObject) {
|
/**
|
||||||
|
* Add a new bitstream to the state
|
||||||
|
*
|
||||||
|
* @param submissionId
|
||||||
|
* The submission id
|
||||||
|
* @param sectionId
|
||||||
|
* The section id
|
||||||
|
* @param fileUUID
|
||||||
|
* The bitstream UUID
|
||||||
|
* @param data
|
||||||
|
* The [[WorkspaceitemSectionUploadFileObject]] object
|
||||||
|
*/
|
||||||
|
public addUploadedFile(submissionId: string, sectionId: string, fileUUID: string, data: WorkspaceitemSectionUploadFileObject) {
|
||||||
this.store.dispatch(
|
this.store.dispatch(
|
||||||
new NewUploadedFileAction(submissionId, sectionId, fileId, data)
|
new NewUploadedFileAction(submissionId, sectionId, fileUUID, data)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public updateFileData(submissionId: string, sectionId: string, fileId: string, data: WorkspaceitemSectionUploadFileObject) {
|
/**
|
||||||
|
* Update bitstream metadata into the state
|
||||||
|
*
|
||||||
|
* @param submissionId
|
||||||
|
* The submission id
|
||||||
|
* @param sectionId
|
||||||
|
* The section id
|
||||||
|
* @param fileUUID
|
||||||
|
* The bitstream UUID
|
||||||
|
* @param data
|
||||||
|
* The [[WorkspaceitemSectionUploadFileObject]] object
|
||||||
|
*/
|
||||||
|
public updateFileData(submissionId: string, sectionId: string, fileUUID: string, data: WorkspaceitemSectionUploadFileObject) {
|
||||||
this.store.dispatch(
|
this.store.dispatch(
|
||||||
new EditFileDataAction(submissionId, sectionId, fileId, data)
|
new EditFileDataAction(submissionId, sectionId, fileUUID, data)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public removeUploadedFile(submissionId: string, sectionId: string, fileId: string) {
|
/**
|
||||||
|
* Remove bitstream from the state
|
||||||
|
*
|
||||||
|
* @param submissionId
|
||||||
|
* The submission id
|
||||||
|
* @param sectionId
|
||||||
|
* The section id
|
||||||
|
* @param fileUUID
|
||||||
|
* The bitstream UUID
|
||||||
|
*/
|
||||||
|
public removeUploadedFile(submissionId: string, sectionId: string, fileUUID: string) {
|
||||||
this.store.dispatch(
|
this.store.dispatch(
|
||||||
new DeleteUploadedFileAction(submissionId, sectionId, fileId)
|
new DeleteUploadedFileAction(submissionId, sectionId, fileUUID)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -6,21 +6,45 @@ import { SubmissionService } from './submission.service';
|
|||||||
import { SubmissionObject } from '../core/submission/models/submission-object.model';
|
import { SubmissionObject } from '../core/submission/models/submission-object.model';
|
||||||
import { RemoteData } from '../core/data/remote-data';
|
import { RemoteData } from '../core/data/remote-data';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Instance of SubmissionService used on SSR.
|
||||||
|
*/
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class ServerSubmissionService extends SubmissionService {
|
export class ServerSubmissionService extends SubmissionService {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Override createSubmission parent method to return an empty observable
|
||||||
|
*
|
||||||
|
* @return Observable<SubmissionObject>
|
||||||
|
* observable of SubmissionObject
|
||||||
|
*/
|
||||||
createSubmission(): Observable<SubmissionObject> {
|
createSubmission(): Observable<SubmissionObject> {
|
||||||
return observableOf(null);
|
return observableOf(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Override retrieveSubmission parent method to return an empty observable
|
||||||
|
*
|
||||||
|
* @return Observable<SubmissionObject>
|
||||||
|
* observable of SubmissionObject
|
||||||
|
*/
|
||||||
retrieveSubmission(submissionId): Observable<RemoteData<SubmissionObject>> {
|
retrieveSubmission(submissionId): Observable<RemoteData<SubmissionObject>> {
|
||||||
return observableOf(null);
|
return observableOf(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Override startAutoSave parent method and return without doing anything
|
||||||
|
*
|
||||||
|
* @param submissionId
|
||||||
|
* The submission id
|
||||||
|
*/
|
||||||
startAutoSave(submissionId) {
|
startAutoSave(submissionId) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Override startAutoSave parent method and return without doing anything
|
||||||
|
*/
|
||||||
stopAutoSave() {
|
stopAutoSave() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@@ -11,6 +11,9 @@ import { SubmissionService } from '../submission.service';
|
|||||||
import { SubmissionObject } from '../../core/submission/models/submission-object.model';
|
import { SubmissionObject } from '../../core/submission/models/submission-object.model';
|
||||||
import { Collection } from '../../core/shared/collection.model';
|
import { Collection } from '../../core/shared/collection.model';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This component allows to submit a new workspaceitem.
|
||||||
|
*/
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'ds-submit-page',
|
selector: 'ds-submit-page',
|
||||||
styleUrls: ['./submission-submit.component.scss'],
|
styleUrls: ['./submission-submit.component.scss'],
|
||||||
@@ -18,14 +21,46 @@ import { Collection } from '../../core/shared/collection.model';
|
|||||||
})
|
})
|
||||||
export class SubmissionSubmitComponent implements OnDestroy, OnInit {
|
export class SubmissionSubmitComponent implements OnDestroy, OnInit {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The collection id this submission belonging to
|
||||||
|
* @type {string}
|
||||||
|
*/
|
||||||
public collectionId: string;
|
public collectionId: string;
|
||||||
public model: any;
|
|
||||||
|
/**
|
||||||
|
* The submission self url
|
||||||
|
* @type {string}
|
||||||
|
*/
|
||||||
public selfUrl: string;
|
public selfUrl: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The configuration object that define this submission
|
||||||
|
* @type {SubmissionDefinitionsModel}
|
||||||
|
*/
|
||||||
public submissionDefinition: SubmissionDefinitionsModel;
|
public submissionDefinition: SubmissionDefinitionsModel;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The submission id
|
||||||
|
* @type {string}
|
||||||
|
*/
|
||||||
public submissionId: string;
|
public submissionId: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Array to track all subscriptions and unsubscribe them onDestroy
|
||||||
|
* @type {Array}
|
||||||
|
*/
|
||||||
protected subs: Subscription[] = [];
|
protected subs: Subscription[] = [];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize instance variables
|
||||||
|
*
|
||||||
|
* @param {ChangeDetectorRef} changeDetectorRef
|
||||||
|
* @param {NotificationsService} notificationsService
|
||||||
|
* @param {SubmissionService} submissioService
|
||||||
|
* @param {Router} router
|
||||||
|
* @param {TranslateService} translate
|
||||||
|
* @param {ViewContainerRef} viewContainerRef
|
||||||
|
*/
|
||||||
constructor(private changeDetectorRef: ChangeDetectorRef,
|
constructor(private changeDetectorRef: ChangeDetectorRef,
|
||||||
private notificationsService: NotificationsService,
|
private notificationsService: NotificationsService,
|
||||||
private router: Router,
|
private router: Router,
|
||||||
@@ -34,6 +69,9 @@ export class SubmissionSubmitComponent implements OnDestroy, OnInit {
|
|||||||
private viewContainerRef: ViewContainerRef) {
|
private viewContainerRef: ViewContainerRef) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create workspaceitem on the server and initialize all instance variables
|
||||||
|
*/
|
||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
// NOTE execute the code on the browser side only, otherwise it is executed twice
|
// NOTE execute the code on the browser side only, otherwise it is executed twice
|
||||||
this.subs.push(
|
this.subs.push(
|
||||||
@@ -56,6 +94,9 @@ export class SubmissionSubmitComponent implements OnDestroy, OnInit {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unsubscribe from all subscriptions
|
||||||
|
*/
|
||||||
ngOnDestroy() {
|
ngOnDestroy() {
|
||||||
this.subs
|
this.subs
|
||||||
.filter((subscription) => hasValue(subscription))
|
.filter((subscription) => hasValue(subscription))
|
||||||
|
Reference in New Issue
Block a user