mirror of
https://github.com/DSpace/dspace-angular.git
synced 2025-10-08 10:34:15 +00:00
Added more comments
This commit is contained in:
@@ -743,7 +743,7 @@
|
||||
"upload-successful": "Upload successful",
|
||||
"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.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": {
|
||||
"access-condition-label": "Access condition type",
|
||||
"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 { RemoteData } from '../../core/data/remote-data';
|
||||
|
||||
/**
|
||||
* This component allows to edit an existing workspaceitem/workflowitem.
|
||||
*/
|
||||
@Component({
|
||||
selector: 'ds-submission-edit',
|
||||
styleUrls: ['./submission-edit.component.scss'],
|
||||
templateUrl: './submission-edit.component.html'
|
||||
})
|
||||
|
||||
export class SubmissionEditComponent implements OnDestroy, OnInit {
|
||||
|
||||
/**
|
||||
* The collection id this submission belonging to
|
||||
* @type {string}
|
||||
*/
|
||||
public collectionId: string;
|
||||
|
||||
/**
|
||||
* The list of submission's sections
|
||||
* @type {WorkspaceitemSectionsObject}
|
||||
*/
|
||||
public sections: WorkspaceitemSectionsObject;
|
||||
|
||||
/**
|
||||
* The submission self url
|
||||
* @type {string}
|
||||
*/
|
||||
public selfUrl: string;
|
||||
|
||||
/**
|
||||
* The configuration object that define this submission
|
||||
* @type {SubmissionDefinitionsModel}
|
||||
*/
|
||||
public submissionDefinition: SubmissionDefinitionsModel;
|
||||
|
||||
/**
|
||||
* The submission id
|
||||
* @type {string}
|
||||
*/
|
||||
public submissionId: string;
|
||||
|
||||
/**
|
||||
@@ -33,6 +60,16 @@ export class SubmissionEditComponent implements OnDestroy, OnInit {
|
||||
*/
|
||||
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,
|
||||
private notificationsService: NotificationsService,
|
||||
private route: ActivatedRoute,
|
||||
@@ -41,6 +78,9 @@ export class SubmissionEditComponent implements OnDestroy, OnInit {
|
||||
private translate: TranslateService) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve workspaceitem/workflowitem from server and initialize all instance variables
|
||||
*/
|
||||
ngOnInit() {
|
||||
this.subs.push(this.route.paramMap.pipe(
|
||||
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() {
|
||||
this.subs
|
||||
|
@@ -36,24 +36,48 @@ import { SubmissionService } from '../../submission.service';
|
||||
import { SubmissionObject } from '../../../core/submission/models/submission-object.model';
|
||||
import { SubmissionJsonPatchOperationsService } from '../../../core/submission/submission-json-patch-operations.service';
|
||||
|
||||
/**
|
||||
* An interface to represent a collection entry
|
||||
*/
|
||||
interface CollectionListEntryItem {
|
||||
id: string;
|
||||
name: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* An interface to represent an entry in the collection list
|
||||
*/
|
||||
interface CollectionListEntry {
|
||||
communities: CollectionListEntryItem[],
|
||||
collection: CollectionListEntryItem
|
||||
}
|
||||
|
||||
/**
|
||||
* This component allows to show the current collection the submission belonging to and to change it.
|
||||
*/
|
||||
@Component({
|
||||
selector: 'ds-submission-form-collection',
|
||||
styleUrls: ['./submission-form-collection.component.scss'],
|
||||
templateUrl: './submission-form-collection.component.html'
|
||||
})
|
||||
export class SubmissionFormCollectionComponent implements OnChanges, OnInit {
|
||||
|
||||
/**
|
||||
* The current collection id this submission belonging to
|
||||
* @type {string}
|
||||
*/
|
||||
@Input() currentCollectionId: string;
|
||||
|
||||
/**
|
||||
* The current configuration object that define this submission
|
||||
* @type {SubmissionDefinitionsModel}
|
||||
*/
|
||||
@Input() currentDefinition: string;
|
||||
|
||||
/**
|
||||
* The submission id
|
||||
* @type {string}
|
||||
*/
|
||||
@Input() submissionId;
|
||||
|
||||
/**
|
||||
@@ -62,18 +86,69 @@ export class SubmissionFormCollectionComponent implements OnChanges, OnInit {
|
||||
*/
|
||||
@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 model: any;
|
||||
|
||||
/**
|
||||
* The search form control
|
||||
* @type {FormControl}
|
||||
*/
|
||||
public searchField: FormControl = new FormControl();
|
||||
|
||||
/**
|
||||
* The collection list obtained from a search
|
||||
* @type {Observable<CollectionListEntry[]>}
|
||||
*/
|
||||
public searchListCollection$: Observable<CollectionListEntry[]>;
|
||||
|
||||
/**
|
||||
* The selected collection id
|
||||
* @type {string}
|
||||
*/
|
||||
public selectedCollectionId: string;
|
||||
|
||||
/**
|
||||
* The selected collection name
|
||||
* @type {Observable<string>}
|
||||
*/
|
||||
public selectedCollectionName$: Observable<string>;
|
||||
|
||||
/**
|
||||
* The JsonPatchOperationPathCombiner object
|
||||
* @type {JsonPatchOperationPathCombiner}
|
||||
*/
|
||||
protected pathCombiner: JsonPatchOperationPathCombiner;
|
||||
|
||||
/**
|
||||
* A boolean representing if dropdown list is scrollable to the bottom
|
||||
* @type {boolean}
|
||||
*/
|
||||
private scrollableBottom = false;
|
||||
|
||||
/**
|
||||
* A boolean representing if dropdown list is scrollable to the top
|
||||
* @type {boolean}
|
||||
*/
|
||||
private scrollableTop = false;
|
||||
|
||||
/**
|
||||
* Array to track all subscriptions and unsubscribe them onDestroy
|
||||
* @type {Array}
|
||||
*/
|
||||
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,
|
||||
private communityDataService: CommunityDataService,
|
||||
private operationsBuilder: JsonPatchOperationsBuilder,
|
||||
@@ -81,6 +156,13 @@ export class SubmissionFormCollectionComponent implements OnChanges, OnInit {
|
||||
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) {
|
||||
if (event.wheelDelta > 0 && this.scrollableTop) {
|
||||
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) {
|
||||
this.scrollableBottom = (event.target.scrollTop + event.target.clientHeight === event.target.scrollHeight);
|
||||
this.scrollableTop = (event.target.scrollTop === 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize collection list
|
||||
*/
|
||||
ngOnChanges(changes: SimpleChanges) {
|
||||
if (hasValue(changes.currentCollectionId)
|
||||
&& hasValue(changes.currentCollectionId.currentValue)) {
|
||||
@@ -153,14 +243,26 @@ export class SubmissionFormCollectionComponent implements OnChanges, OnInit {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize all instance variables
|
||||
*/
|
||||
ngOnInit() {
|
||||
this.pathCombiner = new JsonPatchOperationPathCombiner('sections', 'collection');
|
||||
}
|
||||
|
||||
/**
|
||||
* Unsubscribe from all subscriptions
|
||||
*/
|
||||
ngOnDestroy(): void {
|
||||
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) {
|
||||
this.searchField.reset();
|
||||
this.disabled$.next(true);
|
||||
@@ -181,10 +283,19 @@ export class SubmissionFormCollectionComponent implements OnChanges, OnInit {
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset search form control on dropdown menu close
|
||||
*/
|
||||
onClose() {
|
||||
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) {
|
||||
if (!isOpen) {
|
||||
this.searchField.reset();
|
||||
|
@@ -9,6 +9,9 @@ import { SubmissionService } from '../../submission.service';
|
||||
import { SubmissionScopeType } from '../../../core/submission/submission-scope-type';
|
||||
import { isNotEmpty } from '../../../shared/empty.util';
|
||||
|
||||
/**
|
||||
* This component represents submission form footer bar.
|
||||
*/
|
||||
@Component({
|
||||
selector: 'ds-submission-form-footer',
|
||||
styleUrls: ['./submission-form-footer.component.scss'],
|
||||
@@ -16,18 +19,51 @@ import { isNotEmpty } from '../../../shared/empty.util';
|
||||
})
|
||||
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>;
|
||||
|
||||
/**
|
||||
* A boolean representing if a submission save operation is pending
|
||||
* @type {Observable<boolean>}
|
||||
*/
|
||||
public processingSaveStatus: Observable<boolean>;
|
||||
|
||||
/**
|
||||
* A boolean representing if showing deposit and discard buttons
|
||||
* @type {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);
|
||||
|
||||
/**
|
||||
* Initialize instance variables
|
||||
*
|
||||
* @param {NgbModal} modalService
|
||||
* @param {SubmissionRestService} restService
|
||||
* @param {SubmissionService} submissionService
|
||||
*/
|
||||
constructor(private modalService: NgbModal,
|
||||
private restService: SubmissionRestService,
|
||||
private submissionService: SubmissionService) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize all instance variables
|
||||
*/
|
||||
ngOnChanges(changes: SimpleChanges) {
|
||||
if (isNotEmpty(this.submissionId)) {
|
||||
this.submissionIsInvalid = this.submissionService.getSubmissionStatus(this.submissionId).pipe(
|
||||
@@ -40,18 +76,30 @@ export class SubmissionFormFooterComponent implements OnChanges {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Dispatch a submission save action
|
||||
*/
|
||||
save(event) {
|
||||
this.submissionService.dispatchSave(this.submissionId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Dispatch a submission save for later action
|
||||
*/
|
||||
saveLater(event) {
|
||||
this.submissionService.dispatchSaveForLater(this.submissionId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Dispatch a submission deposit action
|
||||
*/
|
||||
public deposit(event) {
|
||||
this.submissionService.dispatchDeposit(this.submissionId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Dispatch a submission discard action
|
||||
*/
|
||||
public confirmDiscard(content) {
|
||||
this.modalService.open(content).result.then(
|
||||
(result) => {
|
||||
|
@@ -1,30 +1,62 @@
|
||||
import { Component, Input, OnInit, } from '@angular/core';
|
||||
|
||||
import { Observable } from 'rxjs';
|
||||
import { map } from 'rxjs/operators';
|
||||
|
||||
import { SectionsService } from '../../sections/sections.service';
|
||||
import { HostWindowService } from '../../../shared/host-window.service';
|
||||
import { SubmissionService } from '../../submission.service';
|
||||
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({
|
||||
selector: 'ds-submission-form-section-add',
|
||||
styleUrls: [ './submission-form-section-add.component.scss' ],
|
||||
templateUrl: './submission-form-section-add.component.html'
|
||||
})
|
||||
export class SubmissionFormSectionAddComponent implements OnInit {
|
||||
|
||||
/**
|
||||
* The collection id this submission belonging to
|
||||
* @type {string}
|
||||
*/
|
||||
@Input() collectionId: string;
|
||||
|
||||
/**
|
||||
* The submission id
|
||||
* @type {string}
|
||||
*/
|
||||
@Input() submissionId: string;
|
||||
|
||||
/**
|
||||
* The possible section list to add
|
||||
* @type {Observable<SectionDataObject[]>}
|
||||
*/
|
||||
public sectionList$: Observable<SectionDataObject[]>;
|
||||
|
||||
/**
|
||||
* A boolean representing if there are available sections to add
|
||||
* @type {Observable<boolean>}
|
||||
*/
|
||||
public hasSections$: Observable<boolean>;
|
||||
|
||||
/**
|
||||
* Initialize instance variables
|
||||
*
|
||||
* @param {SectionsService} sectionService
|
||||
* @param {SubmissionService} submissionService
|
||||
* @param {HostWindowService} windowService
|
||||
*/
|
||||
constructor(private sectionService: SectionsService,
|
||||
private submissionService: SubmissionService,
|
||||
public windowService: HostWindowService) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize all instance variables
|
||||
*/
|
||||
ngOnInit() {
|
||||
this.sectionList$ = this.submissionService.getDisabledSectionsList(this.submissionId);
|
||||
this.hasSections$ = this.sectionList$.pipe(
|
||||
@@ -32,6 +64,9 @@ export class SubmissionFormSectionAddComponent implements OnInit {
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Dispatch an action to add a new section
|
||||
*/
|
||||
addSection(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 { SubmissionObject } from '../../core/submission/models/submission-object.model';
|
||||
|
||||
/**
|
||||
* This component represents the submission form.
|
||||
*/
|
||||
@Component({
|
||||
selector: 'ds-submission-submit-form',
|
||||
styleUrls: ['./submission-form.component.scss'],
|
||||
templateUrl: './submission-form.component.html',
|
||||
})
|
||||
export class SubmissionFormComponent implements OnChanges, OnDestroy {
|
||||
|
||||
/**
|
||||
* The collection id this submission belonging to
|
||||
* @type {string}
|
||||
*/
|
||||
@Input() collectionId: string;
|
||||
|
||||
/**
|
||||
* The list of submission's sections
|
||||
* @type {WorkspaceitemSectionsObject}
|
||||
*/
|
||||
@Input() sections: WorkspaceitemSectionsObject;
|
||||
|
||||
/**
|
||||
* The submission self url
|
||||
* @type {string}
|
||||
*/
|
||||
@Input() selfUrl: string;
|
||||
|
||||
/**
|
||||
* The configuration object that define this submission
|
||||
* @type {SubmissionDefinitionsModel}
|
||||
*/
|
||||
@Input() submissionDefinition: SubmissionDefinitionsModel;
|
||||
|
||||
/**
|
||||
* The submission id
|
||||
* @type {string}
|
||||
*/
|
||||
@Input() submissionId: string;
|
||||
|
||||
/**
|
||||
* The configuration id that define this submission
|
||||
* @type {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 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 = {
|
||||
url: '',
|
||||
authToken: null,
|
||||
@@ -38,9 +84,26 @@ export class SubmissionFormComponent implements OnChanges, OnDestroy {
|
||||
itemAlias: null
|
||||
};
|
||||
|
||||
/**
|
||||
* A boolean representing if component is active
|
||||
* @type {boolean}
|
||||
*/
|
||||
protected isActive: boolean;
|
||||
|
||||
/**
|
||||
* Array to track all subscriptions and unsubscribe them onDestroy
|
||||
* @type {Array}
|
||||
*/
|
||||
protected subs: Subscription[] = [];
|
||||
|
||||
/**
|
||||
* Initialize instance variables
|
||||
*
|
||||
* @param {AuthService} authService
|
||||
* @param {ChangeDetectorRef} changeDetectorRef
|
||||
* @param {HALEndpointService} halService
|
||||
* @param {SubmissionService} submissionService
|
||||
*/
|
||||
constructor(
|
||||
private authService: AuthService,
|
||||
private changeDetectorRef: ChangeDetectorRef,
|
||||
@@ -49,9 +112,14 @@ export class SubmissionFormComponent implements OnChanges, OnDestroy {
|
||||
this.isActive = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize all instance variables and retrieve form configuration
|
||||
*/
|
||||
ngOnChanges(changes: SimpleChanges) {
|
||||
if (this.collectionId && this.submissionId) {
|
||||
this.isActive = true;
|
||||
|
||||
// retrieve submission's section list
|
||||
this.submissionSections = this.submissionService.getSubmissionObject(this.submissionId).pipe(
|
||||
filter(() => this.isActive),
|
||||
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(
|
||||
filter(() => this.isActive),
|
||||
map((submission: SubmissionObjectEntry) => submission.isLoading),
|
||||
map((isLoading: boolean) => isLoading),
|
||||
distinctUntilChanged());
|
||||
|
||||
// init submission state
|
||||
this.subs.push(
|
||||
this.halService.getEndpoint('workspaceitems').pipe(
|
||||
filter((href: string) => isNotEmpty(href)),
|
||||
@@ -89,10 +159,16 @@ export class SubmissionFormComponent implements OnChanges, OnDestroy {
|
||||
this.changeDetectorRef.detectChanges();
|
||||
})
|
||||
);
|
||||
|
||||
// start auto save
|
||||
this.submissionService.startAutoSave(this.submissionId);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Unsubscribe from all subscriptions, destroy instance variables
|
||||
* and reset submission state
|
||||
*/
|
||||
ngOnDestroy() {
|
||||
this.isActive = false;
|
||||
this.submissionService.stopAutoSave();
|
||||
@@ -102,6 +178,13 @@ export class SubmissionFormComponent implements OnChanges, OnDestroy {
|
||||
.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) {
|
||||
this.collectionId = (submissionObject.collection as Collection).id;
|
||||
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> {
|
||||
return this.loading;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if submission form is loading
|
||||
*/
|
||||
protected getSectionsList(): Observable<any> {
|
||||
return this.submissionService.getSubmissionSections(this.submissionId).pipe(
|
||||
filter((sections: SectionDataObject[]) => isNotEmpty(sections)),
|
||||
|
@@ -14,24 +14,72 @@ import { UploaderOptions } from '../../../shared/uploader/uploader-options.model
|
||||
import parseSectionErrors from '../../utils/parseSectionErrors';
|
||||
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({
|
||||
selector: 'ds-submission-upload-files',
|
||||
templateUrl: './submission-upload-files.component.html',
|
||||
})
|
||||
export class SubmissionUploadFilesComponent implements OnChanges {
|
||||
|
||||
@Input() collectionId;
|
||||
@Input() submissionId;
|
||||
@Input() sectionId;
|
||||
/**
|
||||
* The collection id this submission belonging to
|
||||
* @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;
|
||||
|
||||
/**
|
||||
* A boolean representing if is possible to active drop zone over the document page
|
||||
* @type {boolean}
|
||||
*/
|
||||
public enableDragOverDocument = true;
|
||||
|
||||
/**
|
||||
* i18n message label
|
||||
* @type {string}
|
||||
*/
|
||||
public dropOverDocumentMsg = 'submission.sections.upload.drop-message';
|
||||
|
||||
/**
|
||||
* i18n message label
|
||||
* @type {string}
|
||||
*/
|
||||
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);
|
||||
|
||||
/**
|
||||
* Save submission before to upload a file
|
||||
*/
|
||||
public onBeforeUpload = () => {
|
||||
const sub: Subscription = this.operationsService.jsonPatchByResourceType(
|
||||
this.submissionService.getSubmissionObjectLinkName(),
|
||||
@@ -42,6 +90,15 @@ export class SubmissionUploadFilesComponent implements OnChanges {
|
||||
return sub;
|
||||
};
|
||||
|
||||
/**
|
||||
* Initialize instance variables
|
||||
*
|
||||
* @param {NotificationsService} notificationsService
|
||||
* @param {SubmissionJsonPatchOperationsService} operationsService
|
||||
* @param {SectionsService} sectionService
|
||||
* @param {SubmissionService} submissionService
|
||||
* @param {TranslateService} translate
|
||||
*/
|
||||
constructor(private notificationsService: NotificationsService,
|
||||
private operationsService: SubmissionJsonPatchOperationsService,
|
||||
private sectionService: SectionsService,
|
||||
@@ -49,10 +106,19 @@ export class SubmissionUploadFilesComponent implements OnChanges {
|
||||
private translate: TranslateService) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if upload functionality is enabled
|
||||
*/
|
||||
ngOnChanges() {
|
||||
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) {
|
||||
// Checks if upload section is enabled so do upload
|
||||
this.subs.push(
|
||||
@@ -87,12 +153,15 @@ export class SubmissionUploadFilesComponent implements OnChanges {
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Show error notification on upload fails
|
||||
*/
|
||||
public onUploadError() {
|
||||
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() {
|
||||
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
|
||||
* The current SubmissionObjectEntry
|
||||
|
@@ -138,7 +138,7 @@ export interface SubmissionObjectEntry {
|
||||
collection?: string,
|
||||
|
||||
/**
|
||||
* The configuration name tha define this submission
|
||||
* The configuration name that define this submission
|
||||
*/
|
||||
definition?: string,
|
||||
|
||||
|
@@ -3,29 +3,64 @@ import { Component, Injector, Input, OnInit, ViewChild } from '@angular/core';
|
||||
import { SectionsDirective } from '../sections.directive';
|
||||
import { SectionDataObject } from '../models/section-data.model';
|
||||
import { rendersSectionType } from '../sections-decorator';
|
||||
import { SectionsType } from '../sections-type';
|
||||
import { AlertType } from '../../../shared/alerts/aletrs-type';
|
||||
|
||||
/**
|
||||
* This component represents a section that contains the submission license form.
|
||||
*/
|
||||
@Component({
|
||||
selector: 'ds-submission-form-section-container',
|
||||
templateUrl: './section-container.component.html',
|
||||
styleUrls: ['./section-container.component.scss']
|
||||
})
|
||||
export class SectionContainerComponent implements OnInit {
|
||||
|
||||
/**
|
||||
* The collection id this submission belonging to
|
||||
* @type {string}
|
||||
*/
|
||||
@Input() collectionId: string;
|
||||
|
||||
/**
|
||||
* The section data
|
||||
* @type {SectionDataObject}
|
||||
*/
|
||||
@Input() sectionData: SectionDataObject;
|
||||
|
||||
/**
|
||||
* The submission id
|
||||
* @type {string}
|
||||
*/
|
||||
@Input() submissionId: string;
|
||||
|
||||
/**
|
||||
* The AlertType enumeration
|
||||
* @type {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;
|
||||
|
||||
/**
|
||||
* Initialize instance variables
|
||||
*
|
||||
* @param {Injector} injector
|
||||
*/
|
||||
constructor(private injector: Injector) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize all instance variables
|
||||
*/
|
||||
ngOnInit() {
|
||||
this.objectInjector = Injector.create({
|
||||
providers: [
|
||||
@@ -37,12 +72,21 @@ export class SectionContainerComponent implements OnInit {
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove section from submission form
|
||||
*
|
||||
* @param event
|
||||
* the event emitted
|
||||
*/
|
||||
public removeSection(event) {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
this.sectionRef.removeSection(this.submissionId, this.sectionData.id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the correct component based on the section's type
|
||||
*/
|
||||
getSectionContent(): string {
|
||||
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', () => {
|
||||
@@ -164,7 +164,7 @@ describe('SectionFormOperationsService test suite', () => {
|
||||
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 { DynamicRelationGroupModel } from '../../../shared/form/builder/ds-dynamic-form-ui/models/relation-group/dynamic-relation-group.model';
|
||||
|
||||
/**
|
||||
* The service handling all form section operations
|
||||
*/
|
||||
@Injectable()
|
||||
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,
|
||||
event: DynamicFormControlEvent,
|
||||
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 {
|
||||
let fieldIndex: number;
|
||||
if (isNotEmpty(event)) {
|
||||
@@ -60,7 +91,15 @@ export class SectionFormOperationsService {
|
||||
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)
|
||||
&& (model.parent as any).type === DYNAMIC_FORM_CONTROL_TYPE_GROUP
|
||||
&& (model.parent as any).parent
|
||||
@@ -68,7 +107,15 @@ export class SectionFormOperationsService {
|
||||
&& (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 context = this.formBuilder.isQualdropGroup(event.model)
|
||||
@@ -87,12 +134,28 @@ export class SectionFormOperationsService {
|
||||
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 {
|
||||
const fieldIndex = this.getArrayIndexFromEvent(event);
|
||||
const fieldId = this.getFieldPathSegmentedFromChangeEvent(event);
|
||||
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 {
|
||||
const fieldIndex = this.getArrayIndexFromEvent(event);
|
||||
const metadataValueMap = new Map();
|
||||
@@ -117,6 +180,14 @@ export class SectionFormOperationsService {
|
||||
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 {
|
||||
let fieldId;
|
||||
if (this.formBuilder.isQualdropGroup(event.model as DynamicFormControlModel)) {
|
||||
@@ -129,6 +200,14 @@ export class SectionFormOperationsService {
|
||||
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 {
|
||||
let fieldValue;
|
||||
const value = (event.model as any).value;
|
||||
@@ -162,6 +241,14 @@ export class SectionFormOperationsService {
|
||||
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> {
|
||||
const metadataValueMap = new Map();
|
||||
|
||||
@@ -177,6 +264,16 @@ export class SectionFormOperationsService {
|
||||
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,
|
||||
event: DynamicFormControlEvent,
|
||||
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,
|
||||
event: DynamicFormControlEvent,
|
||||
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>,
|
||||
pathCombiner: JsonPatchOperationPathCombiner,
|
||||
event: DynamicFormControlEvent,
|
||||
|
@@ -42,46 +42,55 @@ export class FormSectionComponent extends SectionModelComponent {
|
||||
|
||||
/**
|
||||
* The form id
|
||||
* @type {string}
|
||||
*/
|
||||
public formId;
|
||||
public formId: string;
|
||||
|
||||
/**
|
||||
* The form model
|
||||
* @type {DynamicFormControlModel[]}
|
||||
*/
|
||||
public formModel: DynamicFormControlModel[];
|
||||
|
||||
/**
|
||||
* A boolean representing if this section is updating
|
||||
* @type {boolean}
|
||||
*/
|
||||
public isUpdating = false;
|
||||
|
||||
/**
|
||||
* A boolean representing if this section is loading
|
||||
* @type {boolean}
|
||||
*/
|
||||
public isLoading = true;
|
||||
|
||||
/**
|
||||
* The form config
|
||||
* @type {SubmissionFormsModel}
|
||||
*/
|
||||
protected formConfig: SubmissionFormsModel;
|
||||
|
||||
/**
|
||||
* The form data
|
||||
* @type {any}
|
||||
*/
|
||||
protected formData: any = Object.create({});
|
||||
|
||||
/**
|
||||
* The [JsonPatchOperationPathCombiner] object
|
||||
* @type {JsonPatchOperationPathCombiner}
|
||||
*/
|
||||
protected pathCombiner: JsonPatchOperationPathCombiner;
|
||||
|
||||
/**
|
||||
* The [FormFieldPreviousValueObject] object
|
||||
* @type {FormFieldPreviousValueObject}
|
||||
*/
|
||||
protected previousValue: FormFieldPreviousValueObject = new FormFieldPreviousValueObject();
|
||||
|
||||
/**
|
||||
* The list of Subscription
|
||||
* @type {Array}
|
||||
*/
|
||||
protected subs: Subscription[] = [];
|
||||
|
||||
@@ -92,6 +101,7 @@ export class FormSectionComponent extends SectionModelComponent {
|
||||
|
||||
/**
|
||||
* Initialize instance variables
|
||||
*
|
||||
* @param {ChangeDetectorRef} cdr
|
||||
* @param {FormBuilderService} formBuilderService
|
||||
* @param {SectionFormOperationsService} formOperationsService
|
||||
@@ -158,6 +168,9 @@ export class FormSectionComponent extends SectionModelComponent {
|
||||
|
||||
/**
|
||||
* Get section status
|
||||
*
|
||||
* @return Observable<boolean>
|
||||
* the section status
|
||||
*/
|
||||
protected getSectionStatus(): Observable<boolean> {
|
||||
return this.formService.isValid(this.formId);
|
||||
@@ -290,6 +303,9 @@ export class FormSectionComponent extends SectionModelComponent {
|
||||
/**
|
||||
* Method called when a form dfChange event is fired.
|
||||
* Dispatch form operations based on changes.
|
||||
*
|
||||
* @param event
|
||||
* the [[DynamicFormControlEvent]] emitted
|
||||
*/
|
||||
onChange(event: DynamicFormControlEvent): void {
|
||||
this.formOperationsService.dispatchOperationsFromEvent(
|
||||
@@ -308,6 +324,9 @@ export class FormSectionComponent extends SectionModelComponent {
|
||||
/**
|
||||
* Method called when a form dfFocus event is fired.
|
||||
* Initialize [FormFieldPreviousValueObject] instance.
|
||||
*
|
||||
* @param event
|
||||
* the [[DynamicFormControlEvent]] emitted
|
||||
*/
|
||||
onFocus(event: DynamicFormControlEvent): void {
|
||||
const value = this.formOperationsService.getFieldValueFromChangeEvent(event);
|
||||
@@ -324,6 +343,9 @@ export class FormSectionComponent extends SectionModelComponent {
|
||||
/**
|
||||
* Method called when a form remove event is fired.
|
||||
* Dispatch form operations based on changes.
|
||||
*
|
||||
* @param event
|
||||
* the [[DynamicFormControlEvent]] emitted
|
||||
*/
|
||||
onRemove(event: DynamicFormControlEvent): void {
|
||||
this.formOperationsService.dispatchOperationsFromEvent(
|
||||
|
@@ -29,6 +29,9 @@ import { SectionsService } from '../sections.service';
|
||||
import { SectionFormOperationsService } from '../form/section-form-operations.service';
|
||||
import { FormComponent } from '../../../shared/form/form.component';
|
||||
|
||||
/**
|
||||
* This component represents a section that contains the submission license form.
|
||||
*/
|
||||
@Component({
|
||||
selector: 'ds-submission-section-license',
|
||||
styleUrls: ['./section-license.component.scss'],
|
||||
@@ -37,17 +40,68 @@ import { FormComponent } from '../../../shared/form/form.component';
|
||||
@renderSectionFor(SectionsType.License)
|
||||
export class LicenseSectionComponent extends SectionModelComponent {
|
||||
|
||||
public formId;
|
||||
/**
|
||||
* The form id
|
||||
* @type {string}
|
||||
*/
|
||||
public formId: string;
|
||||
|
||||
/**
|
||||
* The form model
|
||||
* @type {DynamicFormControlModel[]}
|
||||
*/
|
||||
public formModel: DynamicFormControlModel[];
|
||||
|
||||
/**
|
||||
* The [[DynamicFormLayout]] object
|
||||
* @type {DynamicFormLayout}
|
||||
*/
|
||||
public formLayout: DynamicFormLayout = SECTION_LICENSE_FORM_LAYOUT;
|
||||
|
||||
/**
|
||||
* A boolean representing if to show form submit and cancel buttons
|
||||
* @type {boolean}
|
||||
*/
|
||||
public displaySubmit = false;
|
||||
|
||||
/**
|
||||
* The submission license text
|
||||
* @type {Array}
|
||||
*/
|
||||
public licenseText$: Observable<string>;
|
||||
|
||||
/**
|
||||
* The [[JsonPatchOperationPathCombiner]] object
|
||||
* @type {JsonPatchOperationPathCombiner}
|
||||
*/
|
||||
protected pathCombiner: JsonPatchOperationPathCombiner;
|
||||
|
||||
/**
|
||||
* Array to track all subscriptions and unsubscribe them onDestroy
|
||||
* @type {Array}
|
||||
*/
|
||||
protected subs: Subscription[] = [];
|
||||
|
||||
/**
|
||||
* The FormComponent reference
|
||||
*/
|
||||
@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,
|
||||
protected collectionDataService: CollectionDataService,
|
||||
protected formBuilderService: FormBuilderService,
|
||||
@@ -62,6 +116,9 @@ export class LicenseSectionComponent extends SectionModelComponent {
|
||||
super(injectedCollectionId, injectedSectionData, injectedSubmissionId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize all instance variables and retrieve submission license
|
||||
*/
|
||||
onSectionInit() {
|
||||
this.pathCombiner = new JsonPatchOperationPathCombiner('sections', 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> {
|
||||
const model = this.formBuilderService.findById('granted', this.formModel);
|
||||
return (model as DynamicCheckboxModel).valueUpdates.pipe(
|
||||
@@ -133,6 +196,10 @@ export class LicenseSectionComponent extends SectionModelComponent {
|
||||
startWith((model as DynamicCheckboxModel).value));
|
||||
}
|
||||
|
||||
/**
|
||||
* Method called when a form dfChange event is fired.
|
||||
* Dispatch form operations based on changes.
|
||||
*/
|
||||
onChange(event: DynamicFormControlEvent) {
|
||||
const path = this.formOperationsService.getFieldPathSegmentedFromChangeEvent(event);
|
||||
const value = this.formOperationsService.getFieldValueFromChangeEvent(event);
|
||||
@@ -145,6 +212,9 @@ export class LicenseSectionComponent extends SectionModelComponent {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Unsubscribe from all subscriptions
|
||||
*/
|
||||
onSectionDestroy() {
|
||||
this.subs
|
||||
.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 { SectionsType } from '../sections-type';
|
||||
|
||||
/**
|
||||
* An interface to represent section model
|
||||
*/
|
||||
export interface SectionDataObject {
|
||||
|
||||
/**
|
||||
* The section configuration url
|
||||
*/
|
||||
config: string;
|
||||
|
||||
/**
|
||||
* The section data object
|
||||
*/
|
||||
data: WorkspaceitemSectionDataType;
|
||||
|
||||
/**
|
||||
* The list of the section errors
|
||||
*/
|
||||
errors: SubmissionSectionError[];
|
||||
|
||||
/**
|
||||
* The section header
|
||||
*/
|
||||
header: string;
|
||||
|
||||
/**
|
||||
* The section id
|
||||
*/
|
||||
id: string;
|
||||
|
||||
/**
|
||||
* A boolean representing if this section is mandatory
|
||||
*/
|
||||
mandatory: boolean;
|
||||
|
||||
/**
|
||||
* The section type
|
||||
*/
|
||||
sectionType: SectionsType;
|
||||
|
||||
/**
|
||||
* Eventually additional fields
|
||||
*/
|
||||
[propName: string]: any;
|
||||
}
|
||||
|
@@ -16,12 +16,44 @@ export interface SectionDataModel {
|
||||
*/
|
||||
export abstract class SectionModelComponent implements OnDestroy, OnInit, SectionDataModel {
|
||||
protected abstract sectionService: SectionsService;
|
||||
|
||||
/**
|
||||
* The collection id this submission belonging to
|
||||
* @type {string}
|
||||
*/
|
||||
collectionId: string;
|
||||
|
||||
/**
|
||||
* The section data
|
||||
* @type {SectionDataObject}
|
||||
*/
|
||||
sectionData: SectionDataObject;
|
||||
|
||||
/**
|
||||
* The submission id
|
||||
* @type {string}
|
||||
*/
|
||||
submissionId: string;
|
||||
|
||||
/**
|
||||
* A boolean representing if this section is valid
|
||||
* @type {boolean}
|
||||
*/
|
||||
protected valid: boolean;
|
||||
|
||||
/**
|
||||
* The Subscription to section status observable
|
||||
* @type {Subscription}
|
||||
*/
|
||||
private sectionStatusSub: Subscription;
|
||||
|
||||
/**
|
||||
* Initialize instance variables
|
||||
*
|
||||
* @param {string} injectedCollectionId
|
||||
* @param {SectionDataObject} injectedSectionData
|
||||
* @param {string} injectedSubmissionId
|
||||
*/
|
||||
public constructor(@Inject('collectionIdProvider') public injectedCollectionId: string,
|
||||
@Inject('sectionDataProvider') public injectedSectionData: SectionDataObject,
|
||||
@Inject('submissionIdProvider') public injectedSubmissionId: string) {
|
||||
@@ -30,15 +62,43 @@ export abstract class SectionModelComponent implements OnDestroy, OnInit, Sectio
|
||||
this.submissionId = injectedSubmissionId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Call abstract methods on component init
|
||||
*/
|
||||
ngOnInit(): void {
|
||||
this.onSectionInit();
|
||||
this.updateSectionStatus();
|
||||
}
|
||||
|
||||
/**
|
||||
* Abstract method to implement to get section status
|
||||
*
|
||||
* @return Observable<boolean>
|
||||
* the section status
|
||||
*/
|
||||
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;
|
||||
|
||||
/**
|
||||
* 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;
|
||||
|
||||
/**
|
||||
* Subscribe to section status
|
||||
*/
|
||||
protected updateSectionStatus(): void {
|
||||
this.sectionStatusSub = this.getSectionStatus().pipe(
|
||||
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 {
|
||||
if (hasValue(this.sectionStatusSub)) {
|
||||
this.sectionStatusSub.unsubscribe();
|
||||
|
@@ -10,28 +10,90 @@ import { SubmissionSectionError, SubmissionSectionObject } from '../objects/subm
|
||||
import parseSectionErrorPaths, { SectionErrorPath } from '../utils/parseSectionErrorPaths';
|
||||
import { SubmissionService } from '../submission.service';
|
||||
|
||||
/**
|
||||
* Directive for handling generic section functionality
|
||||
*/
|
||||
@Directive({
|
||||
selector: '[dsSection]',
|
||||
exportAs: 'sectionRef'
|
||||
})
|
||||
export class SectionsDirective implements OnDestroy, OnInit {
|
||||
|
||||
/**
|
||||
* A boolean representing if section is mandatory
|
||||
* @type {boolean}
|
||||
*/
|
||||
@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[] = [];
|
||||
|
||||
/**
|
||||
* The list of all errors related to the element belonging to this section
|
||||
* @type {Array}
|
||||
*/
|
||||
public allSectionErrors: string[] = [];
|
||||
|
||||
/**
|
||||
* A boolean representing if section is active
|
||||
* @type {boolean}
|
||||
*/
|
||||
private active = true;
|
||||
private animation = !this.mandatory;
|
||||
|
||||
/**
|
||||
* A boolean representing if section is enabled
|
||||
* @type {boolean}
|
||||
*/
|
||||
private enabled: Observable<boolean>;
|
||||
|
||||
/**
|
||||
* A boolean representing the panel collapsible state: opened (true) or closed (false)
|
||||
* @type {boolean}
|
||||
*/
|
||||
private sectionState = this.mandatory;
|
||||
|
||||
/**
|
||||
* Array to track all subscriptions and unsubscribe them onDestroy
|
||||
* @type {Array}
|
||||
*/
|
||||
private subs: Subscription[] = [];
|
||||
|
||||
/**
|
||||
* A boolean representing if section is valid
|
||||
* @type {boolean}
|
||||
*/
|
||||
private valid: Observable<boolean>;
|
||||
|
||||
/**
|
||||
* Initialize instance variables
|
||||
*
|
||||
* @param {ChangeDetectorRef} changeDetectorRef
|
||||
* @param {SubmissionService} submissionService
|
||||
* @param {SectionsService} sectionService
|
||||
*/
|
||||
constructor(private changeDetectorRef: ChangeDetectorRef,
|
||||
private submissionService: SubmissionService,
|
||||
private sectionService: SectionsService) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize instance variables
|
||||
*/
|
||||
ngOnInit() {
|
||||
this.valid = this.sectionService.isSectionValid(this.submissionId, this.sectionId).pipe(
|
||||
map((valid: boolean) => {
|
||||
@@ -78,67 +140,145 @@ export class SectionsDirective implements OnDestroy, OnInit {
|
||||
this.enabled = this.sectionService.isSectionEnabled(this.submissionId, this.sectionId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Unsubscribe from all subscriptions
|
||||
*/
|
||||
ngOnDestroy() {
|
||||
this.subs
|
||||
.filter((subscription) => hasValue(subscription))
|
||||
.forEach((subscription) => subscription.unsubscribe());
|
||||
}
|
||||
|
||||
/**
|
||||
* Change section state
|
||||
*
|
||||
* @param event
|
||||
* the event emitted
|
||||
*/
|
||||
public sectionChange(event) {
|
||||
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;
|
||||
}
|
||||
|
||||
public isMandatory() {
|
||||
/**
|
||||
* Check if section is mandatory
|
||||
*
|
||||
* @returns {boolean}
|
||||
* Returns true when section is mandatory
|
||||
*/
|
||||
public isMandatory(): boolean {
|
||||
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 {
|
||||
return this.active;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if section is enabled
|
||||
*
|
||||
* @returns {Observable<boolean>}
|
||||
* Emits true whenever section is enabled
|
||||
*/
|
||||
public isEnabled(): Observable<boolean> {
|
||||
return this.enabled;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if section is valid
|
||||
*
|
||||
* @returns {Observable<boolean>}
|
||||
* Emits true whenever section is valid
|
||||
*/
|
||||
public isValid(): Observable<boolean> {
|
||||
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)
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
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) ||
|
||||
(this.allSectionErrors && this.allSectionErrors.length > 0)
|
||||
}
|
||||
|
||||
public getErrors() {
|
||||
/**
|
||||
* Return section errors
|
||||
*
|
||||
* @returns {Array}
|
||||
* Returns section errors list
|
||||
*/
|
||||
public getErrors(): string[] {
|
||||
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) {
|
||||
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);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove all errors from list
|
||||
*/
|
||||
public resetErrors() {
|
||||
if (isNotEmpty(this.genericSectionErrors)) {
|
||||
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 { RemoteData } from '../../../../core/data/remote-data';
|
||||
|
||||
/**
|
||||
* This component represents a badge that describe an access condition
|
||||
*/
|
||||
@Component({
|
||||
selector: 'ds-section-upload-access-conditions',
|
||||
templateUrl: './section-upload-access-conditions.component.html',
|
||||
})
|
||||
export class SectionUploadAccessConditionsComponent implements OnInit {
|
||||
|
||||
/**
|
||||
* The list of resource policy
|
||||
* @type {Array}
|
||||
*/
|
||||
@Input() accessConditions: ResourcePolicy[];
|
||||
|
||||
/**
|
||||
* The list of access conditions
|
||||
* @type {Array}
|
||||
*/
|
||||
public accessConditionsList = [];
|
||||
|
||||
/**
|
||||
* Initialize instance variables
|
||||
*
|
||||
* @param {GroupEpersonService} groupService
|
||||
*/
|
||||
constructor(private groupService: GroupEpersonService) {}
|
||||
|
||||
/**
|
||||
* Retrieve access conditions list
|
||||
*/
|
||||
ngOnInit() {
|
||||
this.accessConditions.forEach((accessCondition: ResourcePolicy) => {
|
||||
if (isEmpty(accessCondition.name)) {
|
||||
|
@@ -1,6 +1,6 @@
|
||||
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 {
|
||||
DYNAMIC_FORM_CONTROL_TYPE_DATEPICKER,
|
||||
DynamicDateControlModel,
|
||||
@@ -12,6 +12,8 @@ import {
|
||||
DynamicFormGroupModel,
|
||||
DynamicSelectModel
|
||||
} 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 {
|
||||
BITSTREAM_ACCESS_CONDITIONS_FORM_ARRAY_CONFIG,
|
||||
@@ -35,37 +37,113 @@ import { AccessConditionOption } from '../../../../../core/config/models/config-
|
||||
import { SubmissionService } from '../../../../submission.service';
|
||||
import { FormService } from '../../../../../shared/form/form.service';
|
||||
import { FormComponent } from '../../../../../shared/form/form.component';
|
||||
import { FormControl } from '@angular/forms';
|
||||
import { Group } from '../../../../../core/eperson/models/group.model';
|
||||
|
||||
/**
|
||||
* This component represents the edit form for bitstream
|
||||
*/
|
||||
@Component({
|
||||
selector: 'ds-submission-upload-section-file-edit',
|
||||
templateUrl: './section-upload-file-edit.component.html',
|
||||
})
|
||||
export class UploadSectionFileEditComponent implements OnChanges {
|
||||
|
||||
/**
|
||||
* The list of available access condition
|
||||
* @type {Array}
|
||||
*/
|
||||
@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[];
|
||||
|
||||
/**
|
||||
* The FormComponent reference
|
||||
*/
|
||||
@ViewChild('formRef') public formRef: FormComponent;
|
||||
|
||||
/**
|
||||
* Initialize instance variables
|
||||
*
|
||||
* @param {ChangeDetectorRef} cdr
|
||||
* @param {FormBuilderService} formBuilderService
|
||||
* @param {FormService} formService
|
||||
* @param {SubmissionService} submissionService
|
||||
*/
|
||||
constructor(private cdr: ChangeDetectorRef,
|
||||
private formBuilderService: FormBuilderService,
|
||||
private formService: FormService,
|
||||
private submissionService: SubmissionService) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Dispatch form model init
|
||||
*/
|
||||
ngOnChanges() {
|
||||
if (this.fileData && this.formId) {
|
||||
this.formModel = this.buildFileEditForm();
|
||||
@@ -73,8 +151,10 @@ export class UploadSectionFileEditComponent implements OnChanges {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize form model
|
||||
*/
|
||||
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]);
|
||||
configDescr.repeatable = false;
|
||||
const configForm = Object.assign({}, this.configMetadataForm, {
|
||||
@@ -107,7 +187,7 @@ export class UploadSectionFileEditComponent implements OnChanges {
|
||||
}
|
||||
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 hasEnd = [];
|
||||
const hasGroups = [];
|
||||
@@ -153,6 +233,12 @@ export class UploadSectionFileEditComponent implements OnChanges {
|
||||
return formModel;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize form model values
|
||||
*
|
||||
* @param formModel
|
||||
* The form model
|
||||
*/
|
||||
public initModelData(formModel: DynamicFormControlModel[]) {
|
||||
this.fileData.accessConditions.forEach((accessCondition, index) => {
|
||||
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) {
|
||||
if (event.model.id === 'name') {
|
||||
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;
|
||||
this.availableAccessConditionOptions.filter((element) => element.name === control.value)
|
||||
.forEach((element) => accessCondition = element);
|
||||
if (isNotEmpty(accessCondition)) {
|
||||
const showGroups: boolean = accessCondition.hasStartDate === true || accessCondition.hasEndDate === true;
|
||||
|
||||
const groupControl: FormControl = control.parent.get('groupUUID');
|
||||
const startDateControl: FormControl = control.parent.get('startDate');
|
||||
const endDateControl: FormControl = control.parent.get('endDate');
|
||||
const groupControl: FormControl = control.parent.get('groupUUID') as FormControl;
|
||||
const startDateControl: FormControl = control.parent.get('startDate') as FormControl;
|
||||
const endDateControl: FormControl = control.parent.get('endDate') as FormControl;
|
||||
|
||||
// Clear previous state
|
||||
groupControl.markAsUntouched();
|
||||
@@ -236,8 +336,8 @@ export class UploadSectionFileEditComponent implements OnChanges {
|
||||
const confGroup = { relation: groupModel.relation };
|
||||
const groupsConfig = Object.assign({}, BITSTREAM_FORM_ACCESS_CONDITION_GROUPS_CONFIG, confGroup);
|
||||
groupsConfig.options = groupOptions;
|
||||
model.parent.group.pop();
|
||||
model.parent.group.push(new DynamicSelectModel(groupsConfig, BITSTREAM_FORM_ACCESS_CONDITION_GROUPS_LAYOUT));
|
||||
(model.parent as DynamicFormGroupModel).group.pop();
|
||||
(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 { BehaviorSubject } from 'rxjs';
|
||||
import { BehaviorSubject, Subscription } from 'rxjs';
|
||||
import { filter, first, flatMap, take } from 'rxjs/operators';
|
||||
import { DynamicFormControlModel, } from '@ng-dynamic-forms/core';
|
||||
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 { Group } from '../../../../core/eperson/models/group.model';
|
||||
|
||||
/**
|
||||
* This component represents a single bitstream contained in the submission
|
||||
*/
|
||||
@Component({
|
||||
selector: 'ds-submission-upload-section-file',
|
||||
styleUrls: ['./section-upload-file.component.scss'],
|
||||
@@ -30,28 +33,129 @@ import { Group } from '../../../../core/eperson/models/group.model';
|
||||
})
|
||||
export class UploadSectionFileComponent implements OnChanges, OnInit {
|
||||
|
||||
/**
|
||||
* The list of available access condition
|
||||
* @type {Array}
|
||||
*/
|
||||
@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 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[];
|
||||
|
||||
/**
|
||||
* A boolean representing if a submission delete operation is pending
|
||||
* @type {BehaviorSubject<boolean>}
|
||||
*/
|
||||
public processingDelete$ = new BehaviorSubject<boolean>(false);
|
||||
|
||||
/**
|
||||
* The [JsonPatchOperationPathCombiner] object
|
||||
* @type {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;
|
||||
|
||||
/**
|
||||
* 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,
|
||||
private fileService: FileService,
|
||||
private formService: FormService,
|
||||
@@ -64,6 +168,9 @@ export class UploadSectionFileComponent implements OnChanges, OnInit {
|
||||
this.readMode = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve bitstream's metadata
|
||||
*/
|
||||
ngOnChanges() {
|
||||
if (this.availableAccessConditionOptions && this.availableAccessConditionGroups) {
|
||||
// Retrieve file state
|
||||
@@ -79,11 +186,17 @@ export class UploadSectionFileComponent implements OnChanges, OnInit {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize instance variables
|
||||
*/
|
||||
ngOnInit() {
|
||||
this.formId = this.formService.getUniqueId(this.fileId);
|
||||
this.pathCombiner = new JsonPatchOperationPathCombiner('sections', this.sectionId, 'files', this.fileIndex);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete bitstream from submission
|
||||
*/
|
||||
protected deleteFile() {
|
||||
this.operationsBuilder.remove(this.pathCombiner.getPath());
|
||||
this.subscriptions.push(this.operationsService.jsonPatchByResourceID(
|
||||
@@ -97,6 +210,9 @@ export class UploadSectionFileComponent implements OnChanges, OnInit {
|
||||
}));
|
||||
}
|
||||
|
||||
/**
|
||||
* Show confirmation dialog for delete
|
||||
*/
|
||||
public confirmDelete(content) {
|
||||
this.modalService.open(content).result.then(
|
||||
(result) => {
|
||||
@@ -108,6 +224,9 @@ export class UploadSectionFileComponent implements OnChanges, OnInit {
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform bitstream download
|
||||
*/
|
||||
public downloadBitstreamFile() {
|
||||
this.halService.getEndpoint('bitstreams').pipe(
|
||||
first())
|
||||
@@ -117,9 +236,16 @@ export class UploadSectionFileComponent implements OnChanges, OnInit {
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Save bitstream metadata
|
||||
*
|
||||
* @param event
|
||||
* the click event emitted
|
||||
*/
|
||||
public saveBitstreamData(event) {
|
||||
event.preventDefault();
|
||||
|
||||
// validate form
|
||||
this.formService.validateAllFormFields(this.fileEditComp.formRef.formGroup);
|
||||
this.subscriptions.push(this.formService.isValid(this.formId).pipe(
|
||||
take(1),
|
||||
@@ -127,6 +253,7 @@ export class UploadSectionFileComponent implements OnChanges, OnInit {
|
||||
flatMap(() => this.formService.getFormData(this.formId)),
|
||||
take(1),
|
||||
flatMap((formData: any) => {
|
||||
// collect bitstream metadata
|
||||
Object.keys((formData.metadata))
|
||||
.filter((key) => isNotEmpty(formData.metadata[key]))
|
||||
.forEach((key) => {
|
||||
@@ -174,6 +301,7 @@ export class UploadSectionFileComponent implements OnChanges, OnInit {
|
||||
this.operationsBuilder.add(this.pathCombiner.getPath('accessConditions'), accessConditionsToSave, true);
|
||||
}
|
||||
|
||||
// dispatch a PATCH request to save metadata
|
||||
return this.operationsService.jsonPatchByResourceID(
|
||||
this.submissionService.getSubmissionObjectLinkName(),
|
||||
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;
|
||||
return (temp) ? temp.value : undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
* Switch from edit form to metadata view
|
||||
*/
|
||||
public switchMode() {
|
||||
this.readMode = !this.readMode;
|
||||
this.cdr.detectChanges();
|
||||
|
@@ -5,17 +5,42 @@ import { isNotEmpty } from '../../../../../shared/empty.util';
|
||||
import { Metadata } from '../../../../../core/shared/metadata.utils';
|
||||
import { MetadataMap, MetadataValue } from '../../../../../core/shared/metadata.models';
|
||||
|
||||
/**
|
||||
* This component allow to show bitstream's metadata
|
||||
*/
|
||||
@Component({
|
||||
selector: 'ds-submission-upload-section-file-view',
|
||||
templateUrl: './section-upload-file-view.component.html',
|
||||
})
|
||||
export class UploadSectionFileViewComponent implements OnInit {
|
||||
|
||||
/**
|
||||
* The bitstream's metadata data
|
||||
* @type {WorkspaceitemSectionUploadFileObject}
|
||||
*/
|
||||
@Input() fileData: WorkspaceitemSectionUploadFileObject;
|
||||
|
||||
/**
|
||||
* The [[MetadataMap]] object
|
||||
* @type {MetadataMap}
|
||||
*/
|
||||
public metadata: MetadataMap = Object.create({});
|
||||
|
||||
/**
|
||||
* The bitstream's title key
|
||||
* @type {string}
|
||||
*/
|
||||
public fileTitleKey = 'Title';
|
||||
|
||||
/**
|
||||
* The bitstream's description key
|
||||
* @type {string}
|
||||
*/
|
||||
public fileDescrKey = 'Description';
|
||||
|
||||
/**
|
||||
* Initialize instance variables
|
||||
*/
|
||||
ngOnInit() {
|
||||
if (isNotEmpty(this.fileData.metadata)) {
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
@@ -15,13 +15,10 @@
|
||||
<div *ngIf="collectionDefaultAccessConditions.length > 0" class="row">
|
||||
<div class="col-sm-12" >
|
||||
<ds-alert [type]="AlertTypeEnum.Warning">
|
||||
<!-- no def , no banner -->
|
||||
<ng-container *ngIf="collectionPolicyType === 1">
|
||||
<!-- def e no scelta -->
|
||||
{{ 'submission.sections.upload.header.policy.default.nolist' | translate:{ "collectionName": collectionName } }}
|
||||
</ng-container>
|
||||
<ng-container *ngIf="collectionPolicyType === 2">
|
||||
<!-- def e scelta -->
|
||||
{{ 'submission.sections.upload.header.policy.default.withlist' | translate:{ "collectionName": collectionName } }}
|
||||
</ng-container>
|
||||
<span class="clearfix"></span>
|
||||
|
@@ -1,6 +1,6 @@
|
||||
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 { SectionModelComponent } from '../models/section.model';
|
||||
@@ -33,6 +33,9 @@ export interface AccessConditionGroupsMapEntry {
|
||||
groups: Group[]
|
||||
}
|
||||
|
||||
/**
|
||||
* This component represents a section that contains submission's bitstreams
|
||||
*/
|
||||
@Component({
|
||||
selector: 'ds-submission-section-upload',
|
||||
styleUrls: ['./section-upload.component.scss'],
|
||||
@@ -41,37 +44,84 @@ export interface AccessConditionGroupsMapEntry {
|
||||
@renderSectionFor(SectionsType.Upload)
|
||||
export class UploadSectionComponent extends SectionModelComponent {
|
||||
|
||||
/**
|
||||
* The AlertType enumeration
|
||||
* @type {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;
|
||||
|
||||
/*
|
||||
/**
|
||||
* Default access conditions of this collection
|
||||
* @type {Array}
|
||||
*/
|
||||
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>;
|
||||
|
||||
/*
|
||||
/**
|
||||
* List of available access conditions that could be setted to files
|
||||
*/
|
||||
public availableAccessConditionOptions: AccessConditionOption[]; // List of accessConditions that an user can select
|
||||
|
||||
/*
|
||||
/**
|
||||
* List of Groups available for every access condition
|
||||
*/
|
||||
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,
|
||||
private changeDetectorRef: ChangeDetectorRef,
|
||||
private collectionDataService: CollectionDataService,
|
||||
@@ -84,10 +134,14 @@ export class UploadSectionComponent extends SectionModelComponent {
|
||||
super(undefined, injectedSectionData, injectedSubmissionId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize all instance variables and retrieve collection default access conditions
|
||||
*/
|
||||
onSectionInit() {
|
||||
const config$ = this.uploadsConfigService.getConfigByHref(this.sectionData.config).pipe(
|
||||
map((config) => config.payload));
|
||||
|
||||
// retrieve configuration for the bitstream's metadata form
|
||||
this.configMetadataForm$ = config$.pipe(
|
||||
take(1),
|
||||
map((config: SubmissionUploadsModel) => config.metadata));
|
||||
@@ -164,8 +218,9 @@ export class UploadSectionComponent extends SectionModelComponent {
|
||||
this.availableGroups.set(entry.accessCondition, entry.groups);
|
||||
});
|
||||
this.changeDetectorRef.detectChanges();
|
||||
})
|
||||
,
|
||||
}),
|
||||
|
||||
// retrieve submission's bitstreams from state
|
||||
combineLatest(this.configMetadataForm$,
|
||||
this.bitstreamService.getUploadedFileList(this.submissionId, this.sectionData.id)).pipe(
|
||||
filter(([configMetadataForm, fileList]: [SubmissionFormsModel, any[]]) => {
|
||||
@@ -191,6 +246,14 @@ export class UploadSectionComponent extends SectionModelComponent {
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return file name from metadata
|
||||
*
|
||||
* @param configMetadataForm
|
||||
* the bitstream's form configuration
|
||||
* @param fileData
|
||||
* the file metadata
|
||||
*/
|
||||
private getFileName(configMetadataForm: SubmissionFormsModel, fileData: any): string {
|
||||
const metadataName: string = configMetadataForm.rows[0].fields[0].selectableMetadata[0].metadata;
|
||||
let title: string;
|
||||
@@ -203,6 +266,12 @@ export class UploadSectionComponent extends SectionModelComponent {
|
||||
return title;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get section status
|
||||
*
|
||||
* @return Observable<boolean>
|
||||
* the section status
|
||||
*/
|
||||
protected getSectionStatus(): Observable<boolean> {
|
||||
return this.bitstreamService.getUploadedFileList(this.submissionId, this.sectionData.id).pipe(
|
||||
map((fileList: any[]) => (isNotUndefined(fileList) && fileList.length > 0)));
|
||||
|
@@ -14,51 +14,127 @@ import { submissionUploadedFileFromUuidSelector, submissionUploadedFilesFromIdSe
|
||||
import { isUndefined } from '../../../shared/empty.util';
|
||||
import { WorkspaceitemSectionUploadFileObject } from '../../../core/submission/models/workspaceitem-section-upload-file.model';
|
||||
|
||||
/**
|
||||
* A service that provides methods to handle submission's bitstream state.
|
||||
*/
|
||||
@Injectable()
|
||||
export class SectionUploadService {
|
||||
|
||||
/**
|
||||
* Initialize service variables
|
||||
*
|
||||
* @param {Store<SubmissionState>} store
|
||||
*/
|
||||
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> {
|
||||
return this.store.select(submissionUploadedFilesFromIdSelector(submissionId, sectionId)).pipe(
|
||||
map((state) => state),
|
||||
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(
|
||||
filter((state) => !isUndefined(state)),
|
||||
map((state) => {
|
||||
let fileState;
|
||||
Object.keys(state)
|
||||
.filter((key) => state[key].uuid === fileUuid)
|
||||
.filter((key) => state[key].uuid === fileUUID)
|
||||
.forEach((key) => fileState = state[key]);
|
||||
return fileState;
|
||||
}),
|
||||
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),
|
||||
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(
|
||||
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(
|
||||
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(
|
||||
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 { RemoteData } from '../core/data/remote-data';
|
||||
|
||||
/**
|
||||
* Instance of SubmissionService used on SSR.
|
||||
*/
|
||||
@Injectable()
|
||||
export class ServerSubmissionService extends SubmissionService {
|
||||
|
||||
/**
|
||||
* Override createSubmission parent method to return an empty observable
|
||||
*
|
||||
* @return Observable<SubmissionObject>
|
||||
* observable of SubmissionObject
|
||||
*/
|
||||
createSubmission(): Observable<SubmissionObject> {
|
||||
return observableOf(null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Override retrieveSubmission parent method to return an empty observable
|
||||
*
|
||||
* @return Observable<SubmissionObject>
|
||||
* observable of SubmissionObject
|
||||
*/
|
||||
retrieveSubmission(submissionId): Observable<RemoteData<SubmissionObject>> {
|
||||
return observableOf(null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Override startAutoSave parent method and return without doing anything
|
||||
*
|
||||
* @param submissionId
|
||||
* The submission id
|
||||
*/
|
||||
startAutoSave(submissionId) {
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Override startAutoSave parent method and return without doing anything
|
||||
*/
|
||||
stopAutoSave() {
|
||||
return;
|
||||
}
|
||||
|
@@ -11,6 +11,9 @@ import { SubmissionService } from '../submission.service';
|
||||
import { SubmissionObject } from '../../core/submission/models/submission-object.model';
|
||||
import { Collection } from '../../core/shared/collection.model';
|
||||
|
||||
/**
|
||||
* This component allows to submit a new workspaceitem.
|
||||
*/
|
||||
@Component({
|
||||
selector: 'ds-submit-page',
|
||||
styleUrls: ['./submission-submit.component.scss'],
|
||||
@@ -18,14 +21,46 @@ import { Collection } from '../../core/shared/collection.model';
|
||||
})
|
||||
export class SubmissionSubmitComponent implements OnDestroy, OnInit {
|
||||
|
||||
/**
|
||||
* The collection id this submission belonging to
|
||||
* @type {string}
|
||||
*/
|
||||
public collectionId: string;
|
||||
public model: any;
|
||||
|
||||
/**
|
||||
* The submission self url
|
||||
* @type {string}
|
||||
*/
|
||||
public selfUrl: string;
|
||||
|
||||
/**
|
||||
* The configuration object that define this submission
|
||||
* @type {SubmissionDefinitionsModel}
|
||||
*/
|
||||
public submissionDefinition: SubmissionDefinitionsModel;
|
||||
|
||||
/**
|
||||
* The submission id
|
||||
* @type {string}
|
||||
*/
|
||||
public submissionId: string;
|
||||
|
||||
/**
|
||||
* Array to track all subscriptions and unsubscribe them onDestroy
|
||||
* @type {Array}
|
||||
*/
|
||||
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,
|
||||
private notificationsService: NotificationsService,
|
||||
private router: Router,
|
||||
@@ -34,6 +69,9 @@ export class SubmissionSubmitComponent implements OnDestroy, OnInit {
|
||||
private viewContainerRef: ViewContainerRef) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Create workspaceitem on the server and initialize all instance variables
|
||||
*/
|
||||
ngOnInit() {
|
||||
// NOTE execute the code on the browser side only, otherwise it is executed twice
|
||||
this.subs.push(
|
||||
@@ -56,6 +94,9 @@ export class SubmissionSubmitComponent implements OnDestroy, OnInit {
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Unsubscribe from all subscriptions
|
||||
*/
|
||||
ngOnDestroy() {
|
||||
this.subs
|
||||
.filter((subscription) => hasValue(subscription))
|
||||
|
Reference in New Issue
Block a user