Added more comments

This commit is contained in:
Giuseppe Digilio
2019-03-21 11:22:17 +01:00
parent 3615075090
commit 4539ee704a
21 changed files with 282 additions and 6 deletions

View File

@@ -1,7 +1,7 @@
import { Component, OnDestroy, OnInit } from '@angular/core';
import { ActivatedRoute } from '@angular/router';
import { combineLatest as observableCombineLatest, Observable, Subscription } from 'rxjs';
import { combineLatest as observableCombineLatest, Subscription } from 'rxjs';
import { filter, take } from 'rxjs/operators';
import { Store } from '@ngrx/store';
@@ -16,17 +16,34 @@ import { hasValue, isNotEmpty } from '../shared/empty.util';
import { AuthTokenInfo } from '../core/auth/models/auth-token-info.model';
import { isAuthenticated } from '../core/auth/selectors';
/**
* This component represents the login page
*/
@Component({
selector: 'ds-login-page',
styleUrls: ['./login-page.component.scss'],
templateUrl: './login-page.component.html'
})
export class LoginPageComponent implements OnDestroy, OnInit {
/**
* Subscription to unsubscribe onDestroy
* @type {Subscription}
*/
sub: Subscription;
/**
* Initialize instance variables
*
* @param {ActivatedRoute} route
* @param {Store<AppState>} store
*/
constructor(private route: ActivatedRoute,
private store: Store<AppState>) {}
/**
* Initialize instance variables
*/
ngOnInit() {
const queryParamsObs = this.route.queryParams;
const authenticated = this.store.select(isAuthenticated);
@@ -52,6 +69,9 @@ export class LoginPageComponent implements OnDestroy, OnInit {
})
}
/**
* Unsubscribe from subscription
*/
ngOnDestroy() {
if (hasValue(this.sub)) {
this.sub.unsubscribe();

View File

@@ -53,6 +53,14 @@ export abstract class DataService<T extends CacheableObject> {
public abstract getBrowseEndpoint(options: FindAllOptions, linkPath?: string): Observable<string>
/**
* Create the HREF with given options object
*
* @param options The [[FindAllOptions]] object
* @param linkPath The link path for the object
* @return {Observable<string>}
* Return an observable that emits created HREF
*/
protected getFindAllHref(options: FindAllOptions = {}, linkPath?: string): Observable<string> {
let result: Observable<string>;
const args = [];
@@ -62,6 +70,14 @@ export abstract class DataService<T extends CacheableObject> {
return this.buildHrefFromFindOptions(result, args, options);
}
/**
* Create the HREF for a specific object's search method with given options object
*
* @param searchMethod The search method for the object
* @param options The [[FindAllOptions]] object
* @return {Observable<string>}
* Return an observable that emits created HREF
*/
protected getSearchByHref(searchMethod: string, options: FindAllOptions = {}): Observable<string> {
let result: Observable<string>;
const args = [];
@@ -77,6 +93,15 @@ export abstract class DataService<T extends CacheableObject> {
return this.buildHrefFromFindOptions(result, args, options);
}
/**
* Turn an options object into a query string and combine it with the given HREF
*
* @param href$ The HREF to which the query string should be appended
* @param args Array with additional params to combine with query string
* @param options The [[FindAllOptions]] object
* @return {Observable<string>}
* Return an observable that emits created HREF
*/
protected buildHrefFromFindOptions(href$: Observable<string>, args: string[], options: FindAllOptions): Observable<string> {
if (hasValue(options.currentPage) && typeof options.currentPage === 'number') {
@@ -146,6 +171,14 @@ export abstract class DataService<T extends CacheableObject> {
map((href: string) => `${href}/${searchMethod}`));
}
/**
* Make a new FindAllRequest with given search method
*
* @param searchMethod The search method for the object
* @param options The [[FindAllOptions]] object
* @return {Observable<RemoteData<PaginatedList<T>>}
* Return an observable that emits response from the server
*/
protected searchBy(searchMethod: string, options: FindAllOptions = {}): Observable<RemoteData<PaginatedList<T>>> {
const hrefObs = this.getSearchByHref(searchMethod, options);

View File

@@ -5,22 +5,37 @@ import { Workflowitem } from './workflowitem.model';
import { NormalizedSubmissionObject } from './normalized-submission-object.model';
import { ResourceType } from '../../shared/resource-type';
/**
* An model class for a NormalizedWorkflowItem.
*/
@mapsTo(Workflowitem)
@inheritSerialization(NormalizedSubmissionObject)
export class NormalizedWorkflowItem extends NormalizedSubmissionObject<Workflowitem> {
/**
* The collection this workflowitem belonging to
*/
@autoserialize
@relationship(ResourceType.Collection, false)
collection: string;
/**
* The item created with this workflowitem
*/
@autoserialize
@relationship(ResourceType.Item, false)
item: string;
/**
* The configuration object that define this workflowitem
*/
@autoserialize
@relationship(ResourceType.SubmissionDefinition, false)
submissionDefinition: string;
/**
* The EPerson who submit this workflowitem
*/
@autoserialize
@relationship(ResourceType.EPerson, false)
submitter: string;

View File

@@ -7,23 +7,38 @@ import { NormalizedDSpaceObject } from '../../cache/models/normalized-dspace-obj
import { ResourceType } from '../../shared/resource-type';
import { Workflowitem } from './workflowitem.model';
/**
* An model class for a NormalizedWorkspaceItem.
*/
@mapsTo(Workspaceitem)
@inheritSerialization(NormalizedDSpaceObject)
@inheritSerialization(NormalizedSubmissionObject)
export class NormalizedWorkspaceItem extends NormalizedSubmissionObject<Workflowitem> {
/**
* The collection this workspaceitem belonging to
*/
@autoserialize
@relationship(ResourceType.Collection, false)
collection: string;
/**
* The item created with this workspaceitem
*/
@autoserialize
@relationship(ResourceType.Item, false)
item: string;
/**
* The configuration object that define this workspaceitem
*/
@autoserialize
@relationship(ResourceType.SubmissionDefinition, false)
submissionDefinition: string;
/**
* The EPerson who submit this workspaceitem
*/
@autoserialize
@relationship(ResourceType.EPerson, false)
submitter: string;

View File

@@ -46,7 +46,7 @@ export abstract class SubmissionObject extends DSpaceObject implements Cacheable
sections: WorkspaceitemSectionsObject;
/**
* The submission config definition
* The configuration object that define this submission
*/
submissionDefinition: Observable<RemoteData<SubmissionDefinitionsModel>> | SubmissionDefinitionsModel;

View File

@@ -1,6 +1,10 @@
import { FormFieldMetadataValueObject } from '../../../shared/form/builder/models/form-field-metadata-value.model';
import { MetadataMapInterface } from '../../shared/metadata.models';
/**
* An interface to represent submission's form section data.
* A map of metadata keys to an ordered list of FormFieldMetadataValueObject objects.
*/
export interface WorkspaceitemSectionFormObject extends MetadataMapInterface {
[metadata: string]: FormFieldMetadataValueObject[];
}

View File

@@ -1,5 +1,20 @@
/**
* An interface to represent submission's license section data.
*/
export interface WorkspaceitemSectionLicenseObject {
/**
* The license url
*/
url: string;
/**
* The acceptance date of the license
*/
acceptanceDate: string;
/**
* A boolean representing if license has been granted
*/
granted: boolean;
}

View File

@@ -1,15 +1,46 @@
import { SubmissionUploadFileAccessConditionObject } from './submission-upload-file-access-condition.model';
import { WorkspaceitemSectionFormObject } from './workspaceitem-section-form.model';
/**
* An interface to represent submission's upload section file entry.
*/
export class WorkspaceitemSectionUploadFileObject {
/**
* The file UUID
*/
uuid: string;
/**
* The file metadata
*/
metadata: WorkspaceitemSectionFormObject;
/**
* The file size
*/
sizeBytes: number;
/**
* The file check sum
*/
checkSum: {
checkSumAlgorithm: string;
value: string;
};
/**
* The file url
*/
url: string;
/**
* The file thumbnail url
*/
thumbnail: string;
/**
* The list of file access conditions
*/
accessConditions: SubmissionUploadFileAccessConditionObject[];
}

View File

@@ -1,5 +1,12 @@
import { WorkspaceitemSectionUploadFileObject } from './workspaceitem-section-upload-file.model';
/**
* An interface to represent submission's upload section data.
*/
export interface WorkspaceitemSectionUploadObject {
/**
* A list of [[WorkspaceitemSectionUploadFileObject]]
*/
files: WorkspaceitemSectionUploadFileObject[];
}

View File

@@ -2,10 +2,17 @@ import { WorkspaceitemSectionFormObject } from './workspaceitem-section-form.mod
import { WorkspaceitemSectionLicenseObject } from './workspaceitem-section-license.model';
import { WorkspaceitemSectionUploadObject } from './workspaceitem-section-upload.model';
/**
* An interface to represent submission's section object.
* A map of section keys to an ordered list of WorkspaceitemSectionDataType objects.
*/
export class WorkspaceitemSectionsObject {
[name: string]: WorkspaceitemSectionDataType;
}
/**
* Export a type alias of all sections
*/
export type WorkspaceitemSectionDataType
= WorkspaceitemSectionUploadObject
| WorkspaceitemSectionFormObject

View File

@@ -9,6 +9,9 @@ import { SubmitDataResponseDefinitionObject } from '../shared/submit-data-respon
import { SubmissionPatchRequest } from '../data/request.models';
import { CoreState } from '../core.reducers';
/**
* A service that provides methods to make JSON Patch requests.
*/
@Injectable()
export class SubmissionJsonPatchOperationsService extends JsonPatchOperationsService<SubmitDataResponseDefinitionObject, SubmissionPatchRequest> {
protected linkPath = '';

View File

@@ -18,6 +18,11 @@ import { FormFieldMetadataValueObject } from '../../shared/form/builder/models/f
import { SubmissionObject } from './models/submission-object.model';
import { NormalizedObjectFactory } from '../cache/models/normalized-object-factory';
/**
* Export a function to check if object has same properties of FormFieldMetadataValueObject
*
* @param obj
*/
export function isServerFormValue(obj: any): boolean {
return (typeof obj === 'object'
&& obj.hasOwnProperty('value')
@@ -27,6 +32,11 @@ export function isServerFormValue(obj: any): boolean {
&& obj.hasOwnProperty('place'))
}
/**
* Export a function to normalize sections object of the server response
*
* @param obj
*/
export function normalizeSectionData(obj: any) {
let result: any = obj;
if (isNotNull(obj)) {
@@ -74,6 +84,13 @@ export class SubmissionResponseParsingService extends BaseResponseParsingService
super();
}
/**
* Parses data from the workspaceitems/workflowitems endpoints
*
* @param {RestRequest} request
* @param {DSpaceRESTV2Response} data
* @returns {RestResponse}
*/
parse(request: RestRequest, data: DSpaceRESTV2Response): RestResponse {
if (isNotEmpty(data.payload)
&& isNotEmpty(data.payload._links)
@@ -93,6 +110,13 @@ export class SubmissionResponseParsingService extends BaseResponseParsingService
}
}
/**
* Parses response and normalize it
*
* @param {DSpaceRESTV2Response} data
* @param {string} requestHref
* @returns {any[]}
*/
protected processResponse<ObjectDomain, ObjectType>(data: any, requestHref: string): any[] {
const dataDefinition = this.process<ObjectDomain, ObjectType>(data, requestHref);
const normalizedDefinition = Array.of();

View File

@@ -22,7 +22,7 @@ import { ErrorResponse, RestResponse, SubmissionSuccessResponse } from '../cache
import { getResponseFromEntry } from '../shared/operators';
/**
* The service handling all submission requests
* The service handling all submission REST requests
*/
@Injectable()
export class SubmissionRestService {

View File

@@ -14,6 +14,9 @@ import { NotificationsService } from '../../shared/notifications/notifications.s
import { ObjectCacheService } from '../cache/object-cache.service';
import { DSOChangeAnalyzer } from '../data/dso-change-analyzer.service';
/**
* A service that provides methods to make REST requests with workflowitems endpoint.
*/
@Injectable()
export class WorkflowitemDataService extends DataService<Workflowitem> {
protected linkPath = 'workflowitems';

View File

@@ -14,6 +14,9 @@ import { NotificationsService } from '../../shared/notifications/notifications.s
import { ObjectCacheService } from '../cache/object-cache.service';
import { DSOChangeAnalyzer } from '../data/dso-change-analyzer.service';
/**
* A service that provides methods to make REST requests with workspaceitems endpoint.
*/
@Injectable()
export class WorkspaceitemDataService extends DataService<Workspaceitem> {
protected linkPath = 'workspaceitems';

View File

@@ -4,6 +4,9 @@ import { trigger } from '@angular/animations';
import { AlertType } from './aletrs-type';
import { fadeOutLeave, fadeOutState } from '../animations/fade';
/**
* This component allow to create div that uses the Bootstrap's Alerts component.
*/
@Component({
selector: 'ds-alert',
encapsulation: ViewEncapsulation.None,
@@ -15,20 +18,49 @@ import { fadeOutLeave, fadeOutState } from '../animations/fade';
templateUrl: './alerts.component.html',
styleUrls: ['./alerts.component.scss']
})
export class AlertsComponent {
/**
* The alert content
*/
@Input() content: string;
/**
* A boolean representing if alert is dismissible
*/
@Input() dismissible = false;
/**
* The alert type
*/
@Input() type: AlertType;
/**
* An event fired when alert is dismissed.
*/
@Output() close: EventEmitter<any> = new EventEmitter<any>();
/**
* The initial animation name
*/
public animate = 'fadeIn';
/**
* A boolean representing if alert is dismissed or not
*/
public dismissed = false;
/**
* Initialize instance variables
*
* @param {ChangeDetectorRef} cdr
*/
constructor(private cdr: ChangeDetectorRef) {
}
/**
* Dismiss div with animation
*/
dismiss() {
if (this.dismissible) {
this.animate = 'fadeOut';

View File

@@ -19,25 +19,55 @@ import { isNotEmpty, isNull } from '../empty.util';
import { GLOBAL_CONFIG, GlobalConfig } from '../../../config';
import { ConfidenceIconConfig } from '../../../config/submission-config.interface';
/**
* Directive to add to the element a bootstrap utility class based on metadata confidence value
*/
@Directive({
selector: '[dsAuthorityConfidenceState]'
})
export class AuthorityConfidenceStateDirective implements OnChanges {
/**
* The metadata value
*/
@Input() authorityValue: AuthorityValue | FormFieldMetadataValueObject | string;
/**
* A boolean representing if to show html icon if authority value is empty
*/
@Input() visibleWhenAuthorityEmpty = true;
/**
* The css class applied before directive changes
*/
private previousClass: string = null;
/**
* The css class applied after directive changes
*/
private newClass: string;
/**
* An event fired when click on element that has a confidence value empty or different from CF_ACCEPTED
*/
@Output() whenClickOnConfidenceNotAccepted: EventEmitter<ConfidenceType> = new EventEmitter<ConfidenceType>();
/**
* Listener to click event
*/
@HostListener('click') onClick() {
if (isNotEmpty(this.authorityValue) && this.getConfidenceByValue(this.authorityValue) !== ConfidenceType.CF_ACCEPTED) {
this.whenClickOnConfidenceNotAccepted.emit(this.getConfidenceByValue(this.authorityValue));
}
}
/**
* Initialize instance variables
*
* @param {GlobalConfig} EnvConfig
* @param {ElementRef} elem
* @param {Renderer2} renderer
*/
constructor(
@Inject(GLOBAL_CONFIG) protected EnvConfig: GlobalConfig,
private elem: ElementRef,
@@ -45,6 +75,11 @@ export class AuthorityConfidenceStateDirective implements OnChanges {
) {
}
/**
* Apply css class to element whenever authority value change
*
* @param {SimpleChanges} changes
*/
ngOnChanges(changes: SimpleChanges): void {
if (!changes.authorityValue.firstChange) {
this.previousClass = this.getClassByConfidence(this.getConfidenceByValue(changes.authorityValue.previousValue))
@@ -59,6 +94,9 @@ export class AuthorityConfidenceStateDirective implements OnChanges {
}
}
/**
* Apply css class to element after view init
*/
ngAfterViewInit() {
if (isNull(this.previousClass)) {
this.renderer.addClass(this.elem.nativeElement, this.newClass);
@@ -68,6 +106,11 @@ export class AuthorityConfidenceStateDirective implements OnChanges {
}
}
/**
* Return confidence value as ConfidenceType
*
* @param value
*/
private getConfidenceByValue(value: any): ConfidenceType {
let confidence: ConfidenceType = ConfidenceType.CF_UNSET;
@@ -82,6 +125,11 @@ export class AuthorityConfidenceStateDirective implements OnChanges {
return confidence;
}
/**
* Return the properly css class based on confidence value
*
* @param confidence
*/
private getClassByConfidence(confidence: any): string {
if (!this.visibleWhenAuthorityEmpty && confidence === ConfidenceType.CF_UNSET) {
return 'd-none';

View File

@@ -1,5 +1,13 @@
import { Pipe, PipeTransform } from '@angular/core';
/**
* Pipe that allows to iterate over an object and to access to entry key and value :
*
* <div *ngFor="let obj of objs | dsObjNgFor">
* {{obj.key}} - {{obj.value}}
* </div>
*
*/
@Pipe({
name: 'dsObjNgFor'
})

View File

@@ -4,7 +4,9 @@ import { hasValue } from '../shared/empty.util';
import { submissionSelector, SubmissionState } from './submission.reducers';
import { SubmissionObjectEntry, SubmissionSectionObject } from './objects/submission-objects.reducer';
// @TODO: Merge with keySelector function present in 'src/app/core/shared/selectors.ts'
/**
* Export a function to return a subset of the state by key
*/
export function keySelector<T, V>(parentSelector: Selector<any, any>, subState: string, key: string): MemoizedSelector<T, V> {
return createSelector(parentSelector, (state: T) => {
if (hasValue(state) && hasValue(state[subState])) {
@@ -15,6 +17,9 @@ export function keySelector<T, V>(parentSelector: Selector<any, any>, subState:
});
}
/**
* Export a function to return a subset of the state
*/
export function subStateSelector<T, V>(parentSelector: Selector<any, any>, subState: string): MemoizedSelector<T, V> {
return createSelector(parentSelector, (state: T) => {
if (hasValue(state) && hasValue(state[subState])) {

View File

@@ -5,6 +5,9 @@ import {
SubmissionObjectState
} from './objects/submission-objects.reducer';
/**
* The Submission State
*/
export interface SubmissionState {
'objects': SubmissionObjectState
}

View File

@@ -15,7 +15,7 @@ import { Collection } from '../../core/shared/collection.model';
* This component allows to submit a new workspaceitem.
*/
@Component({
selector: 'ds-submit-page',
selector: 'ds-submission-submit',
styleUrls: ['./submission-submit.component.scss'],
templateUrl: './submission-submit.component.html'
})