diff --git a/src/app/core/submission/models/sherpa-policies-details.model.ts b/src/app/core/submission/models/sherpa-policies-details.model.ts new file mode 100644 index 0000000000..af4d4a5890 --- /dev/null +++ b/src/app/core/submission/models/sherpa-policies-details.model.ts @@ -0,0 +1,89 @@ +/** + * An interface to represent an access condition. + */ +export class SherpaPoliciesDetailsObject { + + /** + * The sherpa policies error + */ + error: boolean; + + /** + * The sherpa policies journal details + */ + journals: Journal[]; + + /** + * The sherpa policies message + */ + message: string; + + /** + * The sherpa policies metadata + */ + metadata: Metadata; + +} + + +export interface Metadata { + id: number; + uri: string; + dateCreated: string; + dateModified: string; + inDOAJ: boolean; + publiclyVisible: boolean; +} + + +export interface Journal { + titles: string[]; + url: string; + issns: string[]; + romeoPub: string; + zetoPub: string; + inDOAJ: boolean; + publisher: Publisher; + publishers: Publisher[]; + policies: Policy[]; +} + +export interface Publisher { + name: string; + relationshipType: string; + country: string; + uri: string; + identifier: string; + paidAccessDescription: string; + paidAccessUrl: string; + publicationCount: number; +} + +export interface Policy { + id: number; + openAccessPermitted: boolean; + uri: string; + internalMoniker: string; + permittedVersions: PermittedVersions[]; + urls: any; + publicationCount: number; + preArchiving: string; + postArchiving: string; + pubArchiving: string; + openAccessProhibited: boolean; +} + +export interface PermittedVersions { + articleVersion: string; + option: number; + conditions: string[]; + prerequisites: string[]; + locations: string[]; + licenses: string[]; + embargo: Embargo; +} + +export interface Embargo { + units: any; + amount: any; +} diff --git a/src/app/core/submission/models/workspaceitem-section-sherpa-policies.model.ts b/src/app/core/submission/models/workspaceitem-section-sherpa-policies.model.ts new file mode 100644 index 0000000000..c57beadbb9 --- /dev/null +++ b/src/app/core/submission/models/workspaceitem-section-sherpa-policies.model.ts @@ -0,0 +1,22 @@ +import { SherpaPoliciesDetailsObject } from './sherpa-policies-details.model'; + +/** + * An interface to represent the submission's item accesses condition. + */ +export interface WorkspaceitemSectionSherpaPoliciesObject { + + /** + * The access condition id + */ + id: string; + + /** + * The sherpa policies retrievalTime + */ + retrievalTime: string; + + /** + * The sherpa policies details + */ + sherpaResponse: SherpaPoliciesDetailsObject; +} diff --git a/src/app/core/submission/models/workspaceitem-sections.model.ts b/src/app/core/submission/models/workspaceitem-sections.model.ts index 084da3f088..1112d740ed 100644 --- a/src/app/core/submission/models/workspaceitem-sections.model.ts +++ b/src/app/core/submission/models/workspaceitem-sections.model.ts @@ -3,6 +3,7 @@ import { WorkspaceitemSectionFormObject } from './workspaceitem-section-form.mod import { WorkspaceitemSectionLicenseObject } from './workspaceitem-section-license.model'; import { WorkspaceitemSectionUploadObject } from './workspaceitem-section-upload.model'; import { WorkspaceitemSectionCcLicenseObject } from './workspaceitem-section-cc-license.model'; +import { WorkspaceitemSectionSherpaPoliciesObject } from './workspaceitem-section-sherpa-policies.model'; /** * An interface to represent submission's section object. @@ -21,4 +22,5 @@ export type WorkspaceitemSectionDataType | WorkspaceitemSectionLicenseObject | WorkspaceitemSectionCcLicenseObject | WorkspaceitemSectionAccessesObject + | WorkspaceitemSectionSherpaPoliciesObject | string; diff --git a/src/app/shared/mocks/section-sherpa-policies.service.mock.ts b/src/app/shared/mocks/section-sherpa-policies.service.mock.ts new file mode 100644 index 0000000000..9308325682 --- /dev/null +++ b/src/app/shared/mocks/section-sherpa-policies.service.mock.ts @@ -0,0 +1,101 @@ +import { + WorkspaceitemSectionSherpaPoliciesObject +} from '../../core/submission/models/workspaceitem-section-sherpa-policies.model'; + +export const SherpaDataResponse = { + 'id': 'sherpaPolicies', + 'retrievalTime': '2022-04-20T09:44:39.870+00:00', + 'sherpaResponse': + { + 'error': false, + 'message': null, + 'metadata': { + 'id': 23803, + 'uri': 'http://v2.sherpa.ac.uk/id/publication/23803', + 'dateCreated': '2012-11-20 14:51:52', + 'dateModified': '2020-03-06 11:25:54', + 'inDOAJ': false, + 'publiclyVisible': true + }, + 'journals': [{ + 'titles': ['The Lancet', 'Lancet'], + 'url': 'http://www.thelancet.com/journals/lancet/issue/current', + 'issns': ['0140-6736', '1474-547X'], + 'romeoPub': 'Elsevier: The Lancet', + 'zetoPub': 'Elsevier: The Lancet', + 'publisher': { + 'name': 'Elsevier', + 'relationshipType': null, + 'country': null, + 'uri': 'http://www.elsevier.com/', + 'identifier': null, + 'publicationCount': 0, + 'paidAccessDescription': 'Open access', + 'paidAccessUrl': 'https://www.elsevier.com/about/open-science/open-access' + }, + 'publishers': [{ + 'name': 'Elsevier', + 'relationshipType': null, + 'country': null, + 'uri': 'http://www.elsevier.com/', + 'identifier': null, + 'publicationCount': 0, + 'paidAccessDescription': 'Open access', + 'paidAccessUrl': 'https://www.elsevier.com/about/open-science/open-access' + }], + 'policies': [{ + 'id': 0, + 'openAccessPermitted': false, + 'uri': null, + 'internalMoniker': 'Lancet', + 'permittedVersions': [{ + 'articleVersion': 'submitted', + 'option': 1, + 'conditions': ['Upon publication publisher copyright and source must be acknowledged', 'Upon publication must link to publisher version'], + 'prerequisites': [], + 'locations': ['Author\'s Homepage', 'Preprint Repository'], + 'licenses': [], + 'embargo': null + }, { + 'articleVersion': 'accepted', + 'option': 1, + 'conditions': ['Publisher copyright and source must be acknowledged', 'Must link to publisher version'], + 'prerequisites': [], + 'locations': ['Author\'s Homepage', 'Institutional Website'], + 'licenses': ['CC BY-NC-ND'], + 'embargo': null + }, { + 'articleVersion': 'accepted', + 'option': 2, + 'conditions': ['Publisher copyright and source must be acknowledged', 'Must link to publisher version'], + 'prerequisites': ['If Required by Funder'], + 'locations': ['Non-Commercial Repository'], + 'licenses': ['CC BY-NC-ND'], + 'embargo': { amount: 6, units: 'Months' } + }, { + 'articleVersion': 'accepted', + 'option': 3, + 'conditions': ['Publisher copyright and source must be acknowledged', 'Must link to publisher version'], + 'prerequisites': [], + 'locations': ['Non-Commercial Repository'], + 'licenses': [], + 'embargo': null + }], + 'urls': { + 'http://download.thelancet.com/flatcontentassets/authors/lancet-information-for-authors.pdf': 'Guidelines for Authors', + 'http://www.thelancet.com/journals/lancet/article/PIIS0140-6736%2813%2960720-5/fulltext': 'The Lancet journals welcome a new open access policy', + 'http://www.thelancet.com/lancet-information-for-authors/after-publication': 'What happens after publication?', + 'http://www.thelancet.com/lancet/information-for-authors/disclosure-of-results': 'Disclosure of results before publication', + 'https://www.elsevier.com/__data/assets/pdf_file/0005/78476/external-embargo-list.pdf': 'Journal Embargo Period List', + 'https://www.elsevier.com/__data/assets/pdf_file/0011/78473/UK-Embargo-Periods.pdf': 'Journal Embargo List for UK Authors' + }, + 'openAccessProhibited': false, + 'publicationCount': 0, + 'preArchiving': 'can', + 'postArchiving': 'can', + 'pubArchiving': 'cannot' + }], + 'inDOAJ': false + }] + } +} as WorkspaceitemSectionSherpaPoliciesObject; diff --git a/src/app/shared/testing/sections-service.stub.ts b/src/app/shared/testing/sections-service.stub.ts index 1628453bc8..b687c512c2 100644 --- a/src/app/shared/testing/sections-service.stub.ts +++ b/src/app/shared/testing/sections-service.stub.ts @@ -20,4 +20,5 @@ export class SectionsServiceStub { computeSectionConfiguredMetadata = jasmine.createSpy('computeSectionConfiguredMetadata'); getShownSectionErrors = jasmine.createSpy('getShownSectionErrors'); getSectionServerErrors = jasmine.createSpy('getSectionServerErrors'); + getIsInformational = jasmine.createSpy('getIsInformational'); } diff --git a/src/app/submission/objects/submission-objects.effects.ts b/src/app/submission/objects/submission-objects.effects.ts index e79670306f..4a7907cab1 100644 --- a/src/app/submission/objects/submission-objects.effects.ts +++ b/src/app/submission/objects/submission-objects.effects.ts @@ -2,7 +2,7 @@ import { Injectable } from '@angular/core'; import { Actions, createEffect, ofType } from '@ngrx/effects'; import { Store } from '@ngrx/store'; import { TranslateService } from '@ngx-translate/core'; -import { isEqual, union } from 'lodash'; +import { findKey, isEqual, union } from 'lodash'; import { from as observableFrom, Observable, of as observableOf } from 'rxjs'; import { catchError, filter, map, mergeMap, switchMap, take, tap, withLatestFrom } from 'rxjs/operators'; @@ -43,7 +43,7 @@ import { UpdateSectionDataAction, UpdateSectionDataSuccessAction } from './submission-objects.actions'; -import { SubmissionObjectEntry} from './submission-objects.reducer'; +import { SubmissionObjectEntry } from './submission-objects.reducer'; import { Item } from '../../core/shared/item.model'; import { RemoteData } from '../../core/data/remote-data'; import { getFirstSucceededRemoteDataPayload } from '../../core/shared/operators'; @@ -60,7 +60,7 @@ export class SubmissionObjectEffects { /** * Dispatch a [InitSectionAction] for every submission sections and dispatch a [CompleteInitSubmissionFormAction] */ - loadForm$ = createEffect(() => this.actions$.pipe( + loadForm$ = createEffect(() => this.actions$.pipe( ofType(SubmissionObjectActionTypes.INIT_SUBMISSION_FORM), map((action: InitSubmissionFormAction) => { const definition = action.payload.submissionDefinition; @@ -104,7 +104,7 @@ export class SubmissionObjectEffects { /** * Dispatch a [InitSubmissionFormAction] */ - resetForm$ = createEffect(() => this.actions$.pipe( + resetForm$ = createEffect(() => this.actions$.pipe( ofType(SubmissionObjectActionTypes.RESET_SUBMISSION_FORM), map((action: ResetSubmissionFormAction) => new InitSubmissionFormAction( @@ -120,35 +120,35 @@ export class SubmissionObjectEffects { /** * Dispatch a [SaveSubmissionFormSuccessAction] or a [SaveSubmissionFormErrorAction] on error */ - saveSubmission$ = createEffect(() => this.actions$.pipe( + saveSubmission$ = createEffect(() => this.actions$.pipe( ofType(SubmissionObjectActionTypes.SAVE_SUBMISSION_FORM), switchMap((action: SaveSubmissionFormAction) => { return this.operationsService.jsonPatchByResourceType( this.submissionService.getSubmissionObjectLinkName(), action.payload.submissionId, 'sections').pipe( - map((response: SubmissionObject[]) => new SaveSubmissionFormSuccessAction(action.payload.submissionId, response, action.payload.isManual, action.payload.isManual)), - catchError(() => observableOf(new SaveSubmissionFormErrorAction(action.payload.submissionId)))); + map((response: SubmissionObject[]) => new SaveSubmissionFormSuccessAction(action.payload.submissionId, response, action.payload.isManual, action.payload.isManual)), + catchError(() => observableOf(new SaveSubmissionFormErrorAction(action.payload.submissionId)))); }))); /** * Dispatch a [SaveForLaterSubmissionFormSuccessAction] or a [SaveSubmissionFormErrorAction] on error */ - saveForLaterSubmission$ = createEffect(() => this.actions$.pipe( + saveForLaterSubmission$ = createEffect(() => this.actions$.pipe( ofType(SubmissionObjectActionTypes.SAVE_FOR_LATER_SUBMISSION_FORM), switchMap((action: SaveForLaterSubmissionFormAction) => { return this.operationsService.jsonPatchByResourceType( this.submissionService.getSubmissionObjectLinkName(), action.payload.submissionId, 'sections').pipe( - map((response: SubmissionObject[]) => new SaveForLaterSubmissionFormSuccessAction(action.payload.submissionId, response)), - catchError(() => observableOf(new SaveSubmissionFormErrorAction(action.payload.submissionId)))); + map((response: SubmissionObject[]) => new SaveForLaterSubmissionFormSuccessAction(action.payload.submissionId, response)), + catchError(() => observableOf(new SaveSubmissionFormErrorAction(action.payload.submissionId)))); }))); /** * Call parseSaveResponse and dispatch actions */ - saveSubmissionSuccess$ = createEffect(() => this.actions$.pipe( + saveSubmissionSuccess$ = createEffect(() => this.actions$.pipe( ofType(SubmissionObjectActionTypes.SAVE_SUBMISSION_FORM_SUCCESS), withLatestFrom(this.store$), map(([action, currentState]: [SaveSubmissionFormSuccessAction, any]) => { @@ -162,7 +162,7 @@ export class SubmissionObjectEffects { * Call parseSaveResponse and dispatch actions. * Notification system is forced to be disabled. */ - saveSubmissionSectionSuccess$ = createEffect(() => this.actions$.pipe( + saveSubmissionSectionSuccess$ = createEffect(() => this.actions$.pipe( ofType(SubmissionObjectActionTypes.SAVE_SUBMISSION_SECTION_FORM_SUCCESS), withLatestFrom(this.store$), map(([action, currentState]: [SaveSubmissionSectionFormSuccessAction, any]) => { @@ -174,7 +174,7 @@ export class SubmissionObjectEffects { /** * Dispatch a [SaveSubmissionSectionFormSuccessAction] or a [SaveSubmissionSectionFormErrorAction] on error */ - saveSection$ = createEffect(() => this.actions$.pipe( + saveSection$ = createEffect(() => this.actions$.pipe( ofType(SubmissionObjectActionTypes.SAVE_SUBMISSION_SECTION_FORM), switchMap((action: SaveSubmissionSectionFormAction) => { return this.operationsService.jsonPatchByResourceID( @@ -182,14 +182,14 @@ export class SubmissionObjectEffects { action.payload.submissionId, 'sections', action.payload.sectionId).pipe( - map((response: SubmissionObject[]) => new SaveSubmissionSectionFormSuccessAction(action.payload.submissionId, response)), - catchError(() => observableOf(new SaveSubmissionSectionFormErrorAction(action.payload.submissionId)))); + map((response: SubmissionObject[]) => new SaveSubmissionSectionFormSuccessAction(action.payload.submissionId, response)), + catchError(() => observableOf(new SaveSubmissionSectionFormErrorAction(action.payload.submissionId)))); }))); /** * Show a notification on error */ - saveError$ = createEffect(() => this.actions$.pipe( + saveError$ = createEffect(() => this.actions$.pipe( ofType(SubmissionObjectActionTypes.SAVE_SUBMISSION_FORM_ERROR, SubmissionObjectActionTypes.SAVE_SUBMISSION_SECTION_FORM_ERROR), withLatestFrom(this.store$), tap(() => this.notificationsService.error(null, this.translate.get('submission.sections.general.save_error_notice')))), { dispatch: false }); @@ -197,7 +197,7 @@ export class SubmissionObjectEffects { /** * Call parseSaveResponse and dispatch actions or dispatch [SaveSubmissionFormErrorAction] on error */ - saveAndDeposit$ = createEffect(() => this.actions$.pipe( + saveAndDeposit$ = createEffect(() => this.actions$.pipe( ofType(SubmissionObjectActionTypes.SAVE_AND_DEPOSIT_SUBMISSION), withLatestFrom(this.submissionService.hasUnsavedModification()), switchMap(([action, hasUnsavedModification]: [SaveAndDepositSubmissionAction, boolean]) => { @@ -233,7 +233,7 @@ export class SubmissionObjectEffects { /** * Dispatch a [DepositSubmissionSuccessAction] or a [DepositSubmissionErrorAction] on error */ - depositSubmission$ = createEffect(() => this.actions$.pipe( + depositSubmission$ = createEffect(() => this.actions$.pipe( ofType(SubmissionObjectActionTypes.DEPOSIT_SUBMISSION), withLatestFrom(this.store$), switchMap(([action, state]: [DepositSubmissionAction, any]) => { @@ -245,7 +245,7 @@ export class SubmissionObjectEffects { /** * Show a notification on success and redirect to MyDSpace page */ - saveForLaterSubmissionSuccess$ = createEffect(() => this.actions$.pipe( + saveForLaterSubmissionSuccess$ = createEffect(() => this.actions$.pipe( ofType(SubmissionObjectActionTypes.SAVE_FOR_LATER_SUBMISSION_FORM_SUCCESS), tap(() => this.notificationsService.success(null, this.translate.get('submission.sections.general.save_success_notice'))), tap(() => this.submissionService.redirectToMyDSpace())), { dispatch: false }); @@ -253,7 +253,7 @@ export class SubmissionObjectEffects { /** * Show a notification on success and redirect to MyDSpace page */ - depositSubmissionSuccess$ = createEffect(() => this.actions$.pipe( + depositSubmissionSuccess$ = createEffect(() => this.actions$.pipe( ofType(SubmissionObjectActionTypes.DEPOSIT_SUBMISSION_SUCCESS), tap(() => this.notificationsService.success(null, this.translate.get('submission.sections.general.deposit_success_notice'))), tap(() => this.submissionService.redirectToMyDSpace())), { dispatch: false }); @@ -261,14 +261,14 @@ export class SubmissionObjectEffects { /** * Show a notification on error */ - depositSubmissionError$ = createEffect(() => this.actions$.pipe( + depositSubmissionError$ = createEffect(() => this.actions$.pipe( ofType(SubmissionObjectActionTypes.DEPOSIT_SUBMISSION_ERROR), tap(() => this.notificationsService.error(null, this.translate.get('submission.sections.general.deposit_error_notice')))), { dispatch: false }); /** * Dispatch a [DiscardSubmissionSuccessAction] or a [DiscardSubmissionErrorAction] on error */ - discardSubmission$ = createEffect(() => this.actions$.pipe( + discardSubmission$ = createEffect(() => this.actions$.pipe( ofType(SubmissionObjectActionTypes.DISCARD_SUBMISSION), switchMap((action: DepositSubmissionAction) => { return this.submissionService.discardSubmission(action.payload.submissionId).pipe( @@ -279,7 +279,7 @@ export class SubmissionObjectEffects { /** * Adds all metadata an item to the SubmissionForm sections of the submission */ - addAllMetadataToSectionData = createEffect(() => this.actions$.pipe( + addAllMetadataToSectionData = createEffect(() => this.actions$.pipe( ofType(SubmissionObjectActionTypes.UPDATE_SECTION_DATA), switchMap((action: UpdateSectionDataAction) => { return this.sectionService.getSectionState(action.payload.submissionId, action.payload.sectionId, SectionsType.Upload) @@ -320,18 +320,18 @@ export class SubmissionObjectEffects { /** * Show a notification on error */ - discardSubmissionError$ = createEffect(() => this.actions$.pipe( + discardSubmissionError$ = createEffect(() => this.actions$.pipe( ofType(SubmissionObjectActionTypes.DISCARD_SUBMISSION_ERROR), tap(() => this.notificationsService.error(null, this.translate.get('submission.sections.general.discard_error_notice')))), { dispatch: false }); constructor(private actions$: Actions, - private notificationsService: NotificationsService, - private operationsService: SubmissionJsonPatchOperationsService, - private sectionService: SectionsService, - private store$: Store, - private submissionService: SubmissionService, - private submissionObjectService: SubmissionObjectDataService, - private translate: TranslateService) { + private notificationsService: NotificationsService, + private operationsService: SubmissionJsonPatchOperationsService, + private sectionService: SectionsService, + private store$: Store, + private submissionService: SubmissionService, + private submissionObjectService: SubmissionObjectDataService, + private translate: TranslateService) { } /** @@ -425,7 +425,15 @@ export class SubmissionObjectEffects { const filteredErrors = filterErrors(sectionForm, sectionErrors, currentState.sections[sectionId].sectionType, showErrors); mappedActions.push(new UpdateSectionDataAction(submissionId, sectionId, sectionData, filteredErrors, sectionErrors)); } + + // Sherpa Policies section needs to be updated when the rest response section is empty + const sherpaPoliciesSectionId = findKey(currentState.sections, (section) => section.sectionType === SectionsType.SherpaPolicies); + if (isNotUndefined(sherpaPoliciesSectionId) && isNotEmpty(currentState.sections[sherpaPoliciesSectionId]?.data) + && isEmpty(sections[sherpaPoliciesSectionId])) { + mappedActions.push(new UpdateSectionDataAction(submissionId, sherpaPoliciesSectionId, null, [], [])); + } }); + } return mappedActions; } diff --git a/src/app/submission/sections/container/section-container.component.html b/src/app/submission/sections/container/section-container.component.html index e7a9d141c7..e6ae9d1b9c 100644 --- a/src/app/submission/sections/container/section-container.component.html +++ b/src/app/submission/sections/container/section-container.component.html @@ -1,52 +1,51 @@ -
- - +
+ + - {{ 'submission.sections.'+sectionData.header | translate }} + {{ + 'submission.sections.'+sectionData.header | translate + }}
- +
-
+
-
+
\ No newline at end of file diff --git a/src/app/submission/sections/container/section-container.component.scss b/src/app/submission/sections/container/section-container.component.scss index f3e0ab6cf4..8a286467d5 100644 --- a/src/app/submission/sections/container/section-container.component.scss +++ b/src/app/submission/sections/container/section-container.component.scss @@ -10,7 +10,7 @@ // TODO to remove the following when upgrading @ng-bootstrap :host ::ng-deep .card:first-of-type { - border-bottom: var(--bs-card-border-width) solid var(--bs-card-border-color) !important; + border-bottom: var(--bs-card-border-width) solid var(--bs-card-border-color) !important; border-bottom-left-radius: var(--bs-card-border-radius) !important; border-bottom-right-radius: var(--bs-card-border-radius) !important; } @@ -18,4 +18,4 @@ :host ::ng-deep .card-header button { box-shadow: none !important; width: 100%; -} +} \ No newline at end of file diff --git a/src/app/submission/sections/sections-type.ts b/src/app/submission/sections/sections-type.ts index d13aef1da1..6b6f839b7c 100644 --- a/src/app/submission/sections/sections-type.ts +++ b/src/app/submission/sections/sections-type.ts @@ -6,4 +6,5 @@ export enum SectionsType { CcLicense = 'cclicense', collection = 'collection', AccessesCondition = 'accessCondition', + SherpaPolicies = 'sherpaPolicy', } diff --git a/src/app/submission/sections/sections.directive.ts b/src/app/submission/sections/sections.directive.ts index 3ffb317b15..d82cff82d6 100644 --- a/src/app/submission/sections/sections.directive.ts +++ b/src/app/submission/sections/sections.directive.ts @@ -94,8 +94,8 @@ export class SectionsDirective implements OnDestroy, OnInit { * @param {SectionsService} sectionService */ constructor(private changeDetectorRef: ChangeDetectorRef, - private submissionService: SubmissionService, - private sectionService: SectionsService) { + private submissionService: SubmissionService, + private sectionService: SectionsService) { } /** @@ -272,6 +272,19 @@ export class SectionsDirective implements OnDestroy, OnInit { } } + + /** + * Check if section is information + * + * @returns {Observable} + * Emits true whenever section is information + */ + public isInfo(): boolean { + return this.sectionService.getIsInformational(this.sectionType); + } + + + /** * Remove error from list * diff --git a/src/app/submission/sections/sections.service.ts b/src/app/submission/sections/sections.service.ts index 64f9e2efcd..56b2356ed7 100644 --- a/src/app/submission/sections/sections.service.ts +++ b/src/app/submission/sections/sections.service.ts @@ -60,11 +60,11 @@ export class SectionsService { * @param {TranslateService} translate */ constructor(private formService: FormService, - private notificationsService: NotificationsService, - private scrollToService: ScrollToService, - private submissionService: SubmissionService, - private store: Store, - private translate: TranslateService) { + private notificationsService: NotificationsService, + private scrollToService: ScrollToService, + private submissionService: SubmissionService, + private store: Store, + private translate: TranslateService) { } /** @@ -197,7 +197,7 @@ export class SectionsService { path: pathCombiner.getPath(error.fieldId.replace(/\_/g, '.')).path, message: error.message } as SubmissionSectionError)) - .filter((sectionError: SubmissionSectionError) => findIndex(state.errorsToShow, {path: sectionError.path}) === -1); + .filter((sectionError: SubmissionSectionError) => findIndex(state.errorsToShow, { path: sectionError.path }) === -1); return [...state.errorsToShow, ...sectionErrors]; }) )) @@ -262,7 +262,7 @@ export class SectionsService { } }), distinctUntilChanged() - ); + ); } /** @@ -371,7 +371,7 @@ export class SectionsService { return this.store.select(submissionObjectFromIdSelector(submissionId)).pipe( filter((submissionState: SubmissionObjectEntry) => isNotUndefined(submissionState)), map((submissionState: SubmissionObjectEntry) => { - return isNotUndefined(submissionState.sections) && isNotUndefined(findKey(submissionState.sections, {sectionType: sectionType})); + return isNotUndefined(submissionState.sections) && isNotUndefined(findKey(submissionState.sections, { sectionType: sectionType })); }), distinctUntilChanged()); } @@ -514,4 +514,16 @@ export class SectionsService { return metadata; } + /** + * Return if the section is an informational type section. + * @param sectionType + */ + public getIsInformational(sectionType: SectionsType): boolean { + if (sectionType === SectionsType.SherpaPolicies) { + return true; + } else { + return false; + } + } + } diff --git a/src/app/submission/sections/sherpa-policies/content-accordion/content-accordion.component.html b/src/app/submission/sections/sherpa-policies/content-accordion/content-accordion.component.html new file mode 100644 index 0000000000..3d4fba5cea --- /dev/null +++ b/src/app/submission/sections/sherpa-policies/content-accordion/content-accordion.component.html @@ -0,0 +1,90 @@ +
+
+
+ +
+ {{version.embargo.amount}} + {{version.embargo?.units[0]}} + + {{ + 'submission.sections.sherpa.publisher.policy.noembargo' | translate }} + + + + + + {{version.locations[0]}} +{{version.locations.length-1}} + + + {{ + 'submission.sections.sherpa.publisher.policy.nolocation' | translate }} + + +
+
+
+ + +
+
+
+
+
+
+

{{ + 'submission.sections.sherpa.publisher.policy.embargo' | translate }}

+
+
+

{{version.embargo.amount}} + {{version.embargo.units}}

+ +

{{ 'submission.sections.sherpa.publisher.policy.noembargo' | translate }}

+
+
+
+
+
+

{{ + 'submission.sections.sherpa.publisher.policy.license' | translate }}

+
+
+

{{license}}

+
+
+
+
+

{{ + 'submission.sections.sherpa.publisher.policy.prerequisites' | translate }}

+
+
+

{{prerequisite}}

+
+
+
+
+

{{ + 'submission.sections.sherpa.publisher.policy.location' | translate }}

+
+
+

{{location}}

+
+
+
+
+

{{ + 'submission.sections.sherpa.publisher.policy.conditions' | translate }}

+
+
+

{{condition}}

+
+
+
+
+
\ No newline at end of file diff --git a/src/app/submission/sections/sherpa-policies/content-accordion/content-accordion.component.scss b/src/app/submission/sections/sherpa-policies/content-accordion/content-accordion.component.scss new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/app/submission/sections/sherpa-policies/content-accordion/content-accordion.component.spec.ts b/src/app/submission/sections/sherpa-policies/content-accordion/content-accordion.component.spec.ts new file mode 100644 index 0000000000..b65cb5e00f --- /dev/null +++ b/src/app/submission/sections/sherpa-policies/content-accordion/content-accordion.component.spec.ts @@ -0,0 +1,57 @@ +import { NgbCollapseModule } from '@ng-bootstrap/ng-bootstrap'; +import { TranslateLoaderMock } from '../../../../shared/mocks/translate-loader.mock'; +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { ContentAccordionComponent } from './content-accordion.component'; + +import { DebugElement } from '@angular/core'; +import { By } from '@angular/platform-browser'; +import { TranslateLoader, TranslateModule } from '@ngx-translate/core'; +import { SherpaDataResponse } from '../../../../shared/mocks/section-sherpa-policies.service.mock'; + +describe('ContentAccordionComponent', () => { + let component: ContentAccordionComponent; + let fixture: ComponentFixture; + let de: DebugElement; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [ + TranslateModule.forRoot({ + loader: { + provide: TranslateLoader, + useClass: TranslateLoaderMock + } + }), + NgbCollapseModule + ], + declarations: [ContentAccordionComponent] + }) + .compileComponents(); + }); + + beforeEach(() => { + fixture = TestBed.createComponent(ContentAccordionComponent); + component = fixture.componentInstance; + de = fixture.debugElement; + component.isCollapsed = false; + component.version = SherpaDataResponse.sherpaResponse.journals[0].policies[0].permittedVersions[0]; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); + + it('should show 2 rows', () => { + component.version = SherpaDataResponse.sherpaResponse.journals[0].policies[0].permittedVersions[0]; + fixture.detectChanges(); + expect(de.queryAll(By.css('.row')).length).toEqual(2); + }); + + it('should show 5 rows', () => { + component.version = SherpaDataResponse.sherpaResponse.journals[0].policies[0].permittedVersions[2]; + fixture.detectChanges(); + expect(de.queryAll(By.css('.row')).length).toEqual(5); + }); +}); diff --git a/src/app/submission/sections/sherpa-policies/content-accordion/content-accordion.component.ts b/src/app/submission/sections/sherpa-policies/content-accordion/content-accordion.component.ts new file mode 100644 index 0000000000..0e7bc863ad --- /dev/null +++ b/src/app/submission/sections/sherpa-policies/content-accordion/content-accordion.component.ts @@ -0,0 +1,23 @@ +import { Component, Input } from '@angular/core'; + +import { PermittedVersions } from '../../../../core/submission/models/sherpa-policies-details.model'; + +/** + * This component represents a section that contains the inner accordions for the publisher policy versions. + */ +@Component({ + selector: 'ds-content-accordion', + templateUrl: './content-accordion.component.html', + styleUrls: ['./content-accordion.component.scss'] +}) +export class ContentAccordionComponent { + /** + * PermittedVersions to show information from + */ + @Input() version: PermittedVersions; + + /** + * A boolean representing if div should start collapsed + */ + public isCollapsed = true; +} diff --git a/src/app/submission/sections/sherpa-policies/metadata-information/metadata-information.component.html b/src/app/submission/sections/sherpa-policies/metadata-information/metadata-information.component.html new file mode 100644 index 0000000000..15dd4d7286 --- /dev/null +++ b/src/app/submission/sections/sherpa-policies/metadata-information/metadata-information.component.html @@ -0,0 +1,39 @@ +
+
+
+

{{ 'submission.sections.sherpa.record.information.id' | translate }}

+
+
+

{{metadata.id}} +

+
+
+
+
+

{{ 'submission.sections.sherpa.record.information.date.created' | translate }}

+
+
+

{{metadata.dateCreated | date: 'd MMMM Y H:mm:ss zzzz' }} +

+
+
+
+
+

{{ 'submission.sections.sherpa.record.information.date.modified' | translate }}

+
+
+

{{metadata.dateModified| date: 'd MMMM Y H:mm:ss zzzz' }} +

+
+
+
+
+

{{ 'submission.sections.sherpa.record.information.uri' | translate }}

+
+ +
+
\ No newline at end of file diff --git a/src/app/submission/sections/sherpa-policies/metadata-information/metadata-information.component.scss b/src/app/submission/sections/sherpa-policies/metadata-information/metadata-information.component.scss new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/app/submission/sections/sherpa-policies/metadata-information/metadata-information.component.spec.ts b/src/app/submission/sections/sherpa-policies/metadata-information/metadata-information.component.spec.ts new file mode 100644 index 0000000000..9a60a6d010 --- /dev/null +++ b/src/app/submission/sections/sherpa-policies/metadata-information/metadata-information.component.spec.ts @@ -0,0 +1,47 @@ +import { TranslateLoaderMock } from '../../../../shared/testing/translate-loader.mock'; +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { MetadataInformationComponent } from './metadata-information.component'; + +import { DebugElement } from '@angular/core'; +import { By } from '@angular/platform-browser'; +import { TranslateLoader, TranslateModule } from '@ngx-translate/core'; +import { SherpaDataResponse } from '../../../../shared/mocks/section-sherpa-policies.service.mock'; + +describe('MetadataInformationComponent', () => { + let component: MetadataInformationComponent; + let fixture: ComponentFixture; + let de: DebugElement; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [ + TranslateModule.forRoot({ + loader: { + provide: TranslateLoader, + useClass: TranslateLoaderMock + } + }), + ], + declarations: [MetadataInformationComponent] + }) + .compileComponents(); + }); + + beforeEach(() => { + fixture = TestBed.createComponent(MetadataInformationComponent); + component = fixture.componentInstance; + de = fixture.debugElement; + component.metadata = SherpaDataResponse.sherpaResponse.metadata; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); + + it('should show 4 rows', () => { + expect(de.queryAll(By.css('.row')).length).toEqual(4); + }); + +}); diff --git a/src/app/submission/sections/sherpa-policies/metadata-information/metadata-information.component.ts b/src/app/submission/sections/sherpa-policies/metadata-information/metadata-information.component.ts new file mode 100644 index 0000000000..307c18d8cc --- /dev/null +++ b/src/app/submission/sections/sherpa-policies/metadata-information/metadata-information.component.ts @@ -0,0 +1,19 @@ +import { Component, Input } from '@angular/core'; + +import { Metadata } from '../../../../core/submission/models/sherpa-policies-details.model'; + +/** + * This component represents a section that contains the matadata informations. + */ +@Component({ + selector: 'ds-metadata-information', + templateUrl: './metadata-information.component.html', + styleUrls: ['./metadata-information.component.scss'] +}) +export class MetadataInformationComponent { + /** + * Metadata to show information from + */ + @Input() metadata: Metadata; + +} diff --git a/src/app/submission/sections/sherpa-policies/publication-information/publication-information.component.html b/src/app/submission/sections/sherpa-policies/publication-information/publication-information.component.html new file mode 100644 index 0000000000..3c35da8f08 --- /dev/null +++ b/src/app/submission/sections/sherpa-policies/publication-information/publication-information.component.html @@ -0,0 +1,64 @@ +
+
+
+

{{'submission.sections.sherpa.publication.information.title' | translate}}

+
+
+

{{title}} +

+
+
+
+
+

{{'submission.sections.sherpa.publication.information.issns' | translate}}

+
+
+

{{issn}} +

+
+
+
+
+

{{'submission.sections.sherpa.publication.information.url' | translate}}

+
+ +
+
+
+

{{'submission.sections.sherpa.publication.information.publishers' | translate}}

+
+ +
+
+
+

{{'submission.sections.sherpa.publication.information.romeoPub' | translate}}

+
+
+

+ {{journal.romeoPub}} +

+
+
+
+
+

{{'submission.sections.sherpa.publication.information.zetoPub' | translate}}

+
+
+

+ {{journal.zetoPub}} +

+
+
+
\ No newline at end of file diff --git a/src/app/submission/sections/sherpa-policies/publication-information/publication-information.component.scss b/src/app/submission/sections/sherpa-policies/publication-information/publication-information.component.scss new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/app/submission/sections/sherpa-policies/publication-information/publication-information.component.spec.ts b/src/app/submission/sections/sherpa-policies/publication-information/publication-information.component.spec.ts new file mode 100644 index 0000000000..c5dc896858 --- /dev/null +++ b/src/app/submission/sections/sherpa-policies/publication-information/publication-information.component.spec.ts @@ -0,0 +1,47 @@ +import { TranslateLoaderMock } from '../../../../shared/testing/translate-loader.mock'; +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { PublicationInformationComponent } from './publication-information.component'; +import { DebugElement } from '@angular/core'; +import { By } from '@angular/platform-browser'; +import { TranslateLoader, TranslateModule } from '@ngx-translate/core'; +import { SherpaDataResponse } from '../../../../shared/mocks/section-sherpa-policies.service.mock'; + +describe('PublicationInformationComponent', () => { + let component: PublicationInformationComponent; + let fixture: ComponentFixture; + let de: DebugElement; + + + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [ + TranslateModule.forRoot({ + loader: { + provide: TranslateLoader, + useClass: TranslateLoaderMock + } + }), + ], + declarations: [PublicationInformationComponent] + }) + .compileComponents(); + }); + + beforeEach(() => { + fixture = TestBed.createComponent(PublicationInformationComponent); + component = fixture.componentInstance; + de = fixture.debugElement; + component.journal = SherpaDataResponse.sherpaResponse.journals[0]; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); + + it('should show 6 rows', () => { + expect(de.queryAll(By.css('.row')).length).toEqual(6); + }); + +}); diff --git a/src/app/submission/sections/sherpa-policies/publication-information/publication-information.component.ts b/src/app/submission/sections/sherpa-policies/publication-information/publication-information.component.ts new file mode 100644 index 0000000000..cfe42adf7b --- /dev/null +++ b/src/app/submission/sections/sherpa-policies/publication-information/publication-information.component.ts @@ -0,0 +1,19 @@ +import { Component, Input } from '@angular/core'; + +import { Journal } from '../../../../core/submission/models/sherpa-policies-details.model'; + +/** + * This component represents a section that contains the journal publication information. + */ +@Component({ + selector: 'ds-publication-information', + templateUrl: './publication-information.component.html', + styleUrls: ['./publication-information.component.scss'] +}) +export class PublicationInformationComponent { + /** + * Journal to show information from + */ + @Input() journal: Journal; + +} diff --git a/src/app/submission/sections/sherpa-policies/publisher-policy/publisher-policy.component.html b/src/app/submission/sections/sherpa-policies/publisher-policy/publisher-policy.component.html new file mode 100644 index 0000000000..87370cf7e3 --- /dev/null +++ b/src/app/submission/sections/sherpa-policies/publisher-policy/publisher-policy.component.html @@ -0,0 +1,16 @@ +
+ + +
+
+

+ {{'submission.sections.sherpa.publisher.policy.more.information' | translate}} +

+ +
+
+
\ No newline at end of file diff --git a/src/app/submission/sections/sherpa-policies/publisher-policy/publisher-policy.component.scss b/src/app/submission/sections/sherpa-policies/publisher-policy/publisher-policy.component.scss new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/app/submission/sections/sherpa-policies/publisher-policy/publisher-policy.component.spec.ts b/src/app/submission/sections/sherpa-policies/publisher-policy/publisher-policy.component.spec.ts new file mode 100644 index 0000000000..3e2c33481a --- /dev/null +++ b/src/app/submission/sections/sherpa-policies/publisher-policy/publisher-policy.component.spec.ts @@ -0,0 +1,49 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { PublisherPolicyComponent } from './publisher-policy.component'; +import { By } from '@angular/platform-browser'; +import { DebugElement } from '@angular/core'; +import { TranslateLoader, TranslateModule } from '@ngx-translate/core'; + +import { SherpaDataResponse } from '../../../../shared/mocks/section-sherpa-policies.service.mock'; +import { TranslateLoaderMock } from '../../../../shared/mocks/translate-loader.mock'; + +describe('PublisherPolicyComponent', () => { + let component: PublisherPolicyComponent; + let fixture: ComponentFixture; + let de: DebugElement; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [ + TranslateModule.forRoot({ + loader: { + provide: TranslateLoader, + useClass: TranslateLoaderMock + } + }), + ], + declarations: [PublisherPolicyComponent], + }) + .compileComponents(); + }); + + beforeEach(() => { + fixture = TestBed.createComponent(PublisherPolicyComponent); + component = fixture.componentInstance; + de = fixture.debugElement; + component.policy = SherpaDataResponse.sherpaResponse.journals[0].policies[0]; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); + + it('should show content accordion', () => { + expect(de.query(By.css('ds-content-accordion'))).toBeTruthy(); + }); + + it('should show 1 row', () => { + expect(de.queryAll(By.css('.row')).length).toEqual(1); + }); +}); diff --git a/src/app/submission/sections/sherpa-policies/publisher-policy/publisher-policy.component.ts b/src/app/submission/sections/sherpa-policies/publisher-policy/publisher-policy.component.ts new file mode 100644 index 0000000000..96ada3904c --- /dev/null +++ b/src/app/submission/sections/sherpa-policies/publisher-policy/publisher-policy.component.ts @@ -0,0 +1,28 @@ +import { Component, Input } from '@angular/core'; + +import { Policy } from '../../../../core/submission/models/sherpa-policies-details.model'; +import { AlertType } from '../../../../shared/alert/aletr-type'; + +/** + * This component represents a section that contains the publisher policy informations. + */ +@Component({ + selector: 'ds-publisher-policy', + templateUrl: './publisher-policy.component.html', + styleUrls: ['./publisher-policy.component.scss'] +}) +export class PublisherPolicyComponent { + + /** + * Policy to show information from + */ + @Input() policy: Policy; + + + /** + * The AlertType enumeration + * @type {AlertType} + */ + public AlertTypeEnum = AlertType; + +} diff --git a/src/app/submission/sections/sherpa-policies/section-sherpa-policies.component.html b/src/app/submission/sections/sherpa-policies/section-sherpa-policies.component.html new file mode 100644 index 0000000000..4b636ee46e --- /dev/null +++ b/src/app/submission/sections/sherpa-policies/section-sherpa-policies.component.html @@ -0,0 +1,72 @@ + + + +
+ + {{'submission.sections.sherpa.publisher.policy.description' | translate}} + +
+ +
+
+ + + + +
+
+ +
+ + +
+
+
+ +
+
+
+
+ +
+ + +
+
+
+ +
+
+
+ +
+
+ +
+ + +
+
+
+ +
+
+
+ + + + + +
diff --git a/src/app/submission/sections/sherpa-policies/section-sherpa-policies.component.scss b/src/app/submission/sections/sherpa-policies/section-sherpa-policies.component.scss new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/app/submission/sections/sherpa-policies/section-sherpa-policies.component.spec.ts b/src/app/submission/sections/sherpa-policies/section-sherpa-policies.component.spec.ts new file mode 100644 index 0000000000..76a980ed3c --- /dev/null +++ b/src/app/submission/sections/sherpa-policies/section-sherpa-policies.component.spec.ts @@ -0,0 +1,117 @@ +import { SharedModule } from '../../../shared/shared.module'; +import { NgbCollapseModule } from '@ng-bootstrap/ng-bootstrap'; +import { SubmissionServiceStub } from '../../../shared/testing/submission-service.stub'; +import { SherpaDataResponse } from '../../../shared/mocks/section-sherpa-policies.service.mock'; +import { ComponentFixture, inject, TestBed } from '@angular/core/testing'; + +import { SectionsService } from '../sections.service'; +import { SectionsServiceStub } from '../../../shared/testing/sections-service.stub'; +import { JsonPatchOperationsBuilder } from '../../../core/json-patch/builder/json-patch-operations-builder'; +import { TranslateLoader, TranslateModule } from '@ngx-translate/core'; +import { BrowserModule, By } from '@angular/platform-browser'; + +import { Store } from '@ngrx/store'; +import { AppState } from '../../../app.reducer'; +import { SubmissionSectionSherpaPoliciesComponent } from './section-sherpa-policies.component'; +import { SubmissionService } from '../../submission.service'; +import { DebugElement } from '@angular/core'; +import { TranslateLoaderMock } from '../../../shared/mocks/translate-loader.mock'; +import { of as observableOf } from 'rxjs'; +import { NoopAnimationsModule } from '@angular/platform-browser/animations'; + +describe('SubmissionSectionSherpaPoliciesComponent', () => { + let component: SubmissionSectionSherpaPoliciesComponent; + let fixture: ComponentFixture; + let de: DebugElement; + + const sectionsServiceStub = new SectionsServiceStub(); + + const operationsBuilder = jasmine.createSpyObj('operationsBuilder', { + add: undefined, + remove: undefined, + replace: undefined, + }); + + const storeStub = jasmine.createSpyObj('store', ['dispatch']); + + const sectionData = { + header: 'submit.progressbar.sherpaPolicies', + config: 'http://localhost:8080/server/api/config/submissionaccessoptions/SherpaPoliciesDefaultConfiguration', + mandatory: true, + sectionType: 'sherpaPolicies', + collapsed: false, + enabled: true, + data: SherpaDataResponse, + errorsToShow: [], + serverValidationErrors: [], + isLoading: false, + isValid: true + }; + + describe('SubmissionSectionSherpaPoliciesComponent', () => { + + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [ + BrowserModule, + NoopAnimationsModule, + TranslateModule.forRoot({ + loader: { + provide: TranslateLoader, + useClass: TranslateLoaderMock + } + }), + NgbCollapseModule, + SharedModule + ], + declarations: [SubmissionSectionSherpaPoliciesComponent], + providers: [ + { provide: SectionsService, useValue: sectionsServiceStub }, + { provide: JsonPatchOperationsBuilder, useValue: operationsBuilder }, + { provide: SubmissionService, useValue: SubmissionServiceStub }, + { provide: Store, useValue: storeStub }, + { provide: 'sectionDataProvider', useValue: sectionData }, + { provide: 'submissionIdProvider', useValue: '1508' }, + ] + }) + .compileComponents(); + }); + + beforeEach(inject([Store], (store: Store) => { + fixture = TestBed.createComponent(SubmissionSectionSherpaPoliciesComponent); + component = fixture.componentInstance; + de = fixture.debugElement; + sectionsServiceStub.getSectionData.and.returnValue(observableOf(SherpaDataResponse)); + fixture.detectChanges(); + })); + + + it('should create', () => { + expect(component).toBeTruthy(); + }); + + it('should show refresh button', () => { + expect(de.query(By.css('[data-test="refresh-btn"]'))).toBeTruthy(); + }); + + it('should show publisher information', () => { + expect(de.query(By.css('ds-publication-information'))).toBeTruthy(); + }); + + it('should show publisher policy', () => { + expect(de.query(By.css('ds-publisher-policy'))).toBeTruthy(); + }); + + it('should show metadata information', () => { + expect(de.query(By.css('ds-metadata-information'))).toBeTruthy(); + }); + + it('when refresh button click operationsBuilder.remove should have been called', () => { + de.query(By.css('[data-test="refresh-btn"]')).nativeElement.click(); + expect(operationsBuilder.remove).toHaveBeenCalled(); + }); + + + }); + +}); diff --git a/src/app/submission/sections/sherpa-policies/section-sherpa-policies.component.ts b/src/app/submission/sections/sherpa-policies/section-sherpa-policies.component.ts new file mode 100644 index 0000000000..e55b75146f --- /dev/null +++ b/src/app/submission/sections/sherpa-policies/section-sherpa-policies.component.ts @@ -0,0 +1,127 @@ +import { AlertType } from '../../../shared/alert/aletr-type'; +import { Component, Inject } from '@angular/core'; + +import { BehaviorSubject, Observable, of, Subscription } from 'rxjs'; + +import { JsonPatchOperationPathCombiner } from '../../../core/json-patch/builder/json-patch-operation-path-combiner'; +import { JsonPatchOperationsBuilder } from '../../../core/json-patch/builder/json-patch-operations-builder'; +import { + WorkspaceitemSectionSherpaPoliciesObject +} from '../../../core/submission/models/workspaceitem-section-sherpa-policies.model'; +import { renderSectionFor } from '../sections-decorator'; +import { SectionsType } from '../sections-type'; +import { SectionDataObject } from '../models/section-data.model'; +import { SectionsService } from '../sections.service'; +import { SectionModelComponent } from '../models/section.model'; +import { SubmissionService } from '../../submission.service'; +import { hasValue, isEmpty } from '../../../shared/empty.util'; + +/** + * This component represents a section for the sherpa policy informations structure. + */ +@Component({ + selector: 'ds-section-sherpa-policies', + templateUrl: './section-sherpa-policies.component.html', + styleUrls: ['./section-sherpa-policies.component.scss'] +}) +@renderSectionFor(SectionsType.SherpaPolicies) +export class SubmissionSectionSherpaPoliciesComponent extends SectionModelComponent { + + /** + * The accesses section data + * @type {WorkspaceitemSectionAccessesObject} + */ + public sherpaPoliciesData$: BehaviorSubject = new BehaviorSubject(null); + + /** + * The [[JsonPatchOperationPathCombiner]] object + * @type {JsonPatchOperationPathCombiner} + */ + protected pathCombiner: JsonPatchOperationPathCombiner; + + /** + * Array to track all subscriptions and unsubscribe them onDestroy + * @type {Array} + */ + protected subs: Subscription[] = []; + + /** + * A boolean representing if div should start collapsed + */ + public isCollapsed = false; + + + /** + * The AlertType enumeration + * @type {AlertType} + */ + public AlertTypeEnum = AlertType; + + /** + * Initialize instance variables + * + * @param {SectionsService} sectionService + * @param {SectionDataObject} injectedSectionData + * @param {JsonPatchOperationsBuilder} operationsBuilder + * @param {SubmissionService} submissionService + * @param {string} injectedSubmissionId + */ + constructor( + protected sectionService: SectionsService, + protected operationsBuilder: JsonPatchOperationsBuilder, + private submissionService: SubmissionService, + @Inject('sectionDataProvider') public injectedSectionData: SectionDataObject, + @Inject('submissionIdProvider') public injectedSubmissionId: string) { + super(undefined, injectedSectionData, injectedSubmissionId); + } + + /** + * Unsubscribe from all subscriptions + */ + onSectionDestroy() { + + this.subs + .filter((subscription) => hasValue(subscription)) + .forEach((subscription) => subscription.unsubscribe()); + } + + + /** + * Initialize all instance variables and retrieve collection default access conditions + */ + protected onSectionInit(): void { + this.pathCombiner = new JsonPatchOperationPathCombiner('sections', this.sectionData.id); + this.subs.push( + this.sectionService.getSectionData(this.submissionId, this.sectionData.id, this.sectionData.sectionType) + .subscribe((sherpaPolicies: WorkspaceitemSectionSherpaPoliciesObject) => { + this.sherpaPoliciesData$.next(sherpaPolicies); + }) + ); + } + + /** + * Get section status + * + * @return Observable + * the section status + */ + protected getSectionStatus(): Observable { + return of(true); + } + + /** + * Check if section has no data + */ + hasNoData(): boolean { + return isEmpty(this.sherpaPoliciesData$.value); + } + + /** + * Refresh sherpa information + */ + refresh() { + this.operationsBuilder.remove(this.pathCombiner.getPath('retrievalTime')); + this.submissionService.dispatchSaveSection(this.submissionId, this.sectionData.id); + } + +} diff --git a/src/app/submission/submission.module.ts b/src/app/submission/submission.module.ts index 05aa765054..eb6bde35ad 100644 --- a/src/app/submission/submission.module.ts +++ b/src/app/submission/submission.module.ts @@ -22,15 +22,27 @@ import { SubmissionSectionLicenseComponent } from './sections/license/section-li import { SubmissionUploadsConfigService } from '../core/config/submission-uploads-config.service'; import { SubmissionEditComponent } from './edit/submission-edit.component'; import { SubmissionSectionUploadFileComponent } from './sections/upload/file/section-upload-file.component'; -import { SubmissionSectionUploadFileEditComponent } from './sections/upload/file/edit/section-upload-file-edit.component'; -import { SubmissionSectionUploadFileViewComponent } from './sections/upload/file/view/section-upload-file-view.component'; -import { SubmissionSectionUploadAccessConditionsComponent } from './sections/upload/accessConditions/submission-section-upload-access-conditions.component'; +import { + SubmissionSectionUploadFileEditComponent +} from './sections/upload/file/edit/section-upload-file-edit.component'; +import { + SubmissionSectionUploadFileViewComponent +} from './sections/upload/file/view/section-upload-file-view.component'; +import { + SubmissionSectionUploadAccessConditionsComponent +} from './sections/upload/accessConditions/submission-section-upload-access-conditions.component'; import { SubmissionSubmitComponent } from './submit/submission-submit.component'; import { storeModuleConfig } from '../app.reducer'; import { SubmissionImportExternalComponent } from './import-external/submission-import-external.component'; -import { SubmissionImportExternalSearchbarComponent } from './import-external/import-external-searchbar/submission-import-external-searchbar.component'; -import { SubmissionImportExternalPreviewComponent } from './import-external/import-external-preview/submission-import-external-preview.component'; -import { SubmissionImportExternalCollectionComponent } from './import-external/import-external-collection/submission-import-external-collection.component'; +import { + SubmissionImportExternalSearchbarComponent +} from './import-external/import-external-searchbar/submission-import-external-searchbar.component'; +import { + SubmissionImportExternalPreviewComponent +} from './import-external/import-external-preview/submission-import-external-preview.component'; +import { + SubmissionImportExternalCollectionComponent +} from './import-external/import-external-collection/submission-import-external-collection.component'; import { SubmissionSectionCcLicensesComponent } from './sections/cc-license/submission-section-cc-licenses.component'; import { JournalEntitiesModule } from '../entity-groups/journal-entities/journal-entities.module'; import { ResearchEntitiesModule } from '../entity-groups/research-entities/research-entities.module'; @@ -38,10 +50,19 @@ import { ThemedSubmissionEditComponent } from './edit/themed-submission-edit.com import { ThemedSubmissionSubmitComponent } from './submit/themed-submission-submit.component'; import { ThemedSubmissionImportExternalComponent } from './import-external/themed-submission-import-external.component'; import { FormModule } from '../shared/form/form.module'; -import { NgbAccordionModule, NgbModalModule } from '@ng-bootstrap/ng-bootstrap'; +import { NgbCollapseModule, NgbModalModule, NgbAccordionModule } from '@ng-bootstrap/ng-bootstrap'; import { SubmissionSectionAccessesComponent } from './sections/accesses/section-accesses.component'; import { SubmissionAccessesConfigService } from '../core/config/submission-accesses-config.service'; import { SectionAccessesService } from './sections/accesses/section-accesses.service'; +import { SubmissionSectionSherpaPoliciesComponent } from './sections/sherpa-policies/section-sherpa-policies.component'; +import { ContentAccordionComponent } from './sections/sherpa-policies/content-accordion/content-accordion.component'; +import { PublisherPolicyComponent } from './sections/sherpa-policies/publisher-policy/publisher-policy.component'; +import { + PublicationInformationComponent +} from './sections/sherpa-policies/publication-information/publication-information.component'; +import { + MetadataInformationComponent +} from './sections/sherpa-policies/metadata-information/metadata-information.component'; const ENTRY_COMPONENTS = [ // put only entry components that use custom decorator @@ -50,7 +71,8 @@ const ENTRY_COMPONENTS = [ SubmissionSectionLicenseComponent, SubmissionSectionCcLicensesComponent, SubmissionSectionAccessesComponent, - SubmissionSectionUploadFileEditComponent + SubmissionSectionUploadFileEditComponent, + SubmissionSectionSherpaPoliciesComponent, ]; const DECLARATIONS = [ @@ -75,6 +97,10 @@ const DECLARATIONS = [ SubmissionImportExternalSearchbarComponent, SubmissionImportExternalPreviewComponent, SubmissionImportExternalCollectionComponent, + ContentAccordionComponent, + PublisherPolicyComponent, + PublicationInformationComponent, + MetadataInformationComponent, ]; @NgModule({ @@ -87,8 +113,9 @@ const DECLARATIONS = [ JournalEntitiesModule.withEntryComponents(), ResearchEntitiesModule.withEntryComponents(), FormModule, - NgbAccordionModule, - NgbModalModule + NgbModalModule, + NgbCollapseModule, + NgbAccordionModule ], declarations: DECLARATIONS, exports: DECLARATIONS, diff --git a/src/assets/i18n/en.json5 b/src/assets/i18n/en.json5 index b412f9cee5..1df42e32c6 100644 --- a/src/assets/i18n/en.json5 +++ b/src/assets/i18n/en.json5 @@ -4039,10 +4039,15 @@ "submission.sections.submit.progressbar.license": "Deposit license", + "submission.sections.submit.progressbar.sherpapolicy": "Sherpa policies", + "submission.sections.submit.progressbar.upload": "Upload files", + "submission.sections.submit.progressbar.sherpaPolicies": "Publisher open access policy information", + "submission.sections.sherpa-policy.title-empty": "No publisher policy information available. If your work has an associated ISSN, please enter it above to see any related publisher open access policies.", + "submission.sections.status.errors.title": "Errors", "submission.sections.status.valid.title": "Valid", @@ -4055,6 +4060,10 @@ "submission.sections.status.warnings.aria": "has warnings", + "submission.sections.status.info.title": "Additional Information", + + "submission.sections.status.info.aria": "Additional Information", + "submission.sections.toggle.open": "Open section", "submission.sections.toggle.close": "Close section", @@ -4154,6 +4163,60 @@ "submission.sections.accesses.form.until-placeholder": "Until", + "submission.sections.sherpa.publication.information": "Publication information", + + "submission.sections.sherpa.publication.information.title": "Title", + + "submission.sections.sherpa.publication.information.issns": "ISSNs", + + "submission.sections.sherpa.publication.information.url": "URL", + + "submission.sections.sherpa.publication.information.publishers": "Publisher", + + "submission.sections.sherpa.publication.information.romeoPub": "Romeo Pub", + + "submission.sections.sherpa.publication.information.zetoPub": "Zeto Pub", + + "submission.sections.sherpa.publisher.policy": "Publisher Policy", + + "submission.sections.sherpa.publisher.policy.description": "The below information was found via Sherpa Romeo. Based on the policies of your publisher, it provides advice regarding whether an embargo may be necessary and/or which files you are allowed to upload. If you have questions, please contact your site administrator via the feedback form in the footer.", + + "submission.sections.sherpa.publisher.policy.openaccess": "Open Access pathways permitted by this journal's policy are listed below by article version. Click on a pathway for a more detailed view", + + "submission.sections.sherpa.publisher.policy.more.information": "For more information, please see the following links:", + + "submission.sections.sherpa.publisher.policy.version": "Version", + + "submission.sections.sherpa.publisher.policy.embargo": "Embargo", + + "submission.sections.sherpa.publisher.policy.noembargo": "No Embargo", + + "submission.sections.sherpa.publisher.policy.nolocation": "None", + + "submission.sections.sherpa.publisher.policy.license": "License", + + "submission.sections.sherpa.publisher.policy.prerequisites": "Prerequisites", + + "submission.sections.sherpa.publisher.policy.location": "Location", + + "submission.sections.sherpa.publisher.policy.conditions": "Conditions", + + "submission.sections.sherpa.publisher.policy.refresh": "Refresh", + + "submission.sections.sherpa.record.information": "Record Information", + + "submission.sections.sherpa.record.information.id": "ID", + + "submission.sections.sherpa.record.information.date.created": "Date Created", + + "submission.sections.sherpa.record.information.date.modified": "Last Modified", + + "submission.sections.sherpa.record.information.uri": "URI", + + "submission.sections.sherpa.error.message": "There was an error retrieving sherpa informations", + + + "submission.submit.breadcrumbs": "New submission", "submission.submit.title": "New submission",