From e48ceea61ea32d1f16feaf4b2399f57ed1b823c4 Mon Sep 17 00:00:00 2001 From: Will Byrne Date: Fri, 1 Nov 2024 15:07:50 +0000 Subject: [PATCH 1/8] make evaluationSummary optional for multi tenancy and add story [elifesciences/enhanced-preprints-issues#1184] --- .../pages/article/article-page.stories.tsx | 24 +++++++++++++++++++ .../pages/article/tabs/fulltext-tab.tsx | 2 +- src/types/peer-review.ts | 2 +- 3 files changed, 26 insertions(+), 2 deletions(-) diff --git a/src/components/pages/article/article-page.stories.tsx b/src/components/pages/article/article-page.stories.tsx index 621bc52ee..b52634288 100644 --- a/src/components/pages/article/article-page.stories.tsx +++ b/src/components/pages/article/article-page.stories.tsx @@ -74,6 +74,30 @@ export const ArticlePageFullTextTab: Story = { ), }; +export const ArticlePageFullTextTabNoSummary: Story = { + args: { + metaData, + status, + activeTab: 'fulltext', + tabs, + relatedContent, + metrics, + previousVersionWarningUrl: '#', + timeline, + }, + render: (args) => { + const { reviews, authorResponse } = peerReview; + + return ( + + + + + + ); + }, +}; + export const ArticlePageFiguresTab: Story = { args: { metaData, diff --git a/src/components/pages/article/tabs/fulltext-tab.tsx b/src/components/pages/article/tabs/fulltext-tab.tsx index 49a5f93d5..93be5c1d2 100644 --- a/src/components/pages/article/tabs/fulltext-tab.tsx +++ b/src/components/pages/article/tabs/fulltext-tab.tsx @@ -33,7 +33,7 @@ export const ArticleFullTextTab = (props: Props) => { return ( <> - { props.peerReview && } + { (props.peerReview && props.peerReview.evaluationSummary) && }
diff --git a/src/types/peer-review.ts b/src/types/peer-review.ts index 7734221c8..b57c25087 100644 --- a/src/types/peer-review.ts +++ b/src/types/peer-review.ts @@ -19,7 +19,7 @@ type Evaluation = { }; export type PeerReview = { - evaluationSummary: Evaluation, + evaluationSummary?: Evaluation, reviews: Evaluation[], authorResponse?: Evaluation, }; From 71feab49eba99f67a9855487399757d3864a3339 Mon Sep 17 00:00:00 2001 From: Will Byrne Date: Fri, 1 Nov 2024 15:21:54 +0000 Subject: [PATCH 2/8] fix compilation issue with optional evaluationSummary and add story for no summary reviews tab [elifesciences/enhanced-preprints-issues#1184] --- .../pages/article/article-page.stories.tsx | 23 +++++++++++++++++++ .../pages/article/tabs/reviews-tab.tsx | 2 +- 2 files changed, 24 insertions(+), 1 deletion(-) diff --git a/src/components/pages/article/article-page.stories.tsx b/src/components/pages/article/article-page.stories.tsx index b52634288..820b488ff 100644 --- a/src/components/pages/article/article-page.stories.tsx +++ b/src/components/pages/article/article-page.stories.tsx @@ -158,6 +158,29 @@ export const ArticlePageRevisedReviewsTab: Story = { ), }; +export const ArticlePageRevisedReviewsTabNoSummary: Story = { + args: { + metaData, + status, + activeTab: 'reviews', + tabs, + relatedContent, + metrics, + timeline, + }, + render: (args) => { + const { reviews, authorResponse } = peerReview; + + return ( + + + + + + ); + }, +}; + export const ArticlePageErrorTab: Story = { args: { metaData, diff --git a/src/components/pages/article/tabs/reviews-tab.tsx b/src/components/pages/article/tabs/reviews-tab.tsx index 1b163a70a..41cf9d58c 100644 --- a/src/components/pages/article/tabs/reviews-tab.tsx +++ b/src/components/pages/article/tabs/reviews-tab.tsx @@ -20,7 +20,7 @@ export const ArticleReviewsTab = ({ peerReview, currentVersion }: { peerReview:
- + { peerReview.evaluationSummary && } {peerReview.reviews.map((review, index) => ( ))} From d00941dc12f55a748fcbc3d1e814dc92d5eb5a7e Mon Sep 17 00:00:00 2001 From: Will Byrne Date: Fri, 1 Nov 2024 15:26:44 +0000 Subject: [PATCH 3/8] lint fix [elifesciences/enhanced-preprints-issues#1184] --- src/components/pages/article/article-page.stories.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/pages/article/article-page.stories.tsx b/src/components/pages/article/article-page.stories.tsx index 820b488ff..98705311b 100644 --- a/src/components/pages/article/article-page.stories.tsx +++ b/src/components/pages/article/article-page.stories.tsx @@ -169,12 +169,12 @@ export const ArticlePageRevisedReviewsTabNoSummary: Story = { timeline, }, render: (args) => { - const { reviews, authorResponse } = peerReview; + const { reviews, authorResponse } = peerReview; return ( - + ); From b2bb246598d75139b7ed15f77fca8cf21365d5c5 Mon Sep 17 00:00:00 2001 From: Scott Aubrey Date: Thu, 7 Nov 2024 09:12:06 +0000 Subject: [PATCH 4/8] Remove article status (#2203) --- .../pages/article/article-page.stories.tsx | 9 +- .../pages/article/article-page.test.tsx | 24 +-- src/components/pages/article/article-page.tsx | 7 - .../reviewed-preprints/[...path].page.tsx | 23 +-- src/types/article-status.ts | 5 - src/types/index.ts | 1 - .../generate-article-status.test.ts | 140 ------------------ .../generators/generate-article-status.ts | 21 --- src/utils/generators/index.ts | 1 - src/utils/mocks/index.ts | 1 - src/utils/mocks/status.ts | 9 -- 11 files changed, 17 insertions(+), 224 deletions(-) delete mode 100644 src/types/article-status.ts delete mode 100644 src/utils/generators/generate-article-status.test.ts delete mode 100644 src/utils/generators/generate-article-status.ts delete mode 100644 src/utils/mocks/status.ts diff --git a/src/components/pages/article/article-page.stories.tsx b/src/components/pages/article/article-page.stories.tsx index 98705311b..2dd100740 100644 --- a/src/components/pages/article/article-page.stories.tsx +++ b/src/components/pages/article/article-page.stories.tsx @@ -1,7 +1,7 @@ import LinkTo from '@storybook/addon-links/react'; import { Meta, StoryObj } from '@storybook/react'; import { - content, metaData, metrics, peerReview, relatedContent, status, timeline, + content, metaData, metrics, peerReview, relatedContent, timeline, } from '../../../utils/mocks'; import { ArticlePage } from './article-page'; import { ArticleFullTextTab, ArticleFiguresTab, ArticleReviewsTab } from './tabs'; @@ -57,7 +57,6 @@ const headings = contentToHeadings(content); export const ArticlePageFullTextTab: Story = { args: { metaData, - status, activeTab: 'fulltext', tabs, relatedContent, @@ -77,7 +76,6 @@ export const ArticlePageFullTextTab: Story = { export const ArticlePageFullTextTabNoSummary: Story = { args: { metaData, - status, activeTab: 'fulltext', tabs, relatedContent, @@ -101,7 +99,6 @@ export const ArticlePageFullTextTabNoSummary: Story = { export const ArticlePageFiguresTab: Story = { args: { metaData, - status, activeTab: 'figures', tabs, relatedContent, @@ -123,7 +120,6 @@ export const ArticlePageReviewedReviewsTab: Story = { ...metaData, version: '1', }, - status, activeTab: 'reviews', tabs, relatedContent, @@ -142,7 +138,6 @@ export const ArticlePageReviewedReviewsTab: Story = { export const ArticlePageRevisedReviewsTab: Story = { args: { metaData, - status, activeTab: 'reviews', tabs, relatedContent, @@ -161,7 +156,6 @@ export const ArticlePageRevisedReviewsTab: Story = { export const ArticlePageRevisedReviewsTabNoSummary: Story = { args: { metaData, - status, activeTab: 'reviews', tabs, relatedContent, @@ -184,7 +178,6 @@ export const ArticlePageRevisedReviewsTabNoSummary: Story = { export const ArticlePageErrorTab: Story = { args: { metaData, - status, activeTab: 'reviews', tabs, relatedContent, diff --git a/src/components/pages/article/article-page.test.tsx b/src/components/pages/article/article-page.test.tsx index 36d738347..b065fde82 100644 --- a/src/components/pages/article/article-page.test.tsx +++ b/src/components/pages/article/article-page.test.tsx @@ -4,7 +4,7 @@ import { import { ArticlePage } from './article-page'; import { ArticleStatus } from '../../molecules/article-status/article-status'; import { - metaData, peerReview, status, timeline, citation, relatedContent, + metaData, peerReview, timeline, citation, relatedContent, } from '../../../utils/mocks'; import { ArticleFiguresTab, ArticleFullTextTab, ArticleReviewsTab } from './tabs'; import { contentToText } from '../../../utils/content'; @@ -16,19 +16,19 @@ jest.mock('next/navigation', () => ({ describe('ArticlePage', () => { it('renders correctly', () => { - expect(() => render( + expect(() => render( )).not.toThrow(); }); it('renders with figures tab', () => { - expect(() => render( + expect(() => render( )).not.toThrow(); }); it('renders with reviews tab', () => { - expect(() => render( + expect(() => render( )).not.toThrow(); }); @@ -48,7 +48,7 @@ describe('ArticlePage', () => { linkElement: Peer review, }, ]; - render( + render( ); @@ -61,7 +61,7 @@ describe('ArticlePage', () => { expect(screen.getByText('Peer review').parentElement?.classList.value).not.toContain('tab-label--active'); cleanup(); - render( + render( ); @@ -70,7 +70,7 @@ describe('ArticlePage', () => { expect(screen.getByText('Peer review').parentElement?.classList.value).not.toContain('tab-label--active'); cleanup(); - render( + render( ); @@ -96,7 +96,7 @@ describe('ArticlePage', () => { }); it('renders related content', () => { - render( + render( ); @@ -106,7 +106,7 @@ describe('ArticlePage', () => { }); it('renders metrics if present', () => { - render( + render( ); @@ -122,7 +122,7 @@ describe('ArticlePage', () => { relatedContent={[]} msidWithVersion="12345v1" metaData={{ ...metaData, authors: [] }} - status={status} + timeline={timeline} activeTab="figures" tabs={[]} @@ -143,7 +143,7 @@ describe('ArticlePage', () => { relatedContent={[]} msidWithVersion="12345v1" metaData={{ ...metaData, authors: [] }} - status={status} + timeline={timeline} activeTab="pdf" tabs={[]} @@ -164,7 +164,7 @@ describe('ArticlePage', () => { relatedContent={relatedContent} msidWithVersion="12345v1" metaData={{ ...metaData, authors: [] }} - status={status} + timeline={timeline} activeTab="pdf" tabs={[]} diff --git a/src/components/pages/article/article-page.tsx b/src/components/pages/article/article-page.tsx index c252b1178..e5d4ba18a 100644 --- a/src/components/pages/article/article-page.tsx +++ b/src/components/pages/article/article-page.tsx @@ -10,12 +10,6 @@ import { CitationData } from '../../atoms/citation/citation'; import { RelatedContentData, RelatedContent } from '../../atoms/related-content/related-content'; import { PreviousVersionWarning } from '../../atoms/previous-version-warning/previous-version-warning'; -export type ArticleStatusProps = { - articleType: string, - status: string, - isPreview: boolean, -}; - export type Tab = { id: string, linkElement: ReactElement, @@ -24,7 +18,6 @@ export type Tab = { export type ArticlePageProps = { metaData: MetaData, msidWithVersion: string, - status: ArticleStatusProps, relatedContent: RelatedContentData[], metrics?: Metrics, children: ReactElement, diff --git a/src/pages/reviewed-preprints/[...path].page.tsx b/src/pages/reviewed-preprints/[...path].page.tsx index e579b3d4b..90477f96a 100644 --- a/src/pages/reviewed-preprints/[...path].page.tsx +++ b/src/pages/reviewed-preprints/[...path].page.tsx @@ -14,11 +14,11 @@ import { } from '../../types'; import { fetchVersion, getLatestVersionWarningUrl } from '../../utils/data-fetch'; import { ArticleFiguresTab, ArticleFullTextTab, ArticleReviewsTab } from '../../components/pages/article/tabs'; -import { ArticlePage, ArticleStatusProps, Tab } from '../../components/pages/article/article-page'; +import { ArticlePage, Tab } from '../../components/pages/article/article-page'; import { contentToText, contentToImgInfo, contentToFigures, contentToJsx, contentToHeadings, } from '../../utils/content'; -import { generateStatus, generateTimeline, generateVersionHistory } from '../../utils/generators'; +import { generateTimeline, generateVersionHistory } from '../../utils/generators'; import { ErrorMessages } from '../../components/atoms/error-messages/error-messages'; import { formatAuthorName } from '../../utils/formatters'; import { makeNullableOptional } from '../../utils/make-nullable-optional'; @@ -29,7 +29,6 @@ type PageProps = { metaData: MetaData, imgInfo: Record | null, msidWithVersion: string, - status: ArticleStatusProps, timeline: SerialisedTimelineEvent[], relatedContent: RelatedContent[], content: Content, @@ -60,7 +59,6 @@ export const Page = ({ metaData, imgInfo, msidWithVersion, - status, timeline, relatedContent, content, @@ -69,7 +67,8 @@ export const Page = ({ previousVersionWarningUrl, }: PageProps) => { const { processedTimeline } = stringsToDates({ timeline }); - const routePrefix = status.isPreview ? '/previews/' : '/reviewed-preprints/'; + const router = useRouter(); + const routePrefix = router.asPath.startsWith('/previews/') ? '/previews/' : '/reviewed-preprints/'; const tabLinks = [ { id: 'fulltext', @@ -116,7 +115,6 @@ export const Page = ({ , }, }; - const router = useRouter(); const tabName = useMemo( () => { if (Array.isArray(router.query.path)) { @@ -163,7 +161,6 @@ export const Page = ({ metaData={metaData} msidWithVersion={msidWithVersion} tabs={tabs} - status={status} timeline={processedTimeline} activeTab={tabName} > @@ -202,16 +199,9 @@ export const getServerSideProps: GetServerSideProps = async (context: const imgInfo = context.req.url?.endsWith('/pdf') ? await contentToImgInfo(articleWithVersions.article.article.content) : null; - const status = generateStatus(articleWithVersions); const timeline = generateTimeline(articleWithVersions); const versionHistory = generateVersionHistory(articleWithVersions); - // This is redundant after server has been updated - if (status.isPreview && !(config.showPreviews || context.req.url?.startsWith('/previews'))) { - console.log('Preview requested in non-preview environment'); // eslint-disable-line no-console - return { notFound: true }; - } - return { props: { siteName: config.siteName, @@ -227,11 +217,6 @@ export const getServerSideProps: GetServerSideProps = async (context: imgInfo, msidWithVersion: id, content: articleWithVersions.article.article.content, - status: { - articleType: status.type, - status: status.status, - isPreview: status.isPreview, - }, timeline, relatedContent: articleWithVersions.article.relatedContent ?? [], peerReview: articleWithVersions.article.peerReview ?? null, // cast to null because undefined isn't a JSON value diff --git a/src/types/article-status.ts b/src/types/article-status.ts deleted file mode 100644 index 4c3927e7e..000000000 --- a/src/types/article-status.ts +++ /dev/null @@ -1,5 +0,0 @@ -export type ArticleStatus = { - type: 'reviewed_preprint', - status: string, - isPreview: boolean, -}; diff --git a/src/types/index.ts b/src/types/index.ts index aa2b13afc..db289c9ac 100644 --- a/src/types/index.ts +++ b/src/types/index.ts @@ -1,4 +1,3 @@ -export type { ArticleStatus } from './article-status'; export type { TimelineEvent } from './article-timeline'; export type { Author, AuthorNotesData } from './author'; export type { Content, FigureContent, HeadingContent } from './content'; diff --git a/src/utils/generators/generate-article-status.test.ts b/src/utils/generators/generate-article-status.test.ts deleted file mode 100644 index 86a36b365..000000000 --- a/src/utils/generators/generate-article-status.test.ts +++ /dev/null @@ -1,140 +0,0 @@ -import { EnhancedArticle, ProcessedArticle, VersionSummary } from '../../types/enhanced-article'; -import { generateStatus } from './generate-article-status'; - -const exampleArticle: Omit = { - abstract: '', - title: '', - licenses: [], - content: '', - headings: [], - references: [], -}; - -const version1: EnhancedArticle = { - id: '1v1', - versionIdentifier: '1', - versionDoi: '10.00001/1v1', - - doi: '10.00001/1', - msid: '1', - - preprintDoi: 'doi-123', - preprintUrl: 'https://doi.org/doi-123', - sentForReview: new Date('2023-01-01'), - preprintPosted: new Date('2023-01-02'), - published: new Date('2023-01-03'), - - article: exampleArticle, -}; - -const version2: EnhancedArticle = { - id: '1v2', - versionIdentifier: '2', - versionDoi: '10.00001/1v1', - - doi: '10.00001/1', - msid: '1', - - preprintDoi: 'doi-123v2', - preprintUrl: 'https://doi.org/doi-123v2', - preprintPosted: new Date('2023-01-05'), - sentForReview: new Date('2023-01-06'), - published: new Date('2023-01-09'), - - article: exampleArticle, -}; - -const summariseEnhancedArticleToVersionSummary = (article: EnhancedArticle): VersionSummary => ({ - id: article.id, - doi: article.doi, - msid: article.msid, - versionIdentifier: article.versionIdentifier, - versionDoi: article.versionDoi, - - preprintDoi: article.preprintDoi, - preprintUrl: article.preprintUrl, - preprintPosted: article.preprintPosted, - sentForReview: article.sentForReview, - published: article.published, -}); - -describe('generateStatus', () => { - it('should has specific status text if article is the same as the first version', () => { - const status = generateStatus({ - article: version1, - versions: { - v1: summariseEnhancedArticleToVersionSummary(version1), - v2: summariseEnhancedArticleToVersionSummary(version2), - }, - }); - - expect(status).toMatchObject({ - type: 'reviewed_preprint', - status: 'Published from the original preprint after peer review and assessment by eLife.', - }); - }); - - it('should has specific status text if article is not the same as the first version', () => { - const status = generateStatus({ - article: version2, - versions: { - v1: summariseEnhancedArticleToVersionSummary(version1), - v2: summariseEnhancedArticleToVersionSummary(version2), - }, - }); - - expect(status).toMatchObject({ - type: 'reviewed_preprint', - status: 'Revised by authors after peer review.', - }); - }); - - it('should be a preview if the published date is empty', () => { - const previewVersion = { - ...version1, - published: null, - }; - - const status = generateStatus({ - article: previewVersion, - versions: { - v1: summariseEnhancedArticleToVersionSummary(previewVersion), - }, - }); - - expect(status).toMatchObject({ - isPreview: true, - }); - }); - - it('should be a preview if the published date is in the future', () => { - const previewVersion = { - ...version1, - published: new Date(new Date().setDate(new Date().getDate() + 1)), - }; - - const status = generateStatus({ - article: previewVersion, - versions: { - v1: summariseEnhancedArticleToVersionSummary(previewVersion), - }, - }); - - expect(status).toMatchObject({ - isPreview: true, - }); - }); - - it('should not be a preview if the published date is present and represents a date in the past', () => { - const status = generateStatus({ - article: version1, - versions: { - v1: summariseEnhancedArticleToVersionSummary(version1), - }, - }); - - expect(status).toMatchObject({ - isPreview: false, - }); - }); -}); diff --git a/src/utils/generators/generate-article-status.ts b/src/utils/generators/generate-article-status.ts deleted file mode 100644 index 8eb107909..000000000 --- a/src/utils/generators/generate-article-status.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { i18n } from '../../i18n'; -import { - EnhancedArticle, - EnhancedArticleWithVersions, - VersionSummary, - ArticleStatus, -} from '../../types'; -import { isPreprintVersionSummary } from '../type-guards'; - -const isVersionSameAsCurrentArticle = (article: EnhancedArticle, version: VersionSummary) => isPreprintVersionSummary(version) && version.id === article.id && version.versionIdentifier === article.versionIdentifier; - -const orderVersionsChronologically = (versions: VersionSummary[]) => versions.filter(isPreprintVersionSummary).sort((a, b) => new Date(a.preprintPosted).getTime() - new Date(b.preprintPosted).getTime()); -const getFirstVersion = (version: EnhancedArticleWithVersions) => orderVersionsChronologically(Object.values(version.versions))[0]; - -export const generateStatus = (version: EnhancedArticleWithVersions): ArticleStatus => ({ - type: 'reviewed_preprint', - status: isVersionSameAsCurrentArticle(version.article, getFirstVersion(version)) - ? i18n.t('status_description_reviewed') - : i18n.t('status_description_revised'), - isPreview: !version.article.published || new Date(version.article.published) > (new Date()), -}); diff --git a/src/utils/generators/index.ts b/src/utils/generators/index.ts index e0a440fab..4438945ea 100644 --- a/src/utils/generators/index.ts +++ b/src/utils/generators/index.ts @@ -1,4 +1,3 @@ -export { generateStatus } from './generate-article-status'; export { generateAuthorId } from './generate-author-id'; export { generateImageInfo, generateImageUrl, generateImageUrlSized } from './generate-image-url'; export { generateTimeline } from './generate-timeline'; diff --git a/src/utils/mocks/index.ts b/src/utils/mocks/index.ts index c921f444e..81f38b607 100644 --- a/src/utils/mocks/index.ts +++ b/src/utils/mocks/index.ts @@ -3,7 +3,6 @@ export { metaData } from './meta-data'; export { content } from './content'; export { peerReview } from './peer-review'; export { references } from './references'; -export { status } from './status'; export { citation } from './citation'; export { relatedContent } from './related-content'; export { metrics } from './metrics'; diff --git a/src/utils/mocks/status.ts b/src/utils/mocks/status.ts deleted file mode 100644 index d9e107ae3..000000000 --- a/src/utils/mocks/status.ts +++ /dev/null @@ -1,9 +0,0 @@ -export const status = { - articleType: 'reviewed_preprint', - status: 'This Reviewed Preprint was published after peer review and assessment by eLife.', - timeline: [ - { name: 'Peer review done', date: '2022-01-02' }, - { name: 'Preprint posted', date: '2022-01-01' }, - ], - isPreview: false, -}; From 0926c744876b6815d674dd62b09ce6ed435dd650 Mon Sep 17 00:00:00 2001 From: Nathan Lisgo Date: Wed, 13 Nov 2024 19:42:38 +0000 Subject: [PATCH 5/8] Add eLife assessment to continuum reviewed preprints API response (#2204) * Add eLife assessment to continuum reviewed preprints API response * Add detailed eLife assessment content and refactor logic --- browser-tests/api-reviewed-preprints.spec.ts | 36 ++++++++++ src/pages/api/reviewed-preprints.page.ts | 69 +++++++++++++++---- src/types/reviewed-preprint-snippet.ts | 22 +++++- .../files/preprints-no-content/index.json | 37 +++++++++- 4 files changed, 147 insertions(+), 17 deletions(-) diff --git a/browser-tests/api-reviewed-preprints.spec.ts b/browser-tests/api-reviewed-preprints.spec.ts index 64f7cea27..a136dd102 100644 --- a/browser-tests/api-reviewed-preprints.spec.ts +++ b/browser-tests/api-reviewed-preprints.spec.ts @@ -18,6 +18,24 @@ test('reviewed preprints api listing', async ({ request }) => { expect(responseJson.items[0].version).toBe(2); expect(responseJson.items[0].doi).toBe('10.1101/2022.11.08.515698'); expect(responseJson.items[0].title).toBe('The locus coeruleus broadcasts prediction errors across the cortex to promote sensorimotor plasticity'); + expect(responseJson.items[0].elifeAssessment).toStrictEqual({ + title: 'eLife assessment', + content: [ + { + type: 'paragraph', + // eslint-disable-next-line max-len + text: 'This important study provides convincing evidence that locus coeruleus is activated during visuomotor mismatches. Gain of function optogenetic experiments complement this evidence and indicate that locus coeruleus could be involved in the learning process that enables visuomotor predictions. This study, therefore, sets the groundwork for the circuit dissection of predictive signals in the visual cortex. Loss-of-function experiments would strengthen the evidence of the involvement of locus coeruleus in prediction learning. These results will be of interest to systems neuroscientists.', + }, + ], + id: 'sa2', + doi: '10.7554/eLife.85111.2.sa2', + significance: [ + 'important', + ], + strength: [ + 'convincing', + ], + }); }); test('reviewed preprints api item found', async ({ request }) => { @@ -37,6 +55,24 @@ test('reviewed preprints api item found', async ({ request }) => { expect(responseJson.version).toBe(2); expect(responseJson.doi).toBe('10.1101/2022.11.08.515698'); expect(responseJson.title).toBe('The locus coeruleus broadcasts prediction errors across the cortex to promote sensorimotor plasticity'); + expect(responseJson.elifeAssessment).toStrictEqual({ + title: 'eLife assessment', + content: [ + { + type: 'paragraph', + // eslint-disable-next-line max-len + text: 'This important study provides convincing evidence that locus coeruleus is activated during visuomotor mismatches. Gain of function optogenetic experiments complement this evidence and indicate that locus coeruleus could be involved in the learning process that enables visuomotor predictions. This study, therefore, sets the groundwork for the circuit dissection of predictive signals in the visual cortex. Loss-of-function experiments would strengthen the evidence of the involvement of locus coeruleus in prediction learning. These results will be of interest to systems neuroscientists.', + }, + ], + id: 'sa2', + doi: '10.7554/eLife.85111.2.sa2', + significance: [ + 'important', + ], + strength: [ + 'convincing', + ], + }); expect(responseJson.indexContent).toContain('Through experience with the world, brains learn to predict the sensory feedback'); expect(responseJson.indexContent).toContain('Rebecca Jordan, Georg B. Keller'); }); diff --git a/src/pages/api/reviewed-preprints.page.ts b/src/pages/api/reviewed-preprints.page.ts index b789e8cf9..dcee933b2 100644 --- a/src/pages/api/reviewed-preprints.page.ts +++ b/src/pages/api/reviewed-preprints.page.ts @@ -6,7 +6,12 @@ import { } from '../../types'; import { getSubjects } from '../../components/molecules/article-flag-list/article-flag-list'; import { contentToHtml } from '../../utils/content'; -import { EnhancedArticleNoContent } from '../../types/reviewed-preprint-snippet'; +import { + ElifeAssessment, + EnhancedArticleNoContent, + PeerReviewEvaluationSummaryOnly, +} from '../../types/reviewed-preprint-snippet'; +import { findTerms } from '../../utils/terms'; type BadRequestMessage = { title: 'bad request' | 'not found', @@ -68,6 +73,41 @@ const errorBadRequest = (res: NextApiResponse, message: string) : void => { }); }; +const getAssessment = (peerReview: PeerReviewEvaluationSummaryOnly): ElifeAssessment => { + const { significance, strength } = findTerms(peerReview.evaluationSummary?.text ?? ''); + + const doi = peerReview.evaluationSummary?.doi; + const id = doi && doi.replace(/^.+\.(sa[0-9]+)$/, '$1'); + + const items = (peerReview.evaluationSummary?.text ?? '') + .replaceAll(/(\\n|^\s*|<\/p+>\s*$)/g, '') + .split(/\s*<\/p>\s*]*>\s*/); + + const titleRegex = /^(.*)<\/strong>$/; + const titles = items + .filter((item) => item.match(titleRegex)); + + const title = (titles.length > 0) ? titles[0].replace(titleRegex, '$1') : 'eLife Assessment'; + + return { + elifeAssessment: { + title, + content: (peerReview.evaluationSummary?.text ?? '') + .replaceAll(/(\\n|^\s*|<\/p+>\s*$)/g, '') + .split(/\s*<\/p>\s*]*>\s*/) + .filter((item) => !item.match(titleRegex)) + .map((item) => ({ + type: 'paragraph', + text: item, + })), + ...(id ? { id } : {}), + ...(doi ? { doi } : {}), + significance: significance ?? [], + ...((strength ?? []).length > 0 ? { strength } : {}), + }, + }; +}; + export const errorNotFoundRequest = (res: NextApiResponse) : void => { writeResponse(res, 'application/json', 404, { title: 'not found', @@ -97,6 +137,7 @@ const enhancedArticleNoContentToSnippet = ({ published, subjects, firstPublished, + peerReview, }: EnhancedArticleNoContent): ReviewedPreprintSnippet => ({ id: msid, doi: preprintDoi, @@ -111,6 +152,7 @@ const enhancedArticleNoContentToSnippet = ({ statusDate: toIsoStringWithoutMilliseconds(new Date(published!)), stage: 'published', subjects: getSubjects(subjects || []), + ...(peerReview ? getAssessment(peerReview) : {}), }); export const enhancedArticleToReviewedPreprintItemResponse = ({ @@ -121,21 +163,20 @@ export const enhancedArticleToReviewedPreprintItemResponse = ({ article, published, subjects, + peerReview, article: { content, authors }, }: EnhancedArticle, firstPublished: Date | null): ReviewedPreprintItemResponse => ({ - id: msid, - doi: preprintDoi, - version: +versionIdentifier, - pdf: pdfUrl, - status: 'reviewed', - authorLine: prepareAuthorLine(authors || []), - title: contentToHtml(article.title), - published: toIsoStringWithoutMilliseconds(new Date(firstPublished ?? published!)), - reviewedDate: toIsoStringWithoutMilliseconds(new Date(firstPublished ?? published!)), - versionDate: toIsoStringWithoutMilliseconds(new Date(published!)), - statusDate: toIsoStringWithoutMilliseconds(new Date(published!)), - stage: 'published', - subjects: getSubjects(subjects || []), + ...enhancedArticleNoContentToSnippet({ + msid, + versionIdentifier, + preprintDoi, + pdfUrl, + article, + published, + subjects, + firstPublished: firstPublished ?? published!, + peerReview, + } as EnhancedArticleNoContent), indexContent: `${authors?.map((author) => prepareAuthor(author)).join(', ')} ${contentToHtml(content)}`, }); diff --git a/src/types/reviewed-preprint-snippet.ts b/src/types/reviewed-preprint-snippet.ts index 1265b4bd9..9ab54cac6 100644 --- a/src/types/reviewed-preprint-snippet.ts +++ b/src/types/reviewed-preprint-snippet.ts @@ -1,4 +1,21 @@ import { EnhancedArticle, ProcessedArticle } from './enhanced-article'; +import { PeerReview } from './peer-review'; + +export type ElifeAssessmentContent = { + type: 'paragraph', + text: string, +}[]; + +export type ElifeAssessment = { + elifeAssessment?: { + title: string, + content: ElifeAssessmentContent, + id?: string, + doi?: string, + significance: string[], + strength?: string[], + }, +}; export type ReviewedPreprintSnippet = { id: string, @@ -17,11 +34,14 @@ export type ReviewedPreprintSnippet = { id: string, name: string, }[], -}; +} & ElifeAssessment; export type VersionSummary = Omit; +export type PeerReviewEvaluationSummaryOnly = Pick; + export type EnhancedArticleNoContent = VersionSummary & { article: Omit, + peerReview?: PeerReviewEvaluationSummaryOnly, firstPublished: Date, }; diff --git a/wiremock/files/preprints-no-content/index.json b/wiremock/files/preprints-no-content/index.json index 29dc775bb..f3fb271e1 100644 --- a/wiremock/files/preprints-no-content/index.json +++ b/wiremock/files/preprints-no-content/index.json @@ -68,7 +68,27 @@ "versionDoi": "10.7554/eLife.85111.2", "versionIdentifier": "2", "volume": "12", - "firstPublished": "2023-01-25T14:00:00.000Z" + "firstPublished": "2023-01-25T14:00:00.000Z", + "peerReview": { + "evaluationSummary": { + "date": "2023-04-14T13:42:25.781Z", + "doi": "10.7554/eLife.85111.2.sa2", + "participants": [ + { + "name": "Brice Bathellier", + "institution": "unknown", + "role": "editor" + }, + { + "name": "Kate Wassum", + "institution": "unknown", + "role": "senior-editor" + } + ], + "reviewType": "evaluation-summary", + "text": "

eLife assessment

\n

This important study provides convincing evidence that locus coeruleus is activated during visuomotor mismatches. Gain of function optogenetic experiments complement this evidence and indicate that locus coeruleus could be involved in the learning process that enables visuomotor predictions. This study, therefore, sets the groundwork for the circuit dissection of predictive signals in the visual cortex. Loss-of-function experiments would strengthen the evidence of the involvement of locus coeruleus in prediction learning. These results will be of interest to systems neuroscientists.

\n" + } + } }, { "article": { @@ -226,6 +246,19 @@ "versionDoi": "xxxxxx/biophysics-colab-111111.1", "versionIdentifier": "1", "volume": "1", - "firstPublished": "2022-10-03T09:03:08.000Z" + "firstPublished": "2022-10-03T09:03:08.000Z", + "peerReview": { + "evaluationSummary": { + "date": "2024-01-12T08:24:31.557Z", + "reviewType": "evaluation-summary", + "text": "

Evaluation statement (10 January 2024)

\n

Driggers et al. is an elegant study that reports the structure of an open KATP channel complex formed from the Q52R diabetes mutation of the pore-forming subunit Kir 6.2, the sulfonylurea receptor (SUR1), and long-chain phosphatidylinositol 4,5-bisphosphate (PIP2) – a key lipid that stabilizes the open state of the channel and regulates inhibition by intracellular ATP. The structure reveals one PIP2 site related to that seen in other Kir channels as well as a second unanticipated one where the lipid snuggles into the interface between Kir6.2 and a region of SUR1 previously implicated in promoting the open state of KATP. This important finding helps to explain how PIP2 exerts such a profound regulatory influence on KATP.

\n

Biophysics Colab considers this to be a convincing study and recommends it to scientists working on KATP and other membrane proteins regulated by PIP2.

\n

(This evaluation by Biophysics Colab refers to version 2 of this preprint, which has been revised in response to peer review of version 1.)

", + "participants": [ + { + "name": "Anonymous", + "role": "editor" + } + ] + } + } } ] From c421f151254fe5699c3ef39d1b831850af3b3d0c Mon Sep 17 00:00:00 2001 From: Will Byrne Date: Thu, 21 Nov 2024 15:15:22 +0000 Subject: [PATCH 6/8] Add config and logic to allow the disabling of the terms features (#2207) [elifesciences/enhanced-preprints-issues#1187] Co-authored-by: Nathan Lisgo --- docker-compose.yaml | 1 + src/components/atoms/assessment/assessment.tsx | 14 ++++++++++---- src/config.ts | 2 ++ 3 files changed, 13 insertions(+), 4 deletions(-) diff --git a/docker-compose.yaml b/docker-compose.yaml index 291dfab1a..17367663c 100644 --- a/docker-compose.yaml +++ b/docker-compose.yaml @@ -105,6 +105,7 @@ services: API_SERVER: ${API_SERVER:-http://wiremock:3000} IIIF_SERVER: ${IIIF_SERVER:-http://image-server:8182/iiif} NEXT_PUBLIC_IMAGE_SERVER: /iiif + NEXT_PUBLIC_DISABLE_TERMS: ${NEXT_PUBLIC_DISABLE_TERMS:-false} depends_on: yarn: condition: service_completed_successfully diff --git a/src/components/atoms/assessment/assessment.tsx b/src/components/atoms/assessment/assessment.tsx index 6f0bbe6c2..ef1e31964 100644 --- a/src/components/atoms/assessment/assessment.tsx +++ b/src/components/atoms/assessment/assessment.tsx @@ -7,6 +7,7 @@ import { } from '../../../utils/terms'; import { Descriptors } from '../descriptors/descriptors'; import { isPdfRoute } from '../../../utils/isPdfRoute'; +import { config } from '../../../config'; type Props = { content: string, doi?: string }; export const Assessment = ({ content, doi }: Props) => { @@ -20,7 +21,12 @@ export const Assessment = ({ content, doi }: Props) => { const { strength, significance } = findTerms(content); - return ( + return config.disableTerms ? ( +
+
+ {doi && } +
+ ) : (
{doi && } @@ -30,9 +36,9 @@ export const Assessment = ({ content, doi }: Props) => {

{t('about_assessments_description')} {t('about_assessments')}

{(expanded !== null && !isPdf) && - setExpanded(!expanded)}> {expanded ? 'Show less' : 'Read more about this assessment'}} + setExpanded(!expanded)}> {expanded ? 'Show less' : 'Read more about this assessment'}}
); }; diff --git a/src/config.ts b/src/config.ts index 176b66d19..eb0bf5bf9 100644 --- a/src/config.ts +++ b/src/config.ts @@ -13,6 +13,7 @@ type Config = { cookiebotId?: string, articleCacheAge: string, disallowRobots: boolean, + disableTerms: boolean, }; export const config: Config = { @@ -25,4 +26,5 @@ export const config: Config = { cookiebotId: process.env.NEXT_PUBLIC_COOKIEBOT_ID, articleCacheAge: process.env.ARTICLE_CACHE_AGE || '1800', disallowRobots: !!process.env.DISALLOW_ROBOTS, + disableTerms: !!process.env.NEXT_PUBLIC_DISABLE_TERMS && process.env.NEXT_PUBLIC_DISABLE_TERMS === 'true', }; From 4d0b1d1ac5c3a05756e99fb63481c2f785ef2952 Mon Sep 17 00:00:00 2001 From: Nathan Lisgo Date: Thu, 21 Nov 2024 21:43:35 +0000 Subject: [PATCH 7/8] Enhance disableTerms logic to include 'all' as a valid condition [elifesciences/enhanced-preprints-issues#1187] --- src/config.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/config.ts b/src/config.ts index eb0bf5bf9..c5b6f280c 100644 --- a/src/config.ts +++ b/src/config.ts @@ -26,5 +26,5 @@ export const config: Config = { cookiebotId: process.env.NEXT_PUBLIC_COOKIEBOT_ID, articleCacheAge: process.env.ARTICLE_CACHE_AGE || '1800', disallowRobots: !!process.env.DISALLOW_ROBOTS, - disableTerms: !!process.env.NEXT_PUBLIC_DISABLE_TERMS && process.env.NEXT_PUBLIC_DISABLE_TERMS === 'true', + disableTerms: !!process.env.NEXT_PUBLIC_DISABLE_TERMS && ['all', 'true'].includes(process.env.NEXT_PUBLIC_DISABLE_TERMS), }; From b47835de54fa303d5bde60da9a8064729f79070a Mon Sep 17 00:00:00 2001 From: Nathan Lisgo Date: Thu, 21 Nov 2024 22:24:30 +0000 Subject: [PATCH 8/8] Update i18n strings and adjust review process link text --- .../atoms/review-process/review-process.tsx | 2 +- src/i18n.ts | 15 ++++++--------- 2 files changed, 7 insertions(+), 10 deletions(-) diff --git a/src/components/atoms/review-process/review-process.tsx b/src/components/atoms/review-process/review-process.tsx index 31331e626..74dd7e4c6 100644 --- a/src/components/atoms/review-process/review-process.tsx +++ b/src/components/atoms/review-process/review-process.tsx @@ -15,7 +15,7 @@ export const ReviewProcess = ({ current, authorResponse }: ReviewProcessProps) =

Peer review process

{parse(t(`review_process_${type}${type === 'reviewed' && authorResponse === true ? '_with_author_response' : ''}`))}

- Read more about eLife’s peer review process. + {t('process_url_read_more')}
); diff --git a/src/i18n.ts b/src/i18n.ts index e6b07c385..c614a52b3 100644 --- a/src/i18n.ts +++ b/src/i18n.ts @@ -14,15 +14,11 @@ const resources = { // Defaults: reviewed_preprints_url: '/reviewed-preprints/{{msid}}', // link to reviewed preprints - heading_assessment: '$t(publisher_short) assessment', about_assessments_description: ( 'During the peer-review process the editor and reviewers write an assessment that summarises the significance' + ' of the findings reported in the article and the strength of the evidence.' ), about_assessments: 'Learn more about $t(publisher_short) assessments', - status_description_reviewed: 'Published from the original preprint after peer review and assessment by $t(publisher_short).', - status_description_revised: 'Revised by authors after peer review.', - status_about: 'About $t(publisher_short)\'s process', reviewed_preprint: 'Reviewed Preprint', related_intro: 'Related {{type}}', related_type_default: 'content', @@ -32,6 +28,10 @@ const resources = { history_version_title: '$t(reviewed_preprint) version {{version}}', external_history_version_title: '$t(history_version_title)', external_history_version_title_updated: '$t(external_history_version_title)', + process_url_read_more: 'Read more about $t(publisher_short)’s peer review process.', + review_process_reviewed: '', + review_process_reviewed_with_author_response: '', + review_process_revised: '', }, elife: { twitter_handle: '@elife', @@ -66,11 +66,8 @@ const resources = { twitter_handle: '@BiophysicsColab', publisher_short: 'Biophysics Colab', publisher_long: 'Biophysics Colab', - heading_assessment: 'Endorsement statement', - timeline_version_title: 'Endorsed article published', - reviewed_preprint: 'Endorsed article', - status_description_reviewed: '$t(publisher_short) have endorsed this preprint that was revised by authors after peer review.', - status_description_revised: '$t(publisher_short) have endorsed this preprint that was revised by authors after peer review.', + timeline_version_title: 'Curated preprint published', + reviewed_preprint: 'Curated preprint', process_url: 'https://www.sciencecolab.org/biophysics-colab', about_assessments_url: 'https://www.sciencecolab.org/biophysics-colab', },