diff --git a/app/config/environment.d.ts b/app/config/environment.d.ts index a04a23a875a..51c702dcfe6 100644 --- a/app/config/environment.d.ts +++ b/app/config/environment.d.ts @@ -18,6 +18,8 @@ export interface KeenConfig { } declare const config: { + WATER_BUTLER_ENABLED: boolean; + PLAUDIT_WIDGET_URL: string, environment: any; lintOnBuild: boolean; testsEnabled: boolean; @@ -77,6 +79,7 @@ declare const config: { devMode: boolean; cookieDomain: string; authenticator: string; + metricsStartDate: string; cookies: { status: string; keenUserId: string; diff --git a/app/institutions/discover/controller.ts b/app/institutions/discover/controller.ts index ffb5706ddb4..48a4a3cd0d6 100644 --- a/app/institutions/discover/controller.ts +++ b/app/institutions/discover/controller.ts @@ -8,7 +8,7 @@ import { Filter, OnSearchParams, ResourceTypeFilterValue } from 'osf-components/ export default class InstitutionDiscoverController extends Controller { @service currentUser!: CurrentUser; - @tracked q?: string = ''; + @tracked cardSearchText?: string = ''; @tracked sort?: string = '-relevance'; @tracked resourceType: ResourceTypeFilterValue = ResourceTypeFilterValue.Projects; @tracked activeFilters?: Filter[] = []; diff --git a/app/models/contributor.ts b/app/models/contributor.ts index 4b2007fd81a..e311e9dd5c0 100644 --- a/app/models/contributor.ts +++ b/app/models/contributor.ts @@ -3,6 +3,7 @@ import { not } from '@ember/object/computed'; import { buildValidations, validator } from 'ember-cp-validations'; import DraftRegistrationModel from './draft-registration'; +import PreprintModel from './preprint'; import NodeModel from './node'; import OsfModel, { Permission } from './osf-model'; import UserModel from './user'; @@ -53,6 +54,9 @@ export default class ContributorModel extends OsfModel.extend(Validations) { @belongsTo('node', { inverse: 'contributors', polymorphic: true }) node!: AsyncBelongsTo & NodeModel; + @belongsTo('preprint', { inverse: 'contributors'}) + preprint!: AsyncBelongsTo & PreprintModel; + @belongsTo('draft-registration', { inverse: 'contributors' }) draftRegistration!: AsyncBelongsTo & DraftRegistrationModel; diff --git a/app/models/file-provider.ts b/app/models/file-provider.ts index 4b931e33303..6e786a41dc5 100644 --- a/app/models/file-provider.ts +++ b/app/models/file-provider.ts @@ -19,7 +19,7 @@ export default class FileProviderModel extends BaseFileItem { @belongsTo('base-file-item', { polymorphic: true }) rootFolder!: AsyncBelongsTo & FileModel; - @hasMany('file', { polymorphic: true }) + @hasMany('file', { inverse:'parentFolder', polymorphic: true }) files!: AsyncHasMany; @belongsTo('abstract-node', { inverse: 'files', polymorphic: true }) diff --git a/app/models/file.ts b/app/models/file.ts index 88dbeaff84d..9eceb34e00a 100644 --- a/app/models/file.ts +++ b/app/models/file.ts @@ -5,6 +5,7 @@ import { Link } from 'jsonapi-typescript'; import { FileReference } from 'ember-osf-web/packages/registration-schema'; import getHref from 'ember-osf-web/utils/get-href'; +import PreprintModel from 'ember-osf-web/models/preprint'; import AbstractNodeModel from './abstract-node'; import BaseFileItem, { BaseFileLinks } from './base-file-item'; import CommentModel from './comment'; @@ -56,8 +57,9 @@ export default class FileModel extends BaseFileItem { @hasMany('comment', { inverse: null }) comments!: AsyncHasMany; - @belongsTo('abstract-node', { polymorphic: true }) - target!: (AsyncBelongsTo & AbstractNodeModel) | (AsyncBelongsTo & DraftNode); + @belongsTo('osf-model', { polymorphic: true }) + // eslint-disable-next-line max-len + target!: (AsyncBelongsTo & AbstractNodeModel) | (AsyncBelongsTo & PreprintModel) | (AsyncBelongsTo & DraftNode); // BaseFileItem override isFileModel = true; diff --git a/app/models/preprint-provider.ts b/app/models/preprint-provider.ts index bdf21c91f48..22ab4abf0ea 100644 --- a/app/models/preprint-provider.ts +++ b/app/models/preprint-provider.ts @@ -18,6 +18,7 @@ const { defaultProvider } = config; export default class PreprintProviderModel extends ProviderModel { @service intl!: Intl; + @attr('fixstring') email_support!: string | null; @attr('array') subjectsAcceptable!: string[]; @attr('array') additionalProviders!: string[]; @attr('string') shareSource!: string; @@ -52,23 +53,29 @@ export default class PreprintProviderModel extends ProviderModel { }; } + get searchPlaceholder(): string { + return this.intl.t('preprints.header.search_placeholder', + { placeholder: this.documentType.plural}); + } + @computed('id') - get preprintWordInTitle() { - return this.id !== 'thesiscommons'; + get preprintWordNotInTitle() { + return this.id === 'thesiscommons'; } // Is either OSF Preprints if provider is the default provider, // name+preprintWord.pluralCapitalized(e.g.AfricArXiv Preprints or MarXiv Papers), or "Thesis Commons" - @computed('documentType.pluralCapitalized', 'id', 'name', 'preprintWordInTitle') + @computed('documentType.pluralCapitalized', 'id', 'name', 'preprintWordNotInTitle') get providerTitle() { if (this.id !== defaultProvider) { - if (this.preprintWordInTitle) { - return this.intl.t('preprints.provider-title', - { name: this.name, pluralizedPreprintWord: this.documentType.pluralCapitalized }); + if (this.preprintWordNotInTitle) { + return this.name; } - return this.name; + return this.intl.t('preprints.provider-title', + { name: this.name, pluralizedPreprintWord: this.documentType.pluralCapitalized }); + } else { + return this.intl.t('preprints.header.osf_preprints'); } - return this.intl.t('preprints.osf-title'); } } diff --git a/app/models/preprint-request-action.ts b/app/models/preprint-request-action.ts new file mode 100644 index 00000000000..1fa6764c759 --- /dev/null +++ b/app/models/preprint-request-action.ts @@ -0,0 +1,32 @@ +import { AsyncBelongsTo, attr, belongsTo } from '@ember-data/model'; +import PreprintRequestModel from 'ember-osf-web/models/preprint-request'; +import UserModel from 'ember-osf-web/models/user'; + +import OsfModel from './osf-model'; + + +export enum PreprintRequestActionTriggerEnum { + SUBMIT= 'submit', + ACCEPT = 'accept', + REJECT = 'reject', +} + +export default class PreprintRequestActionModel extends OsfModel { + @attr('string') comment!: string; + @attr('string') actionTrigger!: string; + @attr('date') dateModified!: Date; + @attr('boolean') auto!: boolean; + + // Relationships + @belongsTo('preprint-request', { inverse: 'actions' }) + target!: (AsyncBelongsTo & PreprintRequestModel); + + @belongsTo('user', { inverse: null, async: true }) + creator!: AsyncBelongsTo & UserModel; +} + +declare module 'ember-data/types/registries/model' { + export default interface ModelRegistry { + 'preprint-request-action': PreprintRequestActionModel; + } // eslint-disable-line semi +} diff --git a/app/models/preprint-request.ts b/app/models/preprint-request.ts new file mode 100644 index 00000000000..755a25fbbe2 --- /dev/null +++ b/app/models/preprint-request.ts @@ -0,0 +1,40 @@ +import { AsyncBelongsTo, SyncHasMany, attr, belongsTo, hasMany } from '@ember-data/model'; +import PreprintModel from 'ember-osf-web/models/preprint'; +import UserModel from 'ember-osf-web/models/user'; +import PreprintRequestActionModel from 'ember-osf-web/models/preprint-request-action'; + +import OsfModel from './osf-model'; + +export enum PreprintRequestType{ + WITHDRAWAL = 'withdrawal', +} + +export enum PreprintRequestMachineState { + PENDING = 'pending', + ACCEPTED = 'accepted', + REJECTED = 'rejected', +} + +export default class PreprintRequestModel extends OsfModel { + @attr('string') comment!: string; + @attr('date') dateLastTransitioned!: Date; + @attr('date') created!: Date; + @attr('date') modified!: Date; + @attr('string') machineState!: string; + @attr('string') requestType!: string; + + @belongsTo('preprint', { inverse: 'requests'}) + target!: (AsyncBelongsTo & PreprintModel); + + @belongsTo('user', { inverse: null, async: true }) + creator!: AsyncBelongsTo & UserModel; + + @hasMany('preprint-request-action', { inverse: 'target'}) + actions!: SyncHasMany & PreprintRequestActionModel; +} + +declare module 'ember-data/types/registries/model' { + export default interface ModelRegistry { + 'preprint-request': PreprintRequestModel; + } // eslint-disable-line semi +} diff --git a/app/models/preprint.ts b/app/models/preprint.ts index dd312e80a35..9dd77d6448f 100644 --- a/app/models/preprint.ts +++ b/app/models/preprint.ts @@ -1,29 +1,60 @@ -import { attr, belongsTo, hasMany, SyncHasMany, AsyncBelongsTo, AsyncHasMany } from '@ember-data/model'; +import { attr, belongsTo, hasMany, AsyncBelongsTo, AsyncHasMany } from '@ember-data/model'; import { computed } from '@ember/object'; import { alias } from '@ember/object/computed'; +import CitationModel from 'ember-osf-web/models/citation'; +import PreprintRequestModel from 'ember-osf-web/models/preprint-request'; +import { ReviewsState } from 'ember-osf-web/models/provider'; +import ReviewActionModel from 'ember-osf-web/models/review-action'; import ContributorModel from './contributor'; import FileModel from './file'; import LicenseModel from './license'; import NodeModel from './node'; -import OsfModel from './osf-model'; +import OsfModel, { Permission } from './osf-model'; import PreprintProviderModel from './preprint-provider'; -import ReviewActionModel from './review-action'; import SubjectModel from './subject'; +export enum PreprintDataLinksEnum { + AVAILABLE = 'available', + YES = 'yes', + NO = 'no', + NOT_APPLICABLE = 'not_applicable', +} + +export enum PreprintPreregLinksEnum { + AVAILABLE = 'available', + YES = 'yes', + NO = 'no', + NOT_APPLICABLE = 'not_applicable', +} + export default class PreprintModel extends OsfModel { @attr('fixstring') title!: string; @attr('date') dateCreated!: Date; @attr('date') datePublished!: Date; + @attr('date') dateWithdrawn!: Date; @attr('date') originalPublicationDate!: Date | null; @attr('date') dateModified!: Date; @attr('fixstring') doi!: string | null; + @attr('boolean') public!: boolean; @attr('boolean') isPublished!: boolean; @attr('boolean') isPreprintOrphan!: boolean; @attr('object') licenseRecord!: any; - @attr('string') reviewsState!: string; + @attr('string') reviewsState!: ReviewsState; + @attr('string') description!: string; @attr('date') dateLastTransitioned!: Date; @attr('date') preprintDoiCreated!: Date; + @attr('array') currentUserPermissions!: Permission[]; + @attr('fixstringarray') tags!: string[]; + @attr('fixstring') withdrawalJustification! : string; + @attr('boolean') hasCoi!: boolean; + @attr('string') hasDataLinks!: PreprintDataLinksEnum; + @attr('string') hasPreregLinks!: PreprintPreregLinksEnum; + @attr('string') conflictOfInterestStatement!: string; + @attr('array') dataLinks!: string[]; + @attr('array') preregLinks!: string[]; + @attr('string') whyNoData!: string; + @attr('string') whyNoPrereg!: string; @belongsTo('node', { inverse: 'preprints' }) node!: AsyncBelongsTo & NodeModel; @@ -37,18 +68,34 @@ export default class PreprintModel extends OsfModel { @belongsTo('preprint-provider', { inverse: 'preprints' }) provider!: AsyncBelongsTo & PreprintProviderModel; - @hasMany('review-action', { inverse: 'target' }) + @hasMany('review-action') reviewActions!: AsyncHasMany; - @hasMany('contributor') - contributors!: AsyncHasMany; + @hasMany('files', { inverse: 'target'}) + files!: AsyncHasMany & FileModel; + + @hasMany('contributors', { inverse: 'preprint'}) + contributors!: AsyncHasMany & ContributorModel; - @hasMany('subject', { inverse: null, async: false }) - subjects!: SyncHasMany; + @hasMany('contributor', { inverse: null }) + bibliographicContributors!: AsyncHasMany; + + @belongsTo('citation', { inverse: null }) + citation!: AsyncBelongsTo; + + @hasMany('subject', { inverse: null}) + subjects!: AsyncHasMany; + + @hasMany('preprint-request', { inverse: 'target'}) + requests!: AsyncHasMany; @alias('links.doi') articleDoiUrl!: string | null; @alias('links.preprint_doi') preprintDoiUrl!: string; + get isWithdrawn(): boolean{ + return this.dateWithdrawn !== null; + } + @computed('license', 'licenseRecord') get licenseText(): string { const text = this.license.get('text') || ''; diff --git a/app/models/provider.ts b/app/models/provider.ts index 2372f256b5d..c8da0d06a1c 100644 --- a/app/models/provider.ts +++ b/app/models/provider.ts @@ -20,6 +20,21 @@ export interface Assets { wide_white: string; } +export enum PreprintProviderReviewsWorkFlow{ + PRE_MODERATION = 'pre-moderation', + POST_MODERATION = 'post-moderation' +} + +export enum ReviewsState { + INITIAL = 'initial', + PENDING = 'pending', + ACCEPTED = 'accepted', + REJECTED = 'rejected', + PENDING_WITHDRAWAL = 'pendingWithdrawal', + WITHDRAWAL_REJECTED = 'withdrawalRejected', + WITHDRAWN = 'withdrawn', +} + export enum ReviewPermissions { SetUpModeration = 'set_up_moderation', ViewSubmissions = 'view_submissions', @@ -39,7 +54,6 @@ export enum ReviewPermissions { } /* eslint-enable camelcase */ - export default abstract class ProviderModel extends OsfModel { @attr('fixstring') name!: string; @attr('fixstring') description!: string; @@ -54,7 +68,7 @@ export default abstract class ProviderModel extends OsfModel { @attr('boolean') allowCommenting!: boolean; @attr('boolean') allowUpdates!: boolean; @attr('array') permissions!: ReviewPermissions[]; - @attr('fixstring') reviewsWorkflow!: string | null; + @attr('fixstring') reviewsWorkflow!: PreprintProviderReviewsWorkFlow | null; @attr('boolean') reviewsCommentsAnonymous!: boolean | null; @attr() assets?: Partial; // TODO: camelize in transform diff --git a/app/models/review-action.ts b/app/models/review-action.ts index 4abee75e8be..ec8eec25efe 100644 --- a/app/models/review-action.ts +++ b/app/models/review-action.ts @@ -2,6 +2,7 @@ import { attr, belongsTo, AsyncBelongsTo } from '@ember-data/model'; import { computed } from '@ember/object'; import { inject as service } from '@ember/service'; import Intl from 'ember-intl/services/intl'; +import PreprintModel from 'ember-osf-web/models/preprint'; import Action from './action'; import RegistrationModel, { RegistrationReviewStates } from './registration'; @@ -63,7 +64,8 @@ export default class ReviewActionModel extends Action { @attr('string') toState!: RegistrationReviewStates; @belongsTo('registration', { inverse: 'reviewActions', polymorphic: true }) - target!: AsyncBelongsTo & RegistrationModel; + target!: (AsyncBelongsTo & RegistrationModel + ) | (AsyncBelongsTo & PreprintModel); @computed('actionTrigger') get triggerPastTense(): string { diff --git a/app/models/user.ts b/app/models/user.ts index 1c7e2f945f1..2bccde9981e 100644 --- a/app/models/user.ts +++ b/app/models/user.ts @@ -53,6 +53,7 @@ const Validations = buildValidations({ }); export interface UserLinks extends OsfLinks { + html: Link; profile_image: Link; // eslint-disable-line camelcase } diff --git a/app/preprints/-components/branded-footer/styles.scss b/app/preprints/-components/branded-footer/styles.scss new file mode 100644 index 00000000000..461a9b90af6 --- /dev/null +++ b/app/preprints/-components/branded-footer/styles.scss @@ -0,0 +1,18 @@ +// stylelint-disable max-nesting-depth, selector-max-compound-selectors + +.branded-footer-links { + width: 100%; + display: flex; + flex-direction: row; + justify-content: center; + align-items: center; + margin: 10px 0; + + .social > a { + margin: 0 4px; + } + + .social > a:hover { + text-decoration: none; + } +} diff --git a/app/preprints/-components/branded-footer/template.hbs b/app/preprints/-components/branded-footer/template.hbs new file mode 100644 index 00000000000..ac74507b72c --- /dev/null +++ b/app/preprints/-components/branded-footer/template.hbs @@ -0,0 +1,5 @@ +{{#if @footerLinks}} +
+ {{html-safe @footerLinks}} +
+{{/if}} \ No newline at end of file diff --git a/app/preprints/-components/plaudit-widget/component.ts b/app/preprints/-components/plaudit-widget/component.ts new file mode 100644 index 00000000000..628cfab6468 --- /dev/null +++ b/app/preprints/-components/plaudit-widget/component.ts @@ -0,0 +1,6 @@ +import Component from '@glimmer/component'; +import config from 'ember-osf-web/config/environment'; + +export default class PlauditWidget extends Component { + plauditWidgetUrl = config.PLAUDIT_WIDGET_URL; +} diff --git a/app/preprints/-components/plaudit-widget/template.hbs b/app/preprints/-components/plaudit-widget/template.hbs new file mode 100644 index 00000000000..a2877ce8cb8 --- /dev/null +++ b/app/preprints/-components/plaudit-widget/template.hbs @@ -0,0 +1,4 @@ + \ No newline at end of file diff --git a/app/preprints/-components/preprint-abstract/styles.scss b/app/preprints/-components/preprint-abstract/styles.scss new file mode 100644 index 00000000000..0bdc85e54a1 --- /dev/null +++ b/app/preprints/-components/preprint-abstract/styles.scss @@ -0,0 +1,3 @@ +.abstract-truncated::after { + content: ' \2026'; +} diff --git a/app/preprints/-components/preprint-abstract/template.hbs b/app/preprints/-components/preprint-abstract/template.hbs new file mode 100644 index 00000000000..f4a1eb5ecdd --- /dev/null +++ b/app/preprints/-components/preprint-abstract/template.hbs @@ -0,0 +1,6 @@ +
+

{{t 'preprints.detail.abstract'}}

+ + {{@preprint.description}} + +
\ No newline at end of file diff --git a/app/preprints/-components/preprint-assertion-link/styles.scss b/app/preprints/-components/preprint-assertion-link/styles.scss new file mode 100644 index 00000000000..599de3ae056 --- /dev/null +++ b/app/preprints/-components/preprint-assertion-link/styles.scss @@ -0,0 +1,19 @@ +// stylelint-disable max-nesting-depth, selector-max-compound-selectors + +.assertions-links { + list-style: none; + margin: 0; + padding: 0; + + li { + margin-bottom: 10px; + } + + & li > a { + color: $color-text-blue-dark; + + &:hover { + color: $color-text-blue-dark; + } + } +} diff --git a/app/preprints/-components/preprint-assertion-link/template.hbs b/app/preprints/-components/preprint-assertion-link/template.hbs new file mode 100644 index 00000000000..decb70cbebd --- /dev/null +++ b/app/preprints/-components/preprint-assertion-link/template.hbs @@ -0,0 +1,14 @@ + \ No newline at end of file diff --git a/app/preprints/-components/preprint-author-assertions/component.ts b/app/preprints/-components/preprint-author-assertions/component.ts new file mode 100644 index 00000000000..66eef013c18 --- /dev/null +++ b/app/preprints/-components/preprint-author-assertions/component.ts @@ -0,0 +1,64 @@ +import Component from '@glimmer/component'; +import { inject as service } from '@ember/service'; +import Intl from 'ember-intl/services/intl'; +import PreprintModel from 'ember-osf-web/models/preprint'; +import Features from 'ember-feature-flags'; +import ProviderModel from 'ember-osf-web/models/provider'; +import { tracked } from '@glimmer/tracking'; + +interface InputArgs { + preprint: PreprintModel; + provider: ProviderModel; + documentType: string; +} + +export default class PreprintAuthorAssertions extends Component { + @service features!: Features; + @service intl!: Intl; + + @tracked displayCoi = false; + @tracked displayDataLinks = false; + @tracked displayPreregLinks = false; + + preprint = this.args.preprint; + provider = this.args.provider; + documentType = this.args.documentType; + + public get availableDataLinksMessage(): string { + const prefix = 'preprints.detail.author-assertions.available.'; + const suffix = this.preprint.hasDataLinks; + return this.intl.t(`${prefix}${suffix}`); + } + + public get availablePreregLinksMessage(): string { + const prefix = 'preprints.detail.author-assertions.available.'; + const suffix = this.preprint.hasPreregLinks; + return this.intl.t(`${prefix}${suffix}`); + + } + + public get shouldShowSloanIcons(): boolean { + return this.hasSloanData(); + } + + private hasSloanData(): boolean { + return this.hasCoi || this.hasDataLinks || this.hasPreregLinks; + } + + public get hasCoi(): boolean { + return this.preprint.hasCoi; + } + + public get hasCoiStatement(): boolean { + return typeof this.preprint.conflictOfInterestStatement === 'string'; + } + + public get hasDataLinks(): boolean { + return typeof this.preprint.hasDataLinks === 'string'; + } + + public get hasPreregLinks(): boolean { + return typeof this.preprint.hasPreregLinks === 'string'; + } +} + diff --git a/app/preprints/-components/preprint-author-assertions/styles.scss b/app/preprints/-components/preprint-author-assertions/styles.scss new file mode 100644 index 00000000000..1114790fb04 --- /dev/null +++ b/app/preprints/-components/preprint-author-assertions/styles.scss @@ -0,0 +1,50 @@ +// stylelint-disable max-nesting-depth, selector-max-compound-selectors + +.author-assertions-page-container { + padding: 10px 0; + width: 100%; + display: flex; + flex-direction: row; + justify-content: center; + align-items: center; + + .author-assertions-container { + width: calc(100% - 100px); + display: flex; + flex-direction: column; + justify-content: flex-start; + align-items: flex-start; + + .header-label { + font-size: 11px; + text-transform: uppercase; + padding-bottom: 2px; + font-weight: bold; + margin-bottom: 10px; + } + + .author-assertions { + display: flex; + flex-direction: row; + justify-content: center; + align-items: center; + margin: 0 10px; + + .assertions-container { + justify-content: center; + display: flex; + flex-direction: row; + justify-content: center; + align-items: center; + + .assertion-header-label { + font-size: 11px; + text-transform: uppercase; + padding-bottom: 2px; + font-weight: bold; + padding: 0 20px; + } + } + } + } +} diff --git a/app/preprints/-components/preprint-author-assertions/template.hbs b/app/preprints/-components/preprint-author-assertions/template.hbs new file mode 100644 index 00000000000..1f87b1e34d8 --- /dev/null +++ b/app/preprints/-components/preprint-author-assertions/template.hbs @@ -0,0 +1,142 @@ +{{#if this.shouldShowSloanIcons}} +
+
+
+ {{~t 'preprints.detail.author-assertions.header_label'~}} +
+
+ {{#if this.hasCoi}} +
+
+ {{~t 'preprints.detail.author-assertions.conflict_of_interest.title'~}} +
+ + + +

{{t 'preprints.detail.author-assertions.conflict_of_interest.title'}}

+
+ +
+ {{#if this.hasCoiStatement}} + {{~this.preprint.conflictOfInterestStatement~}} + {{else}} + {{~t 'preprints.detail.author-assertions.conflict_of_interest.no'~}} + {{/if}} +
+
+
+
+ {{/if}} + + {{#if this.hasDataLinks}} +
+
+ {{~t 'preprints.detail.author-assertions.public_data.title'~}} +
+
+ + + +

{{t 'preprints.detail.author-assertions.public_data.title'}}

+
+ +
+ {{#if (eq this.preprint.hasDataLinks 'available')}} + + {{else if (eq this.preprint.hasDataLinks 'no')}} + {{#if this.preprint.whyNoData}} + {{this.preprint.whyNoData}} + {{else}} + {{~t 'preprints.detail.author-assertions.public_data.no'~}} + {{/if}} + {{else}} + {{~t 'preprints.detail.author-assertions.public_data.not_applicable' documentType=this.documentType~}} + {{/if}} +
+
+
+
+
+ {{/if}} + + {{#if this.hasPreregLinks}} +
+
+ {{~t 'preprints.detail.author-assertions.prereg.title'~}} +
+
+ + + +

{{t 'preprints.detail.author-assertions.prereg.title'}}

+
+ +
+ {{#if (eq this.preprint.hasPreregLinks 'available')}} + + {{else if (eq this.preprint.hasPreregLinks 'no')}} + {{#if this.preprint.whyNoPrereg}} + {{this.preprint.whyNoPrereg}} + {{else}} + {{~t 'preprints.detail.author-assertions.prereg.no'~}} + {{/if}} + {{else}} + {{~t 'preprints.detail.author-assertions.prereg.not_applicable' documentType=this.documentType~}} + {{/if}} +
+
+
+
+
+ {{/if}} +
+
+
+{{/if}} \ No newline at end of file diff --git a/app/preprints/-components/preprint-discipline/component.ts b/app/preprints/-components/preprint-discipline/component.ts new file mode 100644 index 00000000000..50866809b2d --- /dev/null +++ b/app/preprints/-components/preprint-discipline/component.ts @@ -0,0 +1,15 @@ +import Component from '@glimmer/component'; +import SubjectModel from 'ember-osf-web/models/subject'; + +interface InputArgs { + subjects: SubjectModel[]; +} + +export default class PreprintDiscipline extends Component { + subjects = this.args.subjects; + + get disciplineReduced(): SubjectModel[] { + // Preprint disciplines are displayed in collapsed form on content page + return this.subjects.reduce((acc: SubjectModel[], val: SubjectModel) => acc.concat(val), []).uniqBy('id'); + } +} diff --git a/app/preprints/-components/preprint-discipline/styles.scss b/app/preprints/-components/preprint-discipline/styles.scss new file mode 100644 index 00000000000..4f580fce232 --- /dev/null +++ b/app/preprints/-components/preprint-discipline/styles.scss @@ -0,0 +1,8 @@ +.subject-preview { + display: inline-block; + background-color: $bg-light; + border-radius: 3px; + border: 1px solid $color-light; + padding: 1px 7px; + margin-bottom: 4px; +} diff --git a/app/preprints/-components/preprint-discipline/template.hbs b/app/preprints/-components/preprint-discipline/template.hbs new file mode 100644 index 00000000000..7de2e4725c9 --- /dev/null +++ b/app/preprints/-components/preprint-discipline/template.hbs @@ -0,0 +1,6 @@ +
+

{{t 'preprints.detail.disciplines'}}

+ {{#each this.disciplineReduced as |subject|}} + {{subject.text}} + {{/each}} +
\ No newline at end of file diff --git a/app/preprints/-components/preprint-doi/component.ts b/app/preprints/-components/preprint-doi/component.ts new file mode 100644 index 00000000000..6ad155176a8 --- /dev/null +++ b/app/preprints/-components/preprint-doi/component.ts @@ -0,0 +1,14 @@ +import Component from '@glimmer/component'; +import PreprintModel from 'ember-osf-web/models/preprint'; +import PreprintProviderModel from 'ember-osf-web/models/preprint-provider'; + +interface InputArgs { + preprint: PreprintModel; + provider: PreprintProviderModel; +} + +export default class PreprintAbstract extends Component { + provider = this.args.provider; + + documentType = this.provider.documentType.singular; +} diff --git a/app/preprints/-components/preprint-doi/template.hbs b/app/preprints/-components/preprint-doi/template.hbs new file mode 100644 index 00000000000..55942ff37e3 --- /dev/null +++ b/app/preprints/-components/preprint-doi/template.hbs @@ -0,0 +1,23 @@ +
+

{{t 'preprints.detail.preprint_doi' documentType=this.documentType}}

+ {{#if @preprint.preprintDoiUrl}} + {{#if @preprint.preprintDoiCreated}} + + {{@preprint.preprintDoiUrl}} + + {{else}} +

{{@preprint.preprintDoiUrl}}

+

{{t 'preprints.detail.preprint_pending_doi_minted'}}

+ {{/if}} + {{else}} + {{#if (not @preprint.public)}} + {{t 'preprints.detail.preprint_pending_doi' documentType=this.documentType}} + {{else if (and this.provider.reviewsWorkflow (not this.preprint.isPublished))}} + {{t 'preprints.detail.preprint_pending_doi_moderation'}} + {{/if}} + {{/if}} +
\ No newline at end of file diff --git a/app/preprints/-components/preprint-license/component.ts b/app/preprints/-components/preprint-license/component.ts new file mode 100644 index 00000000000..b29ae5e3e06 --- /dev/null +++ b/app/preprints/-components/preprint-license/component.ts @@ -0,0 +1,18 @@ +import { action } from '@ember/object'; +import Component from '@glimmer/component'; +import { tracked } from '@glimmer/tracking'; +import PreprintModel from 'ember-osf-web/models/preprint'; + +interface InputArgs { + preprint: PreprintModel; +} + +export default class PreprintLicense extends Component { + preprint = this.args.preprint; + @tracked showLicenseText = false; + + @action + toggleLicenseText(): void { + this.showLicenseText = !this.showLicenseText; + } +} diff --git a/app/preprints/-components/preprint-license/styles.scss b/app/preprints/-components/preprint-license/styles.scss new file mode 100644 index 00000000000..ddf500d88e3 --- /dev/null +++ b/app/preprints/-components/preprint-license/styles.scss @@ -0,0 +1,23 @@ +.license-text { + pre { + white-space: pre-wrap; + font-size: 75%; + width: 100%; + text-align: justify; + max-height: 300px; + word-break: normal; + overflow: auto; + display: block; + padding: 9.5px; + margin: 0 0 10px; + line-height: 1.42857; + word-wrap: break-word; + background-color: $bg-light; + border: 1px solid $color-shadow-gray-light; + border-radius: 4px; + } + + span { + cursor: pointer; + } +} diff --git a/app/preprints/-components/preprint-license/template.hbs b/app/preprints/-components/preprint-license/template.hbs new file mode 100644 index 00000000000..4830862ec35 --- /dev/null +++ b/app/preprints/-components/preprint-license/template.hbs @@ -0,0 +1,14 @@ +{{#if this.preprint.license.name}} +
+

{{t 'preprints.detail.license'}}

+ {{this.preprint.license.name}} + + + + {{#if this.showLicenseText}} +
{{this.preprint.licenseText}}
+ {{/if}} +
+{{/if}} \ No newline at end of file diff --git a/app/preprints/-components/preprint-status-banner/component.ts b/app/preprints/-components/preprint-status-banner/component.ts new file mode 100644 index 00000000000..70964a9c612 --- /dev/null +++ b/app/preprints/-components/preprint-status-banner/component.ts @@ -0,0 +1,210 @@ +import Component from '@glimmer/component'; +import { inject as service } from '@ember/service'; +import Theme from 'ember-osf-web/services/theme'; +import Intl from 'ember-intl/services/intl'; +import PreprintModel from 'ember-osf-web/models/preprint'; +import { task } from 'ember-concurrency'; +import { waitFor } from '@ember/test-waiters'; +import { alias } from '@ember/object/computed'; +import PreprintRequestActionModel from 'ember-osf-web/models/preprint-request-action'; +import { taskFor } from 'ember-concurrency-ts'; +import PreprintProviderModel from 'ember-osf-web/models/preprint-provider'; +import { tracked } from '@glimmer/tracking'; +import { ReviewsState } from 'ember-osf-web/models/provider'; +import ReviewActionModel from 'ember-osf-web/models/review-action'; + +const UNKNOWN = 'unknown'; +const PENDING = 'pending'; +const ACCEPTED = 'accepted'; +const REJECTED = 'rejected'; +const PENDING_WITHDRAWAL = 'pendingWithdrawal'; +const WITHDRAWAL_REJECTED = 'withdrawalRejected'; +const WITHDRAWN = 'withdrawn'; + +const PRE_MODERATION = 'pre-moderation'; +const POST_MODERATION = 'post-moderation'; + +const STATUS = Object({}); +STATUS[PENDING]= 'preprints.detail.status_banner.pending'; +STATUS[ACCEPTED]= 'preprints.detail.status_banner.accepted'; +STATUS[REJECTED]= 'preprints.detail.status_banner.rejected'; +STATUS[PENDING_WITHDRAWAL]= 'preprints.detail.status_banner.pending_withdrawal'; +STATUS[WITHDRAWAL_REJECTED]= 'preprints.detail.status_banner.withdrawal_rejected'; + +const MESSAGE = Object({}); +MESSAGE[PRE_MODERATION] = 'preprints.detail.status_banner.message.pending_pre'; +MESSAGE[POST_MODERATION] = 'preprints.detail.status_banner.message.pending_post'; +MESSAGE[ACCEPTED] = 'preprints.detail.status_banner.message.accepted'; +MESSAGE[REJECTED] = 'preprints.detail.status_banner.message.rejected'; +MESSAGE[PENDING_WITHDRAWAL] = 'preprints.detail.status_banner.message.pending_withdrawal'; +MESSAGE[WITHDRAWAL_REJECTED] = 'preprints.detail.status_banner.message.withdrawal_rejected'; +MESSAGE[WITHDRAWN] = 'preprints.detail.status_banner.message.withdrawn'; +MESSAGE[UNKNOWN] = 'preprints.detail.status_banner.message.withdrawn'; + +const WORKFLOW = Object({}); +WORKFLOW[PRE_MODERATION] = 'preprints.detail.status_banner.pre_moderation'; +WORKFLOW[POST_MODERATION] = 'preprints.detail.status_banner.post_moderation'; +WORKFLOW[UNKNOWN] = 'preprints.detail.status_banner.post_moderation'; + +const CLASS_NAMES = Object({}); +CLASS_NAMES[PRE_MODERATION] = 'preprint-status-pending-pre'; +CLASS_NAMES[POST_MODERATION] = 'preprint-status-pending-post'; +CLASS_NAMES[ACCEPTED] = 'preprint-status-accepted'; +CLASS_NAMES[REJECTED] = 'preprint-status-rejected'; +CLASS_NAMES[PENDING_WITHDRAWAL] = 'preprint-status-rejected'; +CLASS_NAMES[WITHDRAWAL_REJECTED] = 'preprint-status-rejected'; +CLASS_NAMES[WITHDRAWN] = 'preprint-status-withdrawn'; +CLASS_NAMES[UNKNOWN] = 'preprint-status-withdrawn'; + +const ICONS = Object({}); +ICONS[PENDING] = 'hourglass'; +ICONS[ACCEPTED] = 'check-circle'; +ICONS[REJECTED] = 'times-circle'; +ICONS[PENDING_WITHDRAWAL] = 'hourglass'; +ICONS[WITHDRAWAL_REJECTED] = 'times-circle'; +ICONS[WITHDRAWN] = 'exclamation-triangle'; +ICONS[UNKNOWN] = 'exclamation-triangle'; + +interface InputArgs { + submission: PreprintModel; +} + +export default class PreprintStatusBanner extends Component{ + @service intl!: Intl; + @service theme!: Theme; + + submission = this.args.submission; + isWithdrawn = this.args.submission.isWithdrawn; + + provider: PreprintProviderModel | undefined; + + @tracked displayComment = false; + isPendingWithdrawal = false; + isWithdrawalRejected = false; + + // translations + labelModeratorFeedback = 'preprints.detail.status_banner.feedback.moderator_feedback'; + moderator = 'preprints.detail.status_banner.feedback.moderator'; + baseMessage = 'preprints.detail.status_banner.message.base'; + + latestAction: PreprintRequestActionModel | ReviewActionModel | undefined; + + @alias('latestAction.comment') reviewerComment: string | undefined; + @alias('latestAction.creator.fullName') reviewerName: string | undefined; + + constructor(owner: unknown, args: InputArgs) { + super(owner, args); + + taskFor(this.loadPreprintState).perform(); + } + + public get getClassName(): string { + if (this.isPendingWithdrawal) { + return CLASS_NAMES[PENDING_WITHDRAWAL]; + } else if (this.isWithdrawn) { + return CLASS_NAMES[WITHDRAWN]; + } else if (this.isWithdrawalRejected) { + return CLASS_NAMES[WITHDRAWAL_REJECTED]; + } else { + return this.submission.reviewsState === PENDING ? + CLASS_NAMES[this.provider?.reviewsWorkflow || UNKNOWN] : + CLASS_NAMES[this.submission.reviewsState]; + } + } + + public get bannerContent(): string { + if (this.isPendingWithdrawal) { + return this.intl.t(this.statusExplanation, { documentType: this.provider?.documentType.singular }); + } else if (this.isWithdrawn) { + return this.intl.t(MESSAGE[WITHDRAWN], { documentType: this.provider?.documentType.singular }); + } else if (this.isWithdrawalRejected) { + return this.intl.t(MESSAGE[WITHDRAWAL_REJECTED], { documentType: this.provider?.documentType.singular }); + } else { + const tName = this.theme.isProvider ? + this.theme.provider?.name : + this.intl.t('preprints.detail.status_banner.brand_name'); + const tWorkflow = this.intl.t(this.workflow); + const tStatusExplanation = this.intl.t(this.statusExplanation); + const base = (this.intl.t(this.baseMessage, { + name: tName, + reviewsWorkflow: + tWorkflow, + documentType: this.provider?.documentType.singular, + })); + return `${base} ${tStatusExplanation}`; + } + } + + private get statusExplanation(): string { + if (this.isPendingWithdrawal) { + return MESSAGE[PENDING_WITHDRAWAL]; + } else if (this.isWithdrawalRejected) { + return MESSAGE[WITHDRAWAL_REJECTED]; + } else { + return this.submission.reviewsState === PENDING ? + MESSAGE[this.provider?.reviewsWorkflow || UNKNOWN ] : + MESSAGE[this.submission.reviewsState]; + } + } + + public get status(): string { + let currentState = this.submission.reviewsState; + if (this.isPendingWithdrawal) { + currentState = ReviewsState.PENDING_WITHDRAWAL; + } else if (this.isWithdrawalRejected) { + currentState = ReviewsState.WITHDRAWAL_REJECTED; + } + return STATUS[currentState]; + } + + public get icon(): string { + let currentState = this.submission.reviewsState; + if (this.isPendingWithdrawal) { + currentState = ReviewsState.PENDING_WITHDRAWAL; + } else if (this.isWithdrawalRejected) { + currentState = ReviewsState.WITHDRAWAL_REJECTED; + } else if (this.isWithdrawn) { + currentState = ReviewsState.WITHDRAWN; + } + return ICONS[currentState]; + } + + private get workflow(): string { + return WORKFLOW[this.provider?.reviewsWorkflow || UNKNOWN]; + } + + @task + @waitFor + async loadPreprintState() { + this.provider = await this.submission.provider; + + if (this.isWithdrawn) { + return; + } + const submissionActions = await this.submission.reviewActions; + const latestSubmissionAction = submissionActions.firstObject; + const withdrawalRequests = await this.submission.requests; + const withdrawalRequest = withdrawalRequests.firstObject; + if (withdrawalRequest) { + const requestActions = await withdrawalRequest.queryHasMany('actions', { + sort: '-modified', + }); + + const latestRequestAction = requestActions.firstObject; + if (latestRequestAction && latestRequestAction.actionTrigger === 'reject') { + this.isWithdrawalRejected = true; + this.latestAction = latestRequestAction; + return; + } else { + this.isPendingWithdrawal = true; + return; + } + } + + if (this.provider.reviewsCommentsPrivate) { + return; + } + + this.latestAction = latestSubmissionAction; + } +} diff --git a/app/preprints/-components/preprint-status-banner/styles.scss b/app/preprints/-components/preprint-status-banner/styles.scss new file mode 100644 index 00000000000..b073d71ed37 --- /dev/null +++ b/app/preprints/-components/preprint-status-banner/styles.scss @@ -0,0 +1,132 @@ +// stylelint-disable max-nesting-depth, selector-max-compound-selectors + +$color-alert-bg-warning: #fcf8e3; +$color-alert-border-warning: #faebcc; +$color-alert-text-warning: #8a6d3b; + +$color-alert-bg-success: #dff0d8; +$color-alert-border-success: #d6e9c6; +$color-alert-text-success: #3c763d; + +$color-alert-bg-danger: #f2dede; +$color-alert-border-danger: #ebccd1; +$color-alert-text-danger: #a94442; + +$color-alert-bg-info: #d9edf7; +$color-alert-border-info: #bce8f1; +$color-alert-text-info: #31708f; + +$color-bg-color-grey: #333; +$color-bg-color-light: #eee; +$color-border-light: #ddd; + +.preprint-status-pending-pre { + background-color: $color-alert-bg-warning; + border: 1px solid $color-alert-border-warning; + color: $color-alert-text-warning; + + .status-icon { + -webkit-text-stroke: 1px $color-alert-text-warning; + font-size: 14px; + } +} + +.preprint-status-pending-post { + background-color: $color-alert-bg-info; + border: 1px solid $color-alert-border-info; + color: $color-alert-text-info; + + .status-icon { + -webkit-text-stroke: 1px $color-alert-text-info; + font-size: 14px; + } +} + +.preprint-banner-status-container { + height: 75px; + width: 100%; + display: flex; + flex-direction: row; + align-items: center; + justify-content: center; + font-size: 16px; + + .preprint-banner-status { + height: 75px; + width: 100%; + display: flex; + flex-direction: row; + align-items: center; + justify-content: center; + font-size: 16px; + + &.preprint-status-accepted { + background-color: $color-alert-bg-success; + border: 1px solid $color-alert-border-success; + color: $color-alert-text-success; + + .status-icon { + -webkit-text-stroke: 0; + font-size: 16px; + } + } + + &.preprint-status-rejected { + background-color: $color-alert-bg-danger; + border: 1px solid $color-alert-border-danger; + color: $color-alert-text-danger; + + .status-icon { + -webkit-text-stroke: 0; + font-size: 16px; + } + } + + &.preprint-status-withdrawn { + background-color: $color-alert-bg-warning; + border: 1px solid $color-alert-border-warning; + color: $color-alert-text-warning; + + .status-icon { + -webkit-text-stroke: 1px $color-alert-text-warning; + font-size: 14px; + } + } + + .display-container { + display: flex; + flex-direction: row; + align-items: center; + justify-content: center; + padding: 10px; + + .reviewer-feedback { + margin-left: 15px; + + } + } + } +} + +.status-banner-dialog { + .status { + font-size: 1.4em; + + strong { + display: inline-block; // required for the text-transform + } + + strong::first-letter { + text-transform: uppercase; + } + } + + .moderator-comment { + font-size: 1.8em; + padding: 30px 15px; + + p { + padding-bottom: 5px; + } + } +} diff --git a/app/preprints/-components/preprint-status-banner/template.hbs b/app/preprints/-components/preprint-status-banner/template.hbs new file mode 100644 index 00000000000..6c766957af1 --- /dev/null +++ b/app/preprints/-components/preprint-status-banner/template.hbs @@ -0,0 +1,58 @@ +
+ {{#if (or this.submission.provider?.isPending this.loadPreprintState.isRunning) }} + {{ t 'preprints.detail.status_banner.loading' }} + {{else}} +
+
+ {{#if this.isWithdrawn}} +
+
+ {{else}} +
+
+ {{#if (and this.reviewerComment (not this.submission.provider.reviewsCommentsPrivate))}} +
+ + + +

{{t this.labelModeratorFeedback }}

+
+ +
+ {{t this.status}} +
+
+

{{this.reviewerComment}}

+ {{#unless this.submission.provider.reviewsCommentsAnonymous}} +
{{this.reviewerName}}
+ {{/unless}} + {{if this.theme.isProvider this.theme.provider.name (t 'preprints.detail.status_banner.brand_name')}} {{t this.moderator}} +
+
+
+
+ {{/if}} + {{/if}} +
+
+ {{/if}} +
\ No newline at end of file diff --git a/app/preprints/-components/preprint-tag/styles.scss b/app/preprints/-components/preprint-tag/styles.scss new file mode 100644 index 00000000000..c49c0eaaaa8 --- /dev/null +++ b/app/preprints/-components/preprint-tag/styles.scss @@ -0,0 +1,8 @@ +.badge { + display: inline-block; + background-color: $bg-light; + border-radius: 3px; + border: 1px solid $color-light; + padding: 1px 7px; + margin-bottom: 4px; +} diff --git a/app/preprints/-components/preprint-tag/template.hbs b/app/preprints/-components/preprint-tag/template.hbs new file mode 100644 index 00000000000..f394e021d98 --- /dev/null +++ b/app/preprints/-components/preprint-tag/template.hbs @@ -0,0 +1,10 @@ +
+

{{t 'preprints.detail.tags'}}

+ {{#if @preprint.tags.length}} + {{#each @preprint.tags as |tag|}} + {{tag}} + {{/each}} + {{else}} + {{t 'preprints.detail.none'}} + {{/if}} +
\ No newline at end of file diff --git a/app/preprints/-components/preprint-tombstone/styles.scss b/app/preprints/-components/preprint-tombstone/styles.scss new file mode 100644 index 00000000000..b0e955fa4d4 --- /dev/null +++ b/app/preprints/-components/preprint-tombstone/styles.scss @@ -0,0 +1,16 @@ +.withdrawn-container { + padding: 0 15px; + width: 100%; + display: flex; + flex-direction: column; + justify-content: flex-start; + align-items: flex-start; + + h4 { + padding-bottom: 15px; + padding-top: 15px; + margin-top: 10px; + margin-bottom: 10px; + font-weight: bold; + } +} diff --git a/app/preprints/-components/preprint-tombstone/template.hbs b/app/preprints/-components/preprint-tombstone/template.hbs new file mode 100644 index 00000000000..d29d1c4eba1 --- /dev/null +++ b/app/preprints/-components/preprint-tombstone/template.hbs @@ -0,0 +1,15 @@ +
+ {{#if @preprint.withdrawalJustification}} +
+

{{t 'preprints.detail.reason_for_withdrawal'}}

+

+ {{@preprint.withdrawalJustification}} +

+
+ {{/if}} + + + + + +
\ No newline at end of file diff --git a/app/preprints/-components/taxonomy-top-list/component.ts b/app/preprints/-components/taxonomy-top-list/component.ts new file mode 100644 index 00000000000..da20db0b30f --- /dev/null +++ b/app/preprints/-components/taxonomy-top-list/component.ts @@ -0,0 +1,92 @@ +import Component from '@glimmer/component'; +import SubjectModel from 'ember-osf-web/models/subject'; +import Media from 'ember-responsive'; +import { inject as service } from '@ember/service'; + +interface InputArgs { + list: SubjectModel[]; + provider: string; +} + +interface PairModel { + queryParam: object; + text: string; +} + +export default class TaxonomyTopList extends Component { + @service media!: Media; + + provider = this.args.provider; + + get isMobile(): boolean { + return this.media.isMobile; + } + + get sortedList() { + if (!this.args.list) { + return; + } + const sortedList = this.args.list.sortBy('text'); + const pairedList = [] as PairModel[][]; + + if (this.isMobile) { + for (let i = 0; i < sortedList.get('length'); i += 1) { + const pair: PairModel[] = []; + const subject= sortedList.objectAt(i) as SubjectModel; + pair.pushObject({ + queryParam: { + activeFilters: [{ + propertyVisibleLabel:'Subject', + propertyPathKey:'subject', + label:subject.text, + value: subject?.links?.iri, + }], + }, + text: subject?.text, + } as PairModel); + pairedList.pushObject(pair); + } + } else { + for (let i = 0; i < sortedList.get('length'); i += 2) { + const pair: PairModel[] = []; + // path in pair needs to be a list because that's what the + // subject param in the discover controller is expecting + const subjectOdd = sortedList.objectAt(i) as SubjectModel; + pair.pushObject({ + queryParam: { + activeFilters: [{ + propertyVisibleLabel:'Subject', + propertyPathKey:'subject', + label:subjectOdd.text, + value: subjectOdd?.links?.iri, + }], + }, + text: subjectOdd?.text, + } as PairModel); + + if (sortedList.objectAt(i + 1)) { + const subjectEven = sortedList.objectAt(i + 1) as SubjectModel; + pair.pushObject({ + queryParam: { + activeFilters: [{ + propertyVisibleLabel:'Subject', + propertyPathKey:'subject', + label:subjectEven.text, + value: subjectEven?.links?.iri, + }], + }, + text: subjectEven?.text, + }); + } + pairedList.pushObject(pair); + } + + } + + if (pairedList.length > 0 && typeof this.args.provider !== 'string') { + throw new Error('A provider string must be provided with a valid list'); + } + + return pairedList; + } +} diff --git a/app/preprints/-components/taxonomy-top-list/styles.scss b/app/preprints/-components/taxonomy-top-list/styles.scss new file mode 100644 index 00000000000..4991ca1c5bf --- /dev/null +++ b/app/preprints/-components/taxonomy-top-list/styles.scss @@ -0,0 +1,57 @@ +// stylelint-disable max-nesting-depth, selector-max-compound-selectors + +.subject-container { + width: 100%; + display: flex; + flex-direction: row; + justify-content: space-between; + align-items: flex-start; + margin-bottom: 10px; + + .subject-item { + width: calc(50% - 20px); + + .btn { + display: inline-block; + margin-bottom: 0; + font-weight: 400; + text-align: center; + white-space: nowrap; + touch-action: manipulation; + cursor: pointer; + background-image: none; + border: 1px solid transparent; + border-radius: 2px; + padding: 6px 12px; + font-size: 14px; + line-height: 1.42857; + user-select: none; + vertical-align: middle; + color: $color-text-white; + } + + .subject-button { + width: 100%; + font-size: 17px; + overflow: hidden; + text-overflow: ellipsis; + background-color: var(--primary-color); + color: var(--secondary-color); + border: 1px solid var(--secondary-color); + + &:hover { + color: var(--primary-color); + background-color: var(--secondary-color); + border: 1px solid var(--primary-color); + } + } + } + + &.mobile { + flex-direction: column; + + .subject-item { + width: 100%; + } + } +} diff --git a/app/preprints/-components/taxonomy-top-list/template.hbs b/app/preprints/-components/taxonomy-top-list/template.hbs new file mode 100644 index 00000000000..897d2dc9630 --- /dev/null +++ b/app/preprints/-components/taxonomy-top-list/template.hbs @@ -0,0 +1,18 @@ +{{#each this.sortedList as |pair|}} +
+ {{#each pair as |subject|}} +
+ + {{subject.text}} + +
+ {{/each}} +
+{{/each}} diff --git a/app/preprints/detail/controller.ts b/app/preprints/detail/controller.ts new file mode 100644 index 00000000000..620245f4f34 --- /dev/null +++ b/app/preprints/detail/controller.ts @@ -0,0 +1,134 @@ +import Controller from '@ember/controller'; +import { action } from '@ember/object'; +import { inject as service } from '@ember/service'; +import config from 'ember-osf-web/config/environment'; +import Theme from 'ember-osf-web/services/theme'; +import CurrentUserService from 'ember-osf-web/services/current-user'; +import Features from 'ember-feature-flags'; +import ContributorModel from 'ember-osf-web/models/contributor'; +import Intl from 'ember-intl/services/intl'; +import { Permission } from 'ember-osf-web/models/osf-model'; +import { ReviewsState, PreprintProviderReviewsWorkFlow } from 'ember-osf-web/models/provider'; +import { tracked } from '@glimmer/tracking'; +import Media from 'ember-responsive'; + + +/** + * Takes an object with query parameter name as the key and value, + * or [value, maxLength] as the values. + * + * @method queryStringify + * @param queryParams {!object} + * @param queryParams.key {!array|!string} + * @param queryParams.key[0] {!string} + * @param queryParams.key[1] {int} + * @return {string} + */ + +const DATE_LABEL = { + created: 'preprints.detail.date_label.created_on', + submitted: 'preprints.detail.date_label.submitted_on', +}; + +/** + * @module ember-preprints + * @submodule controllers + */ + +/** + * @class Content Controller + */ +export default class PrePrintsDetailController extends Controller { + @service theme!: Theme; + @service currentUser!: CurrentUserService; + @service features!: Features; + @service intl!: Intl; + @service media!: Media; + + @tracked fullScreenMFR = false; + + metricsStartDate = config.OSF.metricsStartDate; + + get hyperlink(): string { + return window.location.href; + } + + get fileDownloadUrl(): string { + const version = this.model.primaryFile.version; + const path = `${this.model.preprint.id}/download/?`; + return `${config.OSF.url}${path}${version ? `version=${version}` : ''}`.replace(/[&?]$/, ''); + } + + get facebookAppId(): string { + return this.model.provider.facebookAppId ? this.model.provider.facebookAppId : config.FB_APP_ID; + } + + get dateLabel(): string { + return this.model.provider.reviewsWorkflow === PreprintProviderReviewsWorkFlow.PRE_MODERATION ? + DATE_LABEL.submitted : + DATE_LABEL.created; + } + + get editButtonLabel(): string { + const editPreprint = 'preprints.detail.project_button.edit_preprint'; + const editResubmitPreprint = 'preprints.detail.project_button.edit_resubmit_preprint'; + const translation = this.model.provider.reviewsWorkflow === PreprintProviderReviewsWorkFlow.PRE_MODERATION + && this.model.preprint.reviewsState === ReviewsState.REJECTED && this.isAdmin() + ? editResubmitPreprint : editPreprint; + return this.intl.t(translation, { + documentType: this.model.provider.documentType.singular, + }); + } + + private isAdmin(): boolean { + // True if the current user has admin permissions for the node that contains the preprint + return (this.model.preprint.currentUserPermissions).includes(Permission.Admin); + } + + get userIsContrib(): boolean { + if (this.isAdmin()) { + return true; + } else if (this.model.contributors.length) { + const authorIds = [] as string[]; + this.model.contributors.forEach((author: ContributorModel) => { + authorIds.push(author.id); + }); + return this.currentUser.currentUserId ? authorIds.includes(this.currentUser.currentUserId) : false; + } + return false; + } + + get showStatusBanner(): boolean { + return ( + this.model.provider.reviewsWorkflow + && this.model.preprint.public + && this.userIsContrib + && this.model.preprint.reviewsState !== ReviewsState.INITIAL + && !this.model.preprint.isPreprintOrphan + ); + } + + get authors(): ContributorModel[] { + return this.model.contributors; + } + + emailHref(): string { + const titleEncoded = encodeURIComponent(this.model.title); + const hrefEncoded = encodeURIComponent(window.location.href); + return `mailto:?subject=${titleEncoded}&body=${hrefEncoded}`; + } + + @action + expandMFR() { + this.fullScreenMFR = !this.fullScreenMFR; + } + + @action + trackNonContributors(category: string, label: string, url: string): void { + this.send('click', category, label, url); + } + + get isMobile() { + return this.media.isMobile; + } +} diff --git a/app/preprints/detail/route.ts b/app/preprints/detail/route.ts new file mode 100644 index 00000000000..d137f76bee5 --- /dev/null +++ b/app/preprints/detail/route.ts @@ -0,0 +1,72 @@ +import Store from '@ember-data/store'; +import Route from '@ember/routing/route'; +import RouterService from '@ember/routing/router-service'; +import { inject as service } from '@ember/service'; +import Theme from 'ember-osf-web/services/theme'; +import captureException from 'ember-osf-web/utils/capture-exception'; + +/** + * @module ember-preprints + * @submodule routes + */ + +/** + * @class Content Route Handler + */ + + +/** + * Loads all disciplines and preprint providers to the index page + * @class Index Route Handler + */ +export default class PreprintsDetail extends Route { + @service store!: Store; + @service theme!: Theme; + @service router!: RouterService; + + async model(params: { guid : string }) { + try { + const guid = params.guid; + + const preprint = await this.store.findRecord('preprint', guid, { + adapterOptions: { + query: { + 'metrics[views]': 'total', + 'metrics[downloads]': 'total', + }, + }, + }); + + const provider = await preprint?.get('provider'); + + const primaryFile = await preprint?.get('primaryFile'); + + this.theme.set('providerType', 'preprint'); + this.theme.set('id', provider.id); + + const contributors = await preprint?.queryHasMany('contributors'); + + const license = await preprint?.get('license'); + + const node = await preprint?.get('node'); + + const subjects = await preprint?.queryHasMany('subjects'); + + return { + preprint, + brand: provider.brand.content, + contributors, + provider, + primaryFile, + license, + subjects, + node, + }; + + } catch (error) { + captureException(error); + this.router.transitionTo('not-found', 'preprints'); + return null; + } + } +} diff --git a/app/preprints/detail/styles.scss b/app/preprints/detail/styles.scss new file mode 100644 index 00000000000..1dc21d829ca --- /dev/null +++ b/app/preprints/detail/styles.scss @@ -0,0 +1,260 @@ +// stylelint-disable max-nesting-depth, selector-max-compound-selectors + +.preprints-details-page-container { + width: 100%; + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + + .btn { + display: inline-block; + margin-bottom: 0; + font-weight: 400; + text-align: center; + white-space: nowrap; + touch-action: manipulation; + cursor: pointer; + background-image: none; + border: 1px solid transparent; + border-radius: 2px; + padding: 6px 12px; + font-size: 14px; + line-height: 1.42857; + user-select: none; + vertical-align: middle; + color: $color-text-white; + } + + .btn-primary { + color: $color-text-white; + background-color: $color-bg-blue-dark; + border-color: #2e6da4; + } + + .header-container { + padding: 30px 0; + width: 100%; + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + color: $color-text-white; + background: var(--hero-background-img-url); + + .preprint-author-container, + .preprint-title-container { + width: calc(100% - 100px); + padding-top: 20px; + display: flex; + flex-direction: column; + align-items: flex-start; + justify-content: center; + + .view-authors { + color: $color-text-white; + padding-bottom: 15px; + + a { + color: #6dd1de; + } + + .detail-header-label { + font-size: 11px; + text-transform: uppercase; + padding-bottom: 2px; + } + } + } + } + + .data-container { + padding: 30px; + width: 100%; + display: flex; + flex-direction: row; + justify-content: flex-start; + align-items: flex-start; + + .withdrawn-container { + padding: 0 15px; + width: 100%; + display: flex; + flex-direction: column; + justify-content: flex-start; + align-items: flex-start; + } + + .data-container-left, + .data-container-right { + padding: 0 15px; + width: 50%; + display: flex; + flex-direction: column; + justify-content: flex-start; + align-items: flex-start; + } + + .data-container-left { + height: 1150px; + + &.expanded { + width: 100%; + } + + &.collapsed { + width: 50%; + } + + .file-description-container { + display: flex; + flex-direction: row; + justify-content: flex-start; + align-items: flex-start; + width: 100%; + padding-top: 15px; + + .file-description { + display: flex; + flex-direction: row; + justify-content: flex-start; + align-items: flex-start; + width: 75%; + } + + .toggle-button { + width: 25%; + min-width: 100px; + display: flex; + justify-content: flex-end; + align-items: flex-start; + } + } + } + + .withdrawn-container, + .data-container-right { + height: 100%; + + h4 { + padding-bottom: 15px; + padding-top: 15px; + margin-top: 10px; + margin-bottom: 10px; + font-weight: bold; + } + + .plaudit-container { + display: flex; + flex-direction: row; + justify-content: flex-start; + align-items: center; + width: 100%; + min-height: 90px; + + .plaudit { + width: calc(100% - 145px); + padding-right: 30px; + } + + .sharing-icons { + font-size: 1.5rem; + display: flex; + flex-direction: row; + justify-content: space-between; + align-items: flex-start; + width: 145px; + } + } + + .download-container { + background-color: $bg-light; + display: flex; + flex-direction: row; + justify-content: space-between; + align-items: center; + width: 100%; + padding: 10px; + } + } + } + + &.mobile { + .header-container { + padding: 0; + flex-direction: column; + + .preprint-author-container, + .preprint-title-container { + width: 100%; + padding: 0 10px; + } + } + + .data-container { + padding: 10px; + flex-direction: column; + justify-content: flex-start; + align-items: center; + + .data-container-left, + .data-container-right { + width: 100%; + padding: 0; + } + + .data-container-left { + height: 481px; + + .file-description-container { + flex-direction: column; + justify-content: flex-start; + margin-bottom: 20px; + + & > div { + margin-top: 10px; + } + + .file-description { + width: 100%; + flex-direction: column; + } + + .toggle-button { + width: 100%; + align-items: flex-end; + } + } + } + + .data-container-right { + .download-container { + flex-direction: column; + align-items: flex-start; + + & > div { + margin-top: 10px; + } + } + + .plaudit-container { + flex-direction: column; + align-items: flex-start; + + .plaudit { + width: 100%; + padding-right: 0; + height: 90px; + } + + .sharing-icons { + padding: 10px; + justify-content: space-between; + align-items: flex-start; + width: 145px; + } + } + } + } + } +} diff --git a/app/preprints/detail/template.hbs b/app/preprints/detail/template.hbs new file mode 100644 index 00000000000..043a1b35323 --- /dev/null +++ b/app/preprints/detail/template.hbs @@ -0,0 +1,199 @@ +{{page-title this.model.preprint.title replace=false}} + + +
+
+
+

{{this.model.preprint.title}}

+ {{#unless this.model.preprint.isWithdrawn}} +
+ {{#if (and this.userIsContrib (not this.isPendingWithdrawal))}} + + {{this.editButtonLabel}} + + + {{/if}} +
+
+ {{/unless}} +
+
+
+
+ {{t 'preprints.detail.header.authors_label'}} +
+ +
+
+ +
+ {{#if (or this.showStatusBanner this.isWithdrawn)}} + + {{/if}} +
+ {{#if this.model.preprint.isWithdrawn}} + + {{else}} +
+ {{#if this.model.preprint.isPreprintOrphan}} + + {{t 'preprints.detail.orphan_preprint'}} + + {{else}} + {{#if this.model.preprint.public}} + +
+
+
{{t this.dateLabel}}: {{moment-format this.model.dateCreated 'MMMM DD, YYYY'}}
+ {{#unless this.isMobile}} +
|
+ {{/unless}} + {{#if this.isWithdrawn}} +
{{t 'preprints.detail.header.withdrawn_on'}}: {{moment-format this.model.preprint.dateWithdrawn 'MMMM DD, YYYY'}}
+ {{else}} +
{{t 'preprints.detail.header.last_edited'}}: {{moment-format this.model.preprint.dateModified 'MMMM DD, YYYY'}}
+ {{/if}} +
+ {{#unless this.isMobile}} +
+ +
+ {{/unless}} +
+ {{else}} + + {{t 'preprints.detail.private_preprint_warning' documentType=this.model.provider.documentType.singular supportEmail='support@osf.io'}} + + {{/if}} + {{/if}} +
+ {{#unless this.fullScreenMFR }} +
+
+
+ + {{t 'preprints.detail.share.download' documentType=this.model.provider.documentType.singular}} + +
+
+ {{t 'preprints.detail.share.views'}}: {{this.model.preprint.apiMeta.metrics.views}} | {{t 'preprints.detail.share.downloads'}}: {{this.model.preprint.apiMeta.metrics.downloads}} + + {{t 'preprints.detail.share.metrics_disclaimer'}} {{moment-format this.metricsStartDate 'YYYY-MM-DD'}} + +
+
+
+
+ +
+ +
+ {{links.email}} +
+
+ {{links.twitter}} +
+
+ {{links.facebook}} +
+
+ {{links.linkedIn}} +
+
+
+ + {{#if this.model.node}} +
+

{{t 'preprints.detail.supplemental_materials'}}

+ + {{this.model.node.links.html}} + + +
+ {{/if}} + + {{#if this.model.preprint.articleDoiUrl}} +
+

{{t 'preprints.detail.article_doi'}}

+ + {{this.model.preprint.articleDoiUrl}} + +
+ {{/if}} + + + + {{#if this.model.preprint.originalPublicationDate}} +
+

{{t 'preprints.detail.original_publication_date'}}

+

+ {{moment-format this.model.preprint.originalPublicationDate 'YYYY-MM-DD'}} +

+
+ {{/if}} +
+

{{t 'preprints.detail.citations'}}

+ +
+
+ {{/unless}} + {{/if}} +
+
diff --git a/app/preprints/index/controller.ts b/app/preprints/index/controller.ts new file mode 100644 index 00000000000..8f6b536033a --- /dev/null +++ b/app/preprints/index/controller.ts @@ -0,0 +1,42 @@ +import Store from '@ember-data/store'; +import Controller from '@ember/controller'; +import { action } from '@ember/object'; +import RouterService from '@ember/routing/router-service'; +import { inject as service } from '@ember/service'; +import Theme from 'ember-osf-web/services/theme'; +import Media from 'ember-responsive'; +import Intl from 'ember-intl/services/intl'; + +export default class Preprints extends Controller { + @service store!: Store; + @service theme!: Theme; + @service router!: RouterService; + @service media!: Media; + @service intl!: Intl; + + get isMobile(): boolean { + return this.media.isMobile; + } + + get isOsf(): boolean { + return this.theme?.provider?.id === 'osf'; + } + + @action + onSearch(query: string) { + let route = 'search'; + + if (this.theme.isSubRoute) { + route = 'provider.discover'; + } + + this.router.transitionTo(route, { queryParams: { q: query } }); + } + + get supportEmail(): string { + const { isProvider, provider } = this.theme; + + // eslint-disable-next-line max-len + return `mailto:${isProvider && provider && provider.emailSupport ? provider.emailSupport : this.intl.t('contact.email')}`; + } +} diff --git a/app/preprints/index/route.ts b/app/preprints/index/route.ts new file mode 100644 index 00000000000..5d3b73376eb --- /dev/null +++ b/app/preprints/index/route.ts @@ -0,0 +1,53 @@ +import Store from '@ember-data/store'; +import Route from '@ember/routing/route'; +import RouterService from '@ember/routing/router-service'; +import { inject as service } from '@ember/service'; +import Theme from 'ember-osf-web/services/theme'; +import captureException from 'ember-osf-web/utils/capture-exception'; + +/** + * Loads all disciplines and preprint providers to the index page + * @class Index Route Handler + */ +export default class Preprints extends Route { + @service store!: Store; + @service theme!: Theme; + @service router!: RouterService; + + async model(params: { provider_id : string }) { + try { + const provider_id = params.provider_id ? params.provider_id : 'osf'; + + const provider = await this.store.findRecord('preprint-provider', provider_id, { + include: 'brand', + }); + this.theme.set('providerType', 'preprint'); + this.theme.set('id', provider_id); + + const taxonomies = await this.theme.provider?.queryHasMany('highlightedSubjects', { + page: { + size: 20, + }, + }); + + let brandedProviders = []; + + if (this.theme.id === 'osf') { + const allProviders = await this.store.findAll('preprint-provider', { reload: true }); + brandedProviders = allProviders.filter(item => item.id !== 'osf'); + } + + return { + provider, + taxonomies, + brandedProviders, + brand: provider.brand.content, + }; + + } catch (error) { + captureException(error); + this.router.transitionTo('not-found', 'preprints'); + return null; + } + } +} diff --git a/app/preprints/index/styles.scss b/app/preprints/index/styles.scss new file mode 100644 index 00000000000..e90e5bd0d33 --- /dev/null +++ b/app/preprints/index/styles.scss @@ -0,0 +1,213 @@ +// stylelint-disable max-nesting-depth, selector-max-compound-selectors + +.preprints-page-container { + width: 100%; + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + + .preprint-header { + border-bottom: 1px solid var(--primary-color); + width: 100%; + background-color: var(--secondary-color); + color: var(--primary-color) !important; + + a:not(.btn) { + color: var(--primary-color); + text-decoration: underline; + } + + .description { + color: var(--primary-color); + } + + .submit-container { + width: 100%; + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + color: var(--primary-color); + + .or-container { + font-size: 21px; + margin-bottom: 20px; + font-weight: 300; + line-height: 1.4; + color: $color-text-white; + + width: 100%; + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + } + + .example-container { + display: flex; + justify-content: center; + align-items: center; + width: 100%; + margin-top: 25px; + } + } + } + + /* Subject Panel */ + .preprint-subjects-container { + background-color: $color-bg-gray-lighter; + border-bottom: 1px solid #6d8a98; + padding: 15px 0; + width: 100%; + flex-direction: column; + display: flex; + justify-content: center; + align-items: center; + + .preprint-subjects-inner-container { + background-color: $color-bg-gray-lighter; + padding: 0 30px; + width: calc(100% - 60px); + flex-direction: column; + display: flex; + justify-content: flex-start; + align-items: flex-start; + + .subject-list-container { + padding: 25px; + width: 100%; + flex-direction: column; + display: flex; + justify-content: flex-start; + align-items: flex-start; + } + } + } + + /* Preprint providers and become provider */ + .preprint-tool-container { + background: var(--hero-background-img-url); + color: $color-text-white; + text-shadow: 0 0 5px #506069; + background-size: cover; + padding: 15px 0; + min-width: 100%; + min-height: 100%; + width: 100%; + flex-direction: column; + display: flex; + justify-content: center; + align-items: center; + + .preprint-tool-inner-container { + padding-right: 30px; + padding-left: 30px; + width: calc(100% - 60px); + flex-direction: column; + display: flex; + justify-content: flex-start; + align-items: flex-start; + + .subtitle { + margin-bottom: 25px; + } + + .preprint-contact-container, + .preprint-logos-container { + padding: 25px; + width: 100%; + flex-direction: row; + flex-wrap: wrap; + display: flex; + justify-content: center; + align-items: flex-start; + + .provider-logo { + width: 150px; + height: 75px; + background-size: contain; + background-repeat: no-repeat; + background-position: center; + margin: 15px; + } + } + + .preprint-contact-container { + flex-direction: column; + align-items: center; + + .lead { + font-size: 21px; + line-height: 1.4; + font-weight: 300; + padding-bottom: 10px; + text-align: center; + + .links { + color: $color-text-white; + text-decoration: underline; + } + } + + .contact { + margin-top: 20px; + } + } + } + } + + .osf-preprint-advisory-container { + background-image: none; + } + + &.mobile { + .preprint-subjects-inner-container { + padding: 0; + background-color: $color-bg-gray-lighter; + padding: 0, 10px; + width: calc(100% - 20px); + + .subject-list-container { + padding: 25px 0; + width: 100%; + flex-direction: column; + } + } + + .preprint-tool-inner-container { + padding: 15px 10px; + width: calc(100% - 20px); + } + } + + .btn { + display: inline-block; + margin-bottom: 0; + font-weight: 400; + text-align: center; + white-space: nowrap; + touch-action: manipulation; + cursor: pointer; + background-image: none; + border: 1px solid transparent; + border-radius: 2px; + padding: 6px 12px; + font-size: 14px; + line-height: 1.42857; + user-select: none; + vertical-align: middle; + color: $color-text-white; + } + + .btn-success { + background-color: #357935; + border-color: #2d672d; + } + + .btn-lg { + padding: 10px 16px; + font-size: 18px; + line-height: 1.33333; + } +} diff --git a/app/preprints/index/template.hbs b/app/preprints/index/template.hbs new file mode 100644 index 00000000000..63e8a69b1dc --- /dev/null +++ b/app/preprints/index/template.hbs @@ -0,0 +1,167 @@ +
+ {{!HEADER}} +
+ + {{#branded-header.lead}} +
+ {{html-safe this.theme.provider.description}} +
+
+ + {{t 'preprints.header.powered_by'}} + +
+ {{/branded-header.lead}} + {{#branded-header.row}} + {{#if this.theme.provider.allowSubmissions}} +
+
{{t 'preprints.header.or'}}
+ + {{t 'preprints.header.submit_label' documentType=this.theme.provider.content.documentType}} + +
+ + {{t 'preprints.header.example'}} + +
+
+ {{/if}} + {{/branded-header.row}} +
+
+ {{!END HEADER}} + + {{!SUBJECTS}} +
+
+

{{#if this.theme.provider.additionalProviders}} + {{t 'preprints.subjects.heading.provider'}} + {{else}} + {{if this.theme.provider.hasHighlightedSubjects (t 'preprints.subjects.heading.hasHighlightedSubjects') (t 'preprints.subjects.heading.noHighlightedSubjects')}} + {{/if}} +

+ {{#if this.theme.provider.hasHighlightedSubjects}} + + {{t 'preprints.subjects.links.seeAllSubjects'}} + + {{/if}} +
+ {{#if this.theme.provider.additionalProviders}} + {{additional-provider-list additionalProviders=this.theme.provider.additionalProviders}} + {{else}} + + {{/if}} +
+
+
+ + {{#unless this.theme.isProvider}} + {{!SERVICES}} +
+
+

{{t 'preprints.services.top.heading' documentType=this.theme.provider.documentType.singularCapitalized}}

+

+ {{t 'preprints.services.top.paragraph' documentType=this.theme.provider.documentType.singular}} +

+
+ {{#each this.model.brandedProviders as |provider| }} + {{#if (not-eq provider.id 'livedata') }} + + {{/if}} + {{/each}} +
+
+
+ {{t 'preprints.services.bottom.p1' documentType=this.theme.provider.documentType.singular}} +
+
+ {{t 'preprints.services.bottom.div.line1'}} + + + {{t 'preprints.services.bottom.div.linkText1'}} + + + {{t 'preprints.services.bottom.div.line2'}} + + + {{t 'preprints.services.bottom.div.linkText2'}} + + + {{t 'preprints.services.bottom.div.line3'}} +
+
+ + {{t 'preprints.services.bottom.contact'}} + +
+
+
+
+ {{/unless}} + + + {{!ADVISORY GROUP}} + {{#if this.theme.provider.advisoryBoard.length}} +
+
+ {{html-safe this.theme.provider.advisoryBoard}} +
+
+ {{/if}} +
+{{!END INDEX}} diff --git a/app/preprints/template.hbs b/app/preprints/template.hbs index 21847e39d8d..f83103440ff 100644 --- a/app/preprints/template.hbs +++ b/app/preprints/template.hbs @@ -1,9 +1,16 @@ {{page-title this.theme.provider.providerTitle replace=true}} -
- - {{outlet}} -
+{{#if this.theme.isProvider}} +
+ + +
+{{/if}} +{{outlet}} + +
+ +
\ No newline at end of file diff --git a/app/resolve-guid/route.ts b/app/resolve-guid/route.ts index 111dbaef86f..8d6571eb323 100644 --- a/app/resolve-guid/route.ts +++ b/app/resolve-guid/route.ts @@ -36,7 +36,7 @@ export default class ResolveGuid extends Route { return { file: 'guid-file', node: 'guid-node', - preprint: 'guid-preprint', + preprint: 'preprints.detail', registration: this.features.isEnabled(routes['registries.overview']) ? 'registries.overview' : 'guid-registration', @@ -75,7 +75,14 @@ export default class ResolveGuid extends Route { throw new Error(`Unknown GUID referentType: ${guid.referentType}`); } - expanded = this.generateURL(this.routeMap[guid.referentType], params.guid); + if (guid.referentType === 'preprint') { + const preprint = await this.store.findRecord('preprint', params.guid); + const providerId = preprint.belongsTo('provider').id(); + expanded = this.generateURL(this.routeMap['preprint'], providerId, params.guid); + } else { + expanded = this.generateURL(this.routeMap[guid.referentType], params.guid); + } + } let url = expanded; diff --git a/app/router.ts b/app/router.ts index e69ef624be8..bed912efd32 100644 --- a/app/router.ts +++ b/app/router.ts @@ -25,10 +25,15 @@ Router.map(function() { this.route('discover', { path: '/:institution_id' }); this.route('dashboard', { path: '/:institution_id/dashboard' }); }); + this.route('preprints', function() { - this.route('discover'); + this.route('index', { path: '/' }); + this.route('index', { path: '/:provider_id' }); this.route('discover', { path: '/:provider_id/discover' }); + this.route('detail', { path: '/:provider_id/:guid' }); }); + + this.route('register'); this.route('settings', function() { this.route('profile', function() { @@ -74,7 +79,6 @@ Router.map(function() { }); }); - this.route('guid-preprint', { path: '--preprint/:guid' }); this.route('guid-registration', { path: '--registration/:guid' }, function() { this.mount('analytics-page', { as: 'analytics' }); diff --git a/app/search/controller.ts b/app/search/controller.ts index e8ed982aa50..5aca419d97b 100644 --- a/app/search/controller.ts +++ b/app/search/controller.ts @@ -4,7 +4,7 @@ import { tracked } from '@glimmer/tracking'; import { Filter, OnSearchParams, ResourceTypeFilterValue } from 'osf-components/components/search-page/component'; export default class SearchController extends Controller { - @tracked q?: string = ''; + @tracked cardSearchText?: string = ''; @tracked sort?: string = '-relevance'; @tracked resourceType?: ResourceTypeFilterValue | null = null; @tracked activeFilters?: Filter[] = []; diff --git a/app/serializers/preprint-request-action.ts b/app/serializers/preprint-request-action.ts new file mode 100644 index 00000000000..2b9d3a4fd52 --- /dev/null +++ b/app/serializers/preprint-request-action.ts @@ -0,0 +1,14 @@ +import OsfSerializer from './osf-serializer'; + +export default class PreprintRequestActionSerializer extends OsfSerializer { + attrs: any = { + ...this.attrs, // from OsfSerializer + actionTrigger: 'trigger', + }; +} + +declare module 'ember-data/types/registries/serializer' { + export default interface SerializerRegistry { + 'preprint-request-action': PreprintRequestActionSerializer; + } // eslint-disable-line semi +} diff --git a/app/serializers/preprint-request.ts b/app/serializers/preprint-request.ts new file mode 100644 index 00000000000..18319f8c50a --- /dev/null +++ b/app/serializers/preprint-request.ts @@ -0,0 +1,10 @@ +import OsfSerializer from './osf-serializer'; + +export default class PreprintRequestSerializer extends OsfSerializer { +} + +declare module 'ember-data/types/registries/serializer' { + export default interface SerializerRegistry { + 'preprint-request': PreprintRequestSerializer; + } // eslint-disable-line semi +} diff --git a/app/styles/_preprint.scss b/app/styles/_preprint.scss new file mode 100644 index 00000000000..bb1767500fc --- /dev/null +++ b/app/styles/_preprint.scss @@ -0,0 +1,67 @@ +// stylelint-disable max-nesting-depth, selector-max-compound-selectors + +.preprint-advisory-container { + background: var(--hero-background-img-url); + background-color: $color-bg-gray-lighter; + border-bottom: 1px solid #6d8a98; + padding: 15px 0; + width: 100%; + flex-direction: column; + display: flex; + justify-content: center; + align-items: center; + + .preprint-advisory-inner-container { + padding: 0 30px; + width: calc(100% - 60px); + flex-direction: column; + display: flex; + justify-content: flex-start; + align-items: flex-start; + + .preprint-advisory-header { + width: 100%; + } + + .preprint-advisory-list { + width: 100%; + flex-direction: row; + display: flex; + justify-content: flex-start; + align-items: flex-start; + margin-top: 25px; + + .preprint-advisory-list-column { + width: 50%; + + ul { + list-style: none; + + li { + padding-top: 5px; + font-size: 16px; + } + } + } + } + } + + &.mobile { + .preprint-advisory-inner-container { + padding: 0 10px; + width: calc(100% - 20px); + + .preprint-advisory-list { + flex-direction: column; + + .preprint-advisory-list-column { + width: 100%; + + ul { + padding: 0; + } + } + } + } + } +} diff --git a/app/styles/headers.scss b/app/styles/headers.scss index ce654bede9b..5663ca4d799 100644 --- a/app/styles/headers.scss +++ b/app/styles/headers.scss @@ -19,6 +19,9 @@ // Branding @import 'branding'; +// Preprints +@import 'preprint'; + .theme-dropdown .dropdown-menu { position: static; display: block; diff --git a/config/environment.js b/config/environment.js index e802090a825..c10b1dd4a89 100644 --- a/config/environment.js +++ b/config/environment.js @@ -28,6 +28,7 @@ const { GOOGLE_TAG_MANAGER_ID, KEEN_CONFIG: keenConfig, LINT_ON_BUILD: lintOnBuild = false, + WATER_BUTLER_ENABLED = true, MIRAGE_ENABLED = false, MIRAGE_SCENARIOS = [ 'loggedIn', @@ -48,6 +49,8 @@ const { OSF_FILE_URL: waterbutlerUrl = 'http://localhost:7777/', OSF_HELP_URL: helpUrl = 'http://localhost:4200/help', OSF_AUTHENTICATOR: osfAuthenticator = 'osf-cookie', + PLAUDIT_WIDGET_URL: plauditWidgetUrl = 'https://osf-review.plaudit.pub/embed/endorsements.js', + METRICS_START_DATE: metricsStartDate = '2019-01-01', POLICY_URL_PREFIX = 'https://github.com/CenterForOpenScience/centerforopenscience.org/blob/master/', POPULAR_LINKS_NODE: popularNode = '57tnq', // POPULAR_LINKS_REGISTRATIONS = '', @@ -69,6 +72,8 @@ module.exports = function(environment) { const ENV = { modulePrefix: 'ember-osf-web', + WATER_BUTLER_ENABLED, + plauditWidgetUrl, environment, lintOnBuild, testsEnabled: false, // Disable tests by default. @@ -151,6 +156,7 @@ module.exports = function(environment) { shareApiUrl, shareSearchUrl, devMode, + metricsStartDate, cookieDomain, authenticator: `authenticator:${osfAuthenticator}`, cookies: { diff --git a/lib/app-components/addon/components/branded-navbar/template.hbs b/lib/app-components/addon/components/branded-navbar/template.hbs index e6b1a93f2a5..5407d118517 100644 --- a/lib/app-components/addon/components/branded-navbar/template.hbs +++ b/lib/app-components/addon/components/branded-navbar/template.hbs @@ -11,6 +11,7 @@