From 500e4bdb15836ac2a55df1c3ba55eeeebf1d908a Mon Sep 17 00:00:00 2001 From: futa-ikeda <51409893+futa-ikeda@users.noreply.github.com> Date: Tue, 3 Dec 2024 17:15:31 -0500 Subject: [PATCH 01/11] [ENG-6447] Update preprint model for versioning (#2419) - Ticket: [ENG-6447] - Feature flag: n/a ## Purpose - Update the Preprint model to add new version-specific fields ## Summary of Changes - Add new `preprintVersion` and `isLatestVersion` attrs to Preprint - Add new `versions` relationship to Preprint - This won't be returned from the API, but the preprint response should have a `preprint_version` URL that can be used to get versions, hence the chicanery with the preprint-serializer - Add new mirage view to handle fetching versions - Add new trait to preprint factory to quickly create versions for a given preprint --- app/models/preprint.ts | 5 +++++ app/preprints/detail/route.ts | 2 ++ app/serializers/preprint.ts | 13 +++++++++++++ mirage/config.ts | 5 ++++- mirage/factories/preprint.ts | 20 ++++++++++++++++++++ mirage/scenarios/preprints.ts | 10 ++++++++++ mirage/serializers/preprint.ts | 1 + mirage/views/preprint.ts | 12 ++++++++++++ types/osf-api.d.ts | 1 + 9 files changed, 68 insertions(+), 1 deletion(-) diff --git a/app/models/preprint.ts b/app/models/preprint.ts index dd67a495f07..baaf54ccdae 100644 --- a/app/models/preprint.ts +++ b/app/models/preprint.ts @@ -70,6 +70,8 @@ export default class PreprintModel extends AbstractNodeModel { @attr('string') whyNoData!: string | null; @attr('string') whyNoPrereg!: string | null; @attr('string') preregLinkInfo!: PreprintPreregLinkInfoEnum; + @attr('number') preprintVersion!: number; + @attr('boolean') isLatestVersion!: boolean; @belongsTo('node', { inverse: 'preprints' }) node!: AsyncBelongsTo & NodeModel; @@ -107,6 +109,9 @@ export default class PreprintModel extends AbstractNodeModel { @hasMany('identifiers') identifiers!: AsyncHasMany; + @hasMany('preprint', { inverse: null }) + versions!: AsyncHasMany; + @alias('links.doi') articleDoiUrl!: string | null; @alias('links.preprint_doi') preprintDoiUrl!: string; diff --git a/app/preprints/detail/route.ts b/app/preprints/detail/route.ts index fb1a3e70fe4..2d9d476f950 100644 --- a/app/preprints/detail/route.ts +++ b/app/preprints/detail/route.ts @@ -76,6 +76,7 @@ export default class PreprintsDetail extends Route { const license = await preprint?.get('license'); const subjects = await preprint?.queryHasMany('subjects'); + const versions = await preprint?.queryHasMany('versions'); return { preprint, @@ -85,6 +86,7 @@ export default class PreprintsDetail extends Route { primaryFile, license, subjects, + versions, }; } catch (error) { diff --git a/app/serializers/preprint.ts b/app/serializers/preprint.ts index 03362dd4093..bda304e9e7d 100644 --- a/app/serializers/preprint.ts +++ b/app/serializers/preprint.ts @@ -1,6 +1,19 @@ +import Model from '@ember-data/model'; +import { Resource } from 'osf-api'; + import OsfSerializer from './osf-serializer'; export default class PreprintSerializer extends OsfSerializer { + normalize(modelClass: Model, resourceHash: Resource) { + const result = super.normalize(modelClass, resourceHash); + // Insert a `versions` relationship to the model + result.data.relationships!.versions = { + links: { + related: resourceHash.links!.preprint_versions!, + }, + }; + return result; + } } declare module 'ember-data/types/registries/serializer' { diff --git a/mirage/config.ts b/mirage/config.ts index bfabf667589..d10586bb62a 100644 --- a/mirage/config.ts +++ b/mirage/config.ts @@ -51,7 +51,7 @@ import { import { updatePassword } from './views/user-password'; import * as userSettings from './views/user-setting'; import * as wb from './views/wb'; -import { createPreprint } from './views/preprint'; +import { createPreprint, getPreprintVersions } from './views/preprint'; const { OSF: { apiUrl, shareBaseUrl, url: osfUrl } } = config; @@ -355,6 +355,9 @@ export default function(this: Server) { return schema.preprints.find(id); }); + this.get('/preprints/:id/versions', getPreprintVersions); + // TODO: add post view + osfNestedResource(this, 'preprint', 'contributors', { path: '/preprints/:parentID/contributors/', defaultSortKey: 'index', diff --git a/mirage/factories/preprint.ts b/mirage/factories/preprint.ts index 858e51b5a59..34c711446f0 100644 --- a/mirage/factories/preprint.ts +++ b/mirage/factories/preprint.ts @@ -32,6 +32,7 @@ export interface PreprintTraits { rejectedWithdrawalNoComment: Trait; reviewAction: Trait; withAffiliatedInstitutions: Trait; + withVersions: Trait; } export default Factory.extend({ @@ -77,6 +78,8 @@ export default Factory.extend({ dateWithdrawn: null, doi: null, + preprintVersion: 1, + isLatestVersion: true, tags() { return faker.lorem.words(5).split(' '); @@ -239,6 +242,23 @@ export default Factory.extend({ }, }), + withVersions: trait({ + afterCreate(preprint, server) { + const baseId = preprint.id; + const versionedPreprints = [1, 2, 3].map((version: number) => { + server.create('preprint', { + title: preprint.title, + description: preprint.description, + provider: preprint.provider, + id: `${baseId}_v${version}`, + preprintVersion: version, + isLatestVersion: version === 3, + }); + }); + preprint.provider.update({ preprints: versionedPreprints }); + }, + }), + reviewAction: trait({ afterCreate(preprint, server) { const creator = server.create('user', { fullName: 'Review action Commentor' }); diff --git a/mirage/scenarios/preprints.ts b/mirage/scenarios/preprints.ts index 670bd1d9d04..5f6edd03795 100644 --- a/mirage/scenarios/preprints.ts +++ b/mirage/scenarios/preprints.ts @@ -234,6 +234,15 @@ function buildOSF( hasPreregLinks: PreprintPreregLinksEnum.NOT_APPLICABLE, }); + const versionedPreprint = server.create('preprint', { + provider: osf, + id: 'versioned-preprint', + title: 'Versioned Preprint', + currentUserPermissions: Object.values(Permission), + reviewsState: ReviewsState.ACCEPTED, + isPublished: true, + }, 'withVersions'); + const subjects = server.createList('subject', 7); osf.update({ @@ -264,6 +273,7 @@ function buildOSF( acceptedWithdrawalPreprintComment, notContributorPreprint, publicDoiPreprint, + versionedPreprint, ], description: 'This is the description for osf', }); diff --git a/mirage/serializers/preprint.ts b/mirage/serializers/preprint.ts index 7e35ba3b294..998de8be8fc 100644 --- a/mirage/serializers/preprint.ts +++ b/mirage/serializers/preprint.ts @@ -11,6 +11,7 @@ export default class PreprintSerializer extends ApplicationSerializer; @@ -81,3 +84,12 @@ export function updatePreprint(this: HandlerContext, schema: Schema, request: Re resource.update(attributes); return this.serialize(resource); } + +export function getPreprintVersions(this: HandlerContext, schema: Schema) { + const preprintId = this.request.params.id as string; + const baseId = preprintId.split('_v')[0]; // assumes preprint id is of the form _v + const preprints = schema.preprints.all().models + .filter((preprint: ModelInstance) => preprint.id !== baseId && preprint.id.includes(baseId)); + return process(schema, this.request, this, + preprints.map((preprint: ModelInstance) => this.serialize(preprint).data)); +} diff --git a/types/osf-api.d.ts b/types/osf-api.d.ts index 3b10b28592d..b0a4091aa52 100644 --- a/types/osf-api.d.ts +++ b/types/osf-api.d.ts @@ -96,5 +96,6 @@ export interface NormalLinks extends JSONAPI.Links { self?: JSONAPI.Link; html?: JSONAPI.Link; iri?: JSONAPI.Link; + preprint_versions?: JSONAPI.Link; } /* eslint-enable camelcase */ From 485756a7d31d185f4018bd2b1c58d481a307d156 Mon Sep 17 00:00:00 2001 From: futa-ikeda <51409893+futa-ikeda@users.noreply.github.com> Date: Wed, 4 Dec 2024 14:26:11 -0500 Subject: [PATCH 02/11] [ENG-6448] Update preprint-doi component to handle versions (#2420) - Ticket: [ENG-6448] - Feature flag: n/a ## Purpose - Update preprint-doi component to handle versions ## Summary of Changes - Update Preprints::PreprintDoi component - Takes an array of versions, rather than a single preprint - Add dropdown to select a specific version - Tests --- .../preprint-doi/component-test.ts | 82 +++++++++++++++++++ .../-components/preprint-doi/component.ts | 12 ++- .../-components/preprint-doi/styles.scss | 4 + .../-components/preprint-doi/template.hbs | 62 ++++++++++---- app/preprints/detail/template.hbs | 5 +- mirage/factories/preprint.ts | 4 +- mirage/views/preprint.ts | 3 +- translations/en-us.yml | 2 + 8 files changed, 151 insertions(+), 23 deletions(-) create mode 100644 app/preprints/-components/preprint-doi/component-test.ts create mode 100644 app/preprints/-components/preprint-doi/styles.scss diff --git a/app/preprints/-components/preprint-doi/component-test.ts b/app/preprints/-components/preprint-doi/component-test.ts new file mode 100644 index 00000000000..ff763efb3b8 --- /dev/null +++ b/app/preprints/-components/preprint-doi/component-test.ts @@ -0,0 +1,82 @@ +import { click } from '@ember/test-helpers'; +import { module, test } from 'qunit'; +import { setupRenderingTest } from 'ember-qunit'; +import { render } from '@ember/test-helpers'; +import hbs from 'htmlbars-inline-precompile'; +import { setupMirage } from 'ember-cli-mirage/test-support'; +import { ModelInstance } from 'ember-cli-mirage'; + +import PreprintProviderModel from 'ember-osf-web/models/preprint-provider'; +import PreprintModel from 'ember-osf-web/models/preprint'; + +module('Integration | Component | preprint-doi', function(hooks) { + setupRenderingTest(hooks); + setupMirage(hooks); + + test('it renders', async function(assert) { + this.store = this.owner.lookup('service:store'); + server.loadFixtures('preprint-providers'); + const mirageProvider = server.schema.preprintProviders.find('osf') as ModelInstance; + const miragePreprint = server.create('preprint', { + id: 'doied', + provider: mirageProvider, + }, 'withVersions'); + // Version 1 has a DOI and has a preprintDoiCreated date + const version1 = server.schema.preprints.find('doied_v1') as ModelInstance; + version1.update({ preprintDoiCreated: new Date('2020-02-02') }); + // Version 2 has a DOI but no preprintDoiCreated date + const version2 = server.schema.preprints.find('doied_v2') as ModelInstance; + version2.update({ preprintDoiCreated: null }); + // Version 3 is pending moderator approval and is not published, therefore has no DOI + const version3 = server.schema.preprints.find('doied_v3') as ModelInstance; + version3.update({ + preprintDoiCreated: null, + isPublished: false, + isPreprintDoi: false, // Mirage flag used to determine if a DOI should be created + }); + + const preprint = await this.store.findRecord('preprint', miragePreprint.id); + const versions = await preprint.queryHasMany('versions'); + + const provider = await this.store.findRecord('preprint-provider', mirageProvider.id); + this.set('versions', versions); + this.set('provider', provider); + + await render(hbs` + + `); + + // check headings exist + assert.dom('[data-test-preprint-doi-heading]').exists('Preprint DOI heading exists'); + assert.dom('[data-test-preprint-doi-heading]').hasText('Preprint DOI', 'Preprint DOI heading has correct text'); + + // check dropdown exists + assert.dom('[data-test-version-select-dropdown]').exists('Version select dropdown exists'); + assert.dom('[data-test-version-select-dropdown]') + .hasText('Version 3', 'Dropdown has latest version selected by default'); + + // check version3 has no DOI + assert.dom('[data-test-no-doi-text]').exists('No DOI text exists'); + assert.dom('[data-test-no-doi-text]').hasText('DOI created after moderator approval', 'No DOI text is correct'); + + // check version2 has DOI, but no preprintDoiCreated date + await click('[data-test-version-select-dropdown]'); + await click('[data-test-preprint-version="2"]'); + assert.dom('[data-test-no-doi-text]').doesNotExist('No DOI text does not exist'); + assert.dom('[data-test-unlinked-doi-url]').exists('Preprint DOI URL exists'); + assert.dom('[data-test-unlinked-doi-description]').exists('Preprint DOI description exists'); + assert.dom('[data-test-unlinked-doi-description]') + // eslint-disable-next-line max-len + .hasText('DOIs are minted by a third party, and may take up to 24 hours to be registered.', 'Description is correct'); + + // check version1 has DOI and preprintDoiCreated date + await click('[data-test-version-select-dropdown]'); + await click('[data-test-preprint-version="1"]'); + assert.dom('[data-test-unlinked-doi-url]').doesNotExist('Unlinked preprint DOI URL does not exist'); + assert.dom('[data-test-unlinked-doi-description]').doesNotExist('Unlinked description does not exist'); + assert.dom('[data-test-linked-doi-url]').exists('Preprint DOI URL exists'); + }); +}); diff --git a/app/preprints/-components/preprint-doi/component.ts b/app/preprints/-components/preprint-doi/component.ts index 6ad155176a8..e67a9dea037 100644 --- a/app/preprints/-components/preprint-doi/component.ts +++ b/app/preprints/-components/preprint-doi/component.ts @@ -1,14 +1,22 @@ +import { action } from '@ember/object'; import Component from '@glimmer/component'; +import { tracked } from '@glimmer/tracking'; import PreprintModel from 'ember-osf-web/models/preprint'; import PreprintProviderModel from 'ember-osf-web/models/preprint-provider'; interface InputArgs { - preprint: PreprintModel; + versions: PreprintModel[]; provider: PreprintProviderModel; } export default class PreprintAbstract extends Component { provider = this.args.provider; + documentType = this.provider.documentType.singularCapitalized; - documentType = this.provider.documentType.singular; + @tracked selectedVersion = this.args.versions[0]; + + @action + selectVersion(version: PreprintModel) { + this.selectedVersion = version; + } } diff --git a/app/preprints/-components/preprint-doi/styles.scss b/app/preprints/-components/preprint-doi/styles.scss new file mode 100644 index 00000000000..d85b72a0d94 --- /dev/null +++ b/app/preprints/-components/preprint-doi/styles.scss @@ -0,0 +1,4 @@ +.version-dropdown { + margin-bottom: 12px; + width: 120px; +} diff --git a/app/preprints/-components/preprint-doi/template.hbs b/app/preprints/-components/preprint-doi/template.hbs index 55942ff37e3..e063aa422e4 100644 --- a/app/preprints/-components/preprint-doi/template.hbs +++ b/app/preprints/-components/preprint-doi/template.hbs @@ -1,23 +1,49 @@
-

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

- {{#if @preprint.preprintDoiUrl}} - {{#if @preprint.preprintDoiCreated}} - + {{t 'preprints.detail.preprint_doi' documentType=this.documentType}} + + {{#if @versions}} + + - {{@preprint.preprintDoiUrl}} - - {{else}} -

{{@preprint.preprintDoiUrl}}

-

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

- {{/if}} + {{t 'preprints.detail.version_doi_title' number=version.preprintVersion}} + + {{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'}} +

{{t 'preprints.detail.no_versions'}}

+ {{/if}} + {{#if this.selectedVersion}} + {{#if this.selectedVersion.preprintDoiUrl}} + {{#if this.selectedVersion.preprintDoiCreated}} + + {{this.selectedVersion.preprintDoiUrl}} + + {{else}} +

{{this.selectedVersion.preprintDoiUrl}}

+

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

+ {{/if}} + {{else}} +

+ {{#if (not this.selectedVersion.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'}} + {{else}} + {{t 'preprints.detail.no_doi'}} + {{/if}} +

{{/if}} {{/if}} -
\ No newline at end of file + diff --git a/app/preprints/detail/template.hbs b/app/preprints/detail/template.hbs index a6a14847d5f..e2c16f42825 100644 --- a/app/preprints/detail/template.hbs +++ b/app/preprints/detail/template.hbs @@ -181,7 +181,10 @@ {{/if}} - + {{#if this.model.preprint.articleDoiUrl}}

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

diff --git a/mirage/factories/preprint.ts b/mirage/factories/preprint.ts index 34c711446f0..60755c234c6 100644 --- a/mirage/factories/preprint.ts +++ b/mirage/factories/preprint.ts @@ -255,7 +255,9 @@ export default Factory.extend({ isLatestVersion: version === 3, }); }); - preprint.provider.update({ preprints: versionedPreprints }); + if (preprint.provider) { + preprint.provider.update({ preprints: versionedPreprints }); + } }, }), diff --git a/mirage/views/preprint.ts b/mirage/views/preprint.ts index b969bc9866c..e71845b6817 100644 --- a/mirage/views/preprint.ts +++ b/mirage/views/preprint.ts @@ -90,6 +90,7 @@ export function getPreprintVersions(this: HandlerContext, schema: Schema) { const baseId = preprintId.split('_v')[0]; // assumes preprint id is of the form _v const preprints = schema.preprints.all().models .filter((preprint: ModelInstance) => preprint.id !== baseId && preprint.id.includes(baseId)); + const versions = preprints.sortBy('versionNumber').reverse(); return process(schema, this.request, this, - preprints.map((preprint: ModelInstance) => this.serialize(preprint).data)); + versions.map((version: ModelInstance) => this.serialize(version).data)); } diff --git a/translations/en-us.yml b/translations/en-us.yml index 0416c52097d..0383cd7f79e 100644 --- a/translations/en-us.yml +++ b/translations/en-us.yml @@ -1431,8 +1431,10 @@ preprints: original_publication_date: 'Original Publication Date' orphan_preprint: 'The user has removed this file.' preprint_doi: '{documentType} DOI' + version_doi_title: 'Version {number}' preprint_pending_doi: 'DOI created after {documentType} is made public' preprint_pending_doi_moderation: 'DOI created after moderator approval' + no_doi: 'No DOI' preprint_pending_doi_minted: 'DOIs are minted by a third party, and may take up to 24 hours to be registered.' private_preprint_warning: 'This {documentType} is private. Contact {supportEmail} if this is in error.' project_button: From 47ea4340ba56c72c9daa94202f05057e049db88d Mon Sep 17 00:00:00 2001 From: futa-ikeda <51409893+futa-ikeda@users.noreply.github.com> Date: Thu, 5 Dec 2024 17:46:03 -0500 Subject: [PATCH 03/11] [ENG-6434] Show/hide file upload page on preprint submit workflow (#2422) - Ticket: [ENG-6434] - Feature flag: n/a ## Purpose - Add logic to show/hide the file upload step on the preprint submission/edit workflow ## Summary of Changes - Add a new flag `displayFileUploadStep` that controls whether or not the file upload step is shown - Should be shown for initial preprint submission - Should be shown for rejected preprint re-submission --- .../preprint-provider-selection/template.hbs | 1 + .../preprint-state-machine/component.ts | 78 ++++++++--- .../status-flow-display/template.hbs | 4 +- .../preprint-state-machine/template.hbs | 1 + tests/acceptance/preprints/edit-test.ts | 130 ++++++++++++++++++ tests/acceptance/preprints/submit-test.ts | 105 ++++++++++++++ 6 files changed, 297 insertions(+), 22 deletions(-) create mode 100644 tests/acceptance/preprints/edit-test.ts create mode 100644 tests/acceptance/preprints/submit-test.ts diff --git a/app/preprints/-components/preprint-provider-selection/template.hbs b/app/preprints/-components/preprint-provider-selection/template.hbs index 5cf71c094b0..b9f22e7445f 100644 --- a/app/preprints/-components/preprint-provider-selection/template.hbs +++ b/app/preprints/-components/preprint-provider-selection/template.hbs @@ -28,6 +28,7 @@
{{/if}}
diff --git a/app/preprints/new-version/controller.ts b/app/preprints/new-version/controller.ts new file mode 100644 index 00000000000..9a7101f1790 --- /dev/null +++ b/app/preprints/new-version/controller.ts @@ -0,0 +1,9 @@ +import Controller from '@ember/controller'; +import { action } from '@ember/object'; + +export default class PreprintNewVersionController extends Controller { + @action + noop() { + return; + } +} diff --git a/app/preprints/new-version/route.ts b/app/preprints/new-version/route.ts new file mode 100644 index 00000000000..d7db18c1f07 --- /dev/null +++ b/app/preprints/new-version/route.ts @@ -0,0 +1,78 @@ +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 Toast from 'ember-toastr/services/toast'; +import Intl from 'ember-intl/services/intl'; + +import Theme from 'ember-osf-web/services/theme'; +import MetaTags, { HeadTagDef } from 'ember-osf-web/services/meta-tags'; +import PreprintModel from 'ember-osf-web/models/preprint'; + +export default class PreprintNewVersionRoute extends Route { + @service store!: Store; + @service theme!: Theme; + @service router!: RouterService; + @service metaTags!: MetaTags; + @service toast!: Toast; + @service intl!: Intl; + + + headTags?: HeadTagDef[]; + + buildRouteInfoMetadata() { + return { + osfMetrics: { + providerId: this.theme.id, + }, + }; + } + + async model(args: any) { + try { + const provider = await this.store.findRecord('preprint-provider', args.provider_id); + this.theme.providerType = 'preprint'; + this.theme.id = args.provider_id; + + const preprint: PreprintModel = await this.store.findRecord('preprint', args.guid); + + // TODO: Re-evaluate if re-route logic is necessary + // if (!preprint.canCreateNewVersion) { + // let message = this.intl.t('preprints.submit.new-version.redirect.latest-published', + // { preprintWord: provider.documentType.singular }); + // if (!preprint.currentUserIsAdmin) { + // message = this.intl.t('preprints.submit.new-version.redirect.permission', + // { preprintWord: provider.documentType.singular }); + // } + + // const title = this.intl.t('preprints.submit.new-version.redirect.title'); + // this.toast.info(message, title); + // this.router.transitionTo('preprints.detail', args.provider_id, args.guid); + // return null; + // } + + return { + provider, + preprint, + brand: provider.brand.content, + }; + } catch (e) { + this.router.transitionTo('not-found', `preprints/${args.provider_id}`); + return null; + } + } + + afterModel(model: any) { + const {provider} = model; + if (provider && provider.assets && provider.assets.favicon) { + const headTags = [{ + type: 'link', + attrs: { + rel: 'icon', + href: provider.assets.favicon, + }, + }]; + this.set('headTags', headTags); + } + } +} diff --git a/app/preprints/new-version/template.hbs b/app/preprints/new-version/template.hbs new file mode 100644 index 00000000000..61dbe11abba --- /dev/null +++ b/app/preprints/new-version/template.hbs @@ -0,0 +1,9 @@ + diff --git a/app/router.ts b/app/router.ts index be2416a6e37..8aa10d2343e 100644 --- a/app/router.ts +++ b/app/router.ts @@ -38,6 +38,7 @@ Router.map(function() { this.route('detail', { path: '/:provider_id/:guid' }); this.route('submit', { path: '/:provider_id/submit' }); this.route('edit', { path: '/:provider_id/edit/:guid' }); + this.route('new-version', { path: '/:provider_id/new-version/:guid' }); this.route('select'); this.route('my-preprints'); }); diff --git a/mirage/config.ts b/mirage/config.ts index d10586bb62a..d2bb051b22e 100644 --- a/mirage/config.ts +++ b/mirage/config.ts @@ -51,7 +51,7 @@ import { import { updatePassword } from './views/user-password'; import * as userSettings from './views/user-setting'; import * as wb from './views/wb'; -import { createPreprint, getPreprintVersions } from './views/preprint'; +import { createPreprint, getPreprintVersions, createPreprintVersion } from './views/preprint'; const { OSF: { apiUrl, shareBaseUrl, url: osfUrl } } = config; @@ -356,7 +356,7 @@ export default function(this: Server) { }); this.get('/preprints/:id/versions', getPreprintVersions); - // TODO: add post view + this.post('/preprints/:id/versions', createPreprintVersion); osfNestedResource(this, 'preprint', 'contributors', { path: '/preprints/:parentID/contributors/', @@ -416,6 +416,7 @@ export default function(this: Server) { defaultSortKey: 'index', relatedModelName: 'review-action', }); + this.post('/preprints/:parentID/review_actions', createReviewAction); /** * Preprint Requests diff --git a/mirage/factories/preprint.ts b/mirage/factories/preprint.ts index 1021080d416..77bcd061258 100644 --- a/mirage/factories/preprint.ts +++ b/mirage/factories/preprint.ts @@ -246,18 +246,25 @@ export default Factory.extend({ afterCreate(preprint, server) { const baseId = preprint.id; const versionedPreprints = [1, 2, 3].map((version: number) => { - server.create('preprint', { + const isLatestVersion = version === 3; + return server.create('preprint', { title: preprint.title, description: preprint.description, provider: preprint.provider, id: `${baseId}_v${version}`, reviewsState: preprint.reviewsState, preprintVersion: version, - isLatestVersion: version === 3, + isLatestVersion, }); }); + preprint.update({ + // A bit of a workaround since the API will return the latest version when getting baseId + preprintVersion: 3, + isLatestVersion: true, + }); + if (preprint.provider) { - preprint.provider.update({ preprints: versionedPreprints }); + preprint.provider.preprints.models.pushObjects(versionedPreprints); } }, }), diff --git a/mirage/factories/review-action.ts b/mirage/factories/review-action.ts index 07310c81e18..b03aefd9895 100644 --- a/mirage/factories/review-action.ts +++ b/mirage/factories/review-action.ts @@ -3,6 +3,15 @@ import faker from 'faker'; import ReviewActionModel, { ReviewActionTrigger } from 'ember-osf-web/models/review-action'; +export interface TargetRelationship { + id: string | number; + type: 'registrations' | 'preprints'; +} +export interface MirageReviewAction { + creatorId: string; + targetId: TargetRelationship; +} + export default Factory.extend({ auto: false, visible: true, diff --git a/mirage/scenarios/preprints.ts b/mirage/scenarios/preprints.ts index 5f6edd03795..8a87ea69faf 100644 --- a/mirage/scenarios/preprints.ts +++ b/mirage/scenarios/preprints.ts @@ -39,7 +39,7 @@ function buildOSF( const currentUserModerator = server.create('moderator', { id: currentUser.id, user: currentUser, provider: osf }, 'asAdmin'); - const rejectedAdminPreprint = server.create('preprint', { + server.create('preprint', { provider: osf, id: 'osf-rejected-admin', title: 'Preprint RWF: Pre-moderation, Admin and Rejected with Review Actions comment', @@ -74,7 +74,7 @@ function buildOSF( approvedAdminPreprint.update({ identifiers: [osfApprovedAdminIdentifier] }); - const notContributorPreprint = server.create('preprint', Object({ + server.create('preprint', Object({ provider: osf, id: 'osf-not-contributor', title: 'Preprint RWF: Pre-moderation, Non-Admin and Rejected', @@ -88,7 +88,7 @@ function buildOSF( isPreprintDoi: false, })); - const rejectedPreprint = server.create('preprint', { + server.create('preprint', { provider: osf, id: 'osf-rejected', title: 'Preprint RWF: Pre-moderation, Non-Admin and Rejected', @@ -99,7 +99,7 @@ function buildOSF( tags: [], }, 'isContributor'); - const approvedPreprint = server.create('preprint', { + server.create('preprint', { provider: osf, id: 'osf-approved', title: 'Preprint RWF: Pre-moderation, Non-Admin and Approved', @@ -120,7 +120,7 @@ function buildOSF( conflictOfInterestStatement: `${faker.lorem.sentence(200)}\n${faker.lorem.sentence(300)}`, }, 'isContributor'); - const orphanedPreprint = server.create('preprint', { + server.create('preprint', { provider: osf, id: 'osf-orphan', title: 'Preprint RWF: Pre-moderation, Non-Admin and Approved', @@ -129,7 +129,7 @@ function buildOSF( isPreprintOrphan: true, }, 'isContributor'); - const privatePreprint = server.create('preprint', Object({ + server.create('preprint', Object({ provider: osf, id: 'osf-private', title: 'Preprint RWF: Pre-moderation, Non-Admin and Approved', @@ -139,7 +139,7 @@ function buildOSF( isPreprintDoi: false, }), 'isContributor'); - const publicDoiPreprint = server.create('preprint', Object({ + server.create('preprint', Object({ provider: osf, id: 'osf-public-doi', title: 'Preprint RWF: Pre-moderation, Non-Admin and Approved', @@ -151,7 +151,7 @@ function buildOSF( isPublished: true, }), 'isContributor'); - const notPublishedPreprint = server.create('preprint', { + server.create('preprint', { provider: osf, id: 'osf-not-published', title: 'Preprint RWF: Pre-moderation, Non-Admin and Approved', @@ -160,7 +160,7 @@ function buildOSF( isPublished: false, }, 'isContributor'); - const withdrawnPreprint = server.create('preprint', Object({ + server.create('preprint', Object({ provider: osf, id: 'osf-withdrawn', title: 'Preprint Non-Admin, Not Published and withdrawn - no license - no justification', @@ -171,7 +171,7 @@ function buildOSF( addLicenseName: false, }), 'isContributor', 'withdrawn' ); - const withdrawnLicensePreprint = server.create('preprint', Object({ + server.create('preprint', Object({ provider: osf, id: 'osf-withdrawn-license', title: 'Preprint Non-Admin, Not Published and withdrawn - license - justification - tombstone', @@ -183,7 +183,7 @@ function buildOSF( description: `${faker.lorem.sentence(200)}\n${faker.lorem.sentence(100)}`, }), 'isContributor', 'withdrawn'); - const pendingWithdrawalPreprint = server.create('preprint', { + server.create('preprint', { provider: osf, id: 'osf-pending-withdrawal', title: 'Preprint Non-Admin, Not Published and Pending Withdrawal', @@ -192,7 +192,7 @@ function buildOSF( isPublished: false, }, 'pendingWithdrawal', 'isContributor'); - const rejectedWithdrawalPreprintNoComment = server.create('preprint', { + server.create('preprint', { provider: osf, id: 'osf-rejected-withdrawal-no-comment', title: 'Preprint Non-Admin, Not Published and Rejected Withdrawal - No Comment', @@ -201,7 +201,7 @@ function buildOSF( isPublished: false, }, 'rejectedWithdrawalNoComment', 'isContributor'); - const rejectedWithdrawalPreprintComment = server.create('preprint', { + server.create('preprint', { provider: osf, id: 'osf-rejected-withdrawal-comment', title: 'Preprint Non-Admin, Not Published and Rejected Withdrawal - Comment - Reviews Allowed', @@ -210,7 +210,7 @@ function buildOSF( isPublished: false, }, 'rejectedWithdrawalComment', 'isContributor'); - const acceptedWithdrawalPreprintComment = server.create('preprint', { + server.create('preprint', { provider: osf, id: 'osf-accepted-withdrawal-comment', title: 'Preprint Non-Admin, Not Published and Accepted Withdrawal - Comment - Reviews Allowed', @@ -219,7 +219,7 @@ function buildOSF( isPublished: false, }, 'acceptedWithdrawalComment'); - const examplePreprint = server.create('preprint', { + server.create('preprint', { provider: osf, id: 'khbvy', title: 'The "See Example" hard-coded preprint', @@ -234,14 +234,34 @@ function buildOSF( hasPreregLinks: PreprintPreregLinksEnum.NOT_APPLICABLE, }); - const versionedPreprint = server.create('preprint', { + // Accepted with versions + server.create('preprint', { provider: osf, id: 'versioned-preprint', - title: 'Versioned Preprint', + title: '3 Versions Preprint', currentUserPermissions: Object.values(Permission), reviewsState: ReviewsState.ACCEPTED, isPublished: true, }, 'withVersions'); + // Withdrawn with versions + server.create('preprint', { + provider: osf, + id: 'withdrawn-preprint', + title: 'ReviewsState: Withdrawn Preprint', + currentUserPermissions: Object.values(Permission), + reviewsState: ReviewsState.WITHDRAWN, + isPublished: true, + dateWithdrawn: new Date(), + }, 'withVersions'); + // Rejected with versions + server.create('preprint', { + provider: osf, + id: 'rejected-preprint', + title: 'ReviewsState: Rejected Preprint', + currentUserPermissions: Object.values(Permission), + reviewsState: ReviewsState.REJECTED, + isPublished: true, + }, 'withVersions'); const subjects = server.createList('subject', 7); @@ -256,25 +276,6 @@ function buildOSF( footer_links: '', brand, moderators: [currentUserModerator], - preprints: [ - examplePreprint, - rejectedAdminPreprint, - approvedAdminPreprint, - approvedPreprint, - rejectedPreprint, - orphanedPreprint, - privatePreprint, - notPublishedPreprint, - withdrawnPreprint, - withdrawnLicensePreprint, - pendingWithdrawalPreprint, - rejectedWithdrawalPreprintNoComment, - rejectedWithdrawalPreprintComment, - acceptedWithdrawalPreprintComment, - notContributorPreprint, - publicDoiPreprint, - versionedPreprint, - ], description: 'This is the description for osf', }); } diff --git a/mirage/views/preprint.ts b/mirage/views/preprint.ts index e71845b6817..d51a3165f16 100644 --- a/mirage/views/preprint.ts +++ b/mirage/views/preprint.ts @@ -1,6 +1,7 @@ import { HandlerContext, ModelInstance, Request, Response, Schema } from 'ember-cli-mirage'; import { Permission } from 'ember-osf-web/models/osf-model'; import PreprintModel from 'ember-osf-web/models/preprint'; +import { ReviewsState } from 'ember-osf-web/models/provider'; import faker from 'faker'; import { guid } from '../factories/utils'; @@ -94,3 +95,19 @@ export function getPreprintVersions(this: HandlerContext, schema: Schema) { return process(schema, this.request, this, versions.map((version: ModelInstance) => this.serialize(version).data)); } + +export function createPreprintVersion(this: HandlerContext, schema: Schema) { + const basePreprintId = this.request.params.id as string; + const basePreprint = schema.preprints.find(basePreprintId); + basePreprint.update({ isLatestVersion: false }); + const baseVersionNumber = basePreprint.preprintVersion || 1; + const providerModeration = basePreprint.provider && basePreprint.provider.reviewsWorkflow; + const newVersion = schema.preprints.create({ + ...basePreprint.attrs, + reviewsState: providerModeration ? ReviewsState.PENDING : ReviewsState.ACCEPTED, + id: basePreprintId.split('_v')[0] + '_v' + (baseVersionNumber + 1), + versionNumber: baseVersionNumber + 1, + isLatestVersion: true, + }); + return this.serialize(newVersion); +} diff --git a/mirage/views/review-action.ts b/mirage/views/review-action.ts index 37407f46a99..8e34488c86c 100644 --- a/mirage/views/review-action.ts +++ b/mirage/views/review-action.ts @@ -1,39 +1,61 @@ -import { HandlerContext, NormalizedRequestAttrs, Request, Schema } from 'ember-cli-mirage'; +import { HandlerContext, ModelInstance, NormalizedRequestAttrs, Request, Schema } from 'ember-cli-mirage'; +import { PreprintMirageModel } from 'ember-osf-web/mirage/factories/preprint'; +import { MirageRegistration } from 'ember-osf-web/mirage/factories/registration'; +import { MirageReviewAction } from 'ember-osf-web/mirage/factories/review-action'; +import { ReviewsState } from 'ember-osf-web/models/provider'; import { RegistrationReviewStates } from 'ember-osf-web/models/registration'; -import ReviewActionModel, { ReviewActionTrigger } from 'ember-osf-web/models/review-action'; +import { ReviewActionTrigger } from 'ember-osf-web/models/review-action'; import { RevisionReviewStates } from 'ember-osf-web/models/schema-response'; export function createReviewAction(this: HandlerContext, schema: Schema, request: Request) { - const attrs = this.normalizedRequestAttrs('review-action') as Partial>; - const registrationId = request.params.parentID; + const attrs = this.normalizedRequestAttrs('review-action') as Partial>; + const targetId = request.params.parentID; const userId = schema.roots.first().currentUserId; let reviewAction; - if (userId && registrationId) { + if (userId && targetId) { const currentUser = schema.users.find(userId); - const registration = schema.registrations.find(registrationId); + const target = schema[attrs.targetId!.type].find(targetId) as + ModelInstance; const { trigger } = attrs as any; // have to cast attrs to any because `actionTrigger` does not exist on type reviewAction = schema.reviewActions.create({ creator: currentUser, - target: registration, + target, dateCreated: new Date(), dateModified: new Date(), ...attrs, }); - switch (trigger) { - case ReviewActionTrigger.AcceptSubmission: - case ReviewActionTrigger.RejectWithdrawal: - registration.reviewsState = RegistrationReviewStates.Accepted; - registration.revisionState = RevisionReviewStates.Approved; - break; - case ReviewActionTrigger.RejectSubmission: - registration.reviewsState = RegistrationReviewStates.Rejected; - break; - case ReviewActionTrigger.ForceWithdraw: - case ReviewActionTrigger.AcceptWithdrawal: - registration.reviewsState = RegistrationReviewStates.Withdrawn; - break; - default: - break; + if (target.modelName === 'preprint') { + switch (trigger) { + case ReviewActionTrigger.Submit: + target.reviewsState = ReviewsState.PENDING; + break; + case ReviewActionTrigger.RejectSubmission: + target.reviewsState = ReviewsState.REJECTED; + break; + case ReviewActionTrigger.ForceWithdraw: + case ReviewActionTrigger.AcceptWithdrawal: + target.reviewsState = ReviewsState.WITHDRAWN; + break; + default: + break; + } + } else if (target.modelName === 'registration') { + switch (trigger) { + case ReviewActionTrigger.AcceptSubmission: + case ReviewActionTrigger.RejectWithdrawal: + target.reviewsState = RegistrationReviewStates.Accepted; + target.revisionState = RevisionReviewStates.Approved; + break; + case ReviewActionTrigger.RejectSubmission: + target.reviewsState = RegistrationReviewStates.Rejected; + break; + case ReviewActionTrigger.ForceWithdraw: + case ReviewActionTrigger.AcceptWithdrawal: + target.reviewsState = RegistrationReviewStates.Withdrawn; + break; + default: + break; + } } } return reviewAction; diff --git a/tests/acceptance/preprints/new-version-test.ts b/tests/acceptance/preprints/new-version-test.ts new file mode 100644 index 00000000000..185fbe4acb2 --- /dev/null +++ b/tests/acceptance/preprints/new-version-test.ts @@ -0,0 +1,52 @@ +import { currentRouteName } from '@ember/test-helpers'; +import { ModelInstance } from 'ember-cli-mirage'; +import { setupMirage } from 'ember-cli-mirage/test-support'; +import { percySnapshot } from 'ember-percy'; +import { TestContext } from 'ember-test-helpers'; +import { module, test } from 'qunit'; + +import { setupOSFApplicationTest, visit } from 'ember-osf-web/tests/helpers'; +import PreprintProviderModel from 'ember-osf-web/models/preprint-provider'; +import PreprintModel from 'ember-osf-web/models/preprint'; +import { ReviewsState } from 'ember-osf-web/models/provider'; +import { Permission } from 'ember-osf-web/models/osf-model'; + +interface PreprintNewVersionTestContext extends TestContext { + provider: ModelInstance; + miragePreprint: ModelInstance; +} + +module('Acceptance | preprints | new version', hooks => { + setupOSFApplicationTest(hooks); + setupMirage(hooks); + + hooks.beforeEach(async function(this: PreprintNewVersionTestContext) { + server.loadFixtures('preprint-providers'); + server.create('user', 'loggedIn'); + const provider = server.schema.preprintProviders.find('osf') as ModelInstance; + const miragePreprint = server.create('preprint', { + id: 'test', + provider, + currentUserPermissions: Object.values(Permission), + }); + + this.provider = provider; + this.miragePreprint = miragePreprint; + }); + + test('LeftNav for new preprint version', async function(this: PreprintNewVersionTestContext, assert) { + this.miragePreprint.update({reviewsState: ReviewsState.ACCEPTED}); + await visit('/preprints/osf/new-version/test'); + assert.equal(currentRouteName(), 'preprints.new-version', 'Current route is preprint new-version'); + + const pageTitle = document.getElementsByTagName('title')[0].innerText; + assert.equal(pageTitle, 'OSF Preprints | New Version', 'Page title is correct'); + + assert.dom('[data-test-preprint-submission-step="File"]').exists('File step present'); + assert.dom('[data-test-preprint-submission-step="Metadata"]').doesNotExist('Metadata step not present'); + assert.dom('[data-test-preprint-submission-step="Author Assertions"]') + .doesNotExist('Author Assertions step not present'); + assert.dom('[data-test-preprint-submission-step="Review"]').exists('Review step present'); + await percySnapshot(assert); + }); +}); diff --git a/translations/en-us.yml b/translations/en-us.yml index 197aaefe375..a1943dca3a9 100644 --- a/translations/en-us.yml +++ b/translations/en-us.yml @@ -1279,6 +1279,7 @@ preprints: edit-permission-error: 'User does not have permission to edit this {singularPreprintWord}' title-submit: 'New {documentType}' title-edit: 'Edit {documentType}' + title-new-version: 'New Version' step-title: title: 'Title and Abstract' title-input: 'Title' @@ -1405,12 +1406,24 @@ preprints: save-before-exit: 'Unsaved changes present. Are you sure you want to leave this page?' success: '{singularPreprintWord} saved.' success-withdrawal: 'Your {singularCapitalizedPreprintWord} has been successfully withdrawn.' + submit: 'Submit' withdraw-button: 'Withdraw' withdrawal-input-error: '25 characters' withdrawal-label: 'Reason for withdrawal (required):' withdrawal-modal-title: 'Withdraw {singularPreprintWord}' withdrawal-placeholder: 'Comment' + new-version: + success: 'New version created.' + success-review: 'New version submitted for moderation.' + redirect: + title: 'Cannot create a new version' + permissions: 'You do not have permission to create a new version of this {preprintWord}.' + latest-published: 'A new version can only be created from the latest published version of a {preprintWord}.' + error: + title: 'Error creating a new version' + description: 'An error occurred while creating a new version of this {preprintWord}. Please try again.' + conflict: 'There is already a new version of this {preprintWord} in progress. Please wait for the current version to be completed.' detail: abstract: 'Abstract' article_doi: 'Peer-reviewed Publication DOI' From 6a62967aec5aa7d5a4e1b95d03db2d924b5b3509 Mon Sep 17 00:00:00 2001 From: futa-ikeda <51409893+futa-ikeda@users.noreply.github.com> Date: Mon, 30 Dec 2024 09:55:19 -0500 Subject: [PATCH 06/11] [ENG-6470] Withdrawn version picker (#2436) - Ticket: [ENG-6470] - Feature flag: n/a ## Purpose - Add a version select dropdown to the tombstone page ## Summary of Changes - Add dropdown to tombstone page header to view prior versions - Update tests --- app/models/preprint.ts | 2 +- .../-components/preprint-doi/template.hbs | 4 +- app/preprints/detail/styles.scss | 21 +++++++++- app/preprints/detail/template.hbs | 39 ++++++++++++++++++- mirage/factories/preprint.ts | 6 +-- mirage/views/preprint.ts | 2 +- tests/acceptance/preprints/detail-test.ts | 21 +++++++++- translations/en-us.yml | 3 ++ 8 files changed, 86 insertions(+), 12 deletions(-) diff --git a/app/models/preprint.ts b/app/models/preprint.ts index d87e6e689d6..26e05211ff7 100644 --- a/app/models/preprint.ts +++ b/app/models/preprint.ts @@ -70,7 +70,7 @@ export default class PreprintModel extends AbstractNodeModel { @attr('string') whyNoData!: string | null; @attr('string') whyNoPrereg!: string | null; @attr('string') preregLinkInfo!: PreprintPreregLinkInfoEnum; - @attr('number') preprintVersion!: number; + @attr('number') version!: number; @attr('boolean') isLatestVersion!: boolean; @belongsTo('node', { inverse: 'preprints' }) diff --git a/app/preprints/-components/preprint-doi/template.hbs b/app/preprints/-components/preprint-doi/template.hbs index e063aa422e4..1d24a5d5da1 100644 --- a/app/preprints/-components/preprint-doi/template.hbs +++ b/app/preprints/-components/preprint-doi/template.hbs @@ -12,9 +12,9 @@ as |version| > - {{t 'preprints.detail.version_doi_title' number=version.preprintVersion}} + {{t 'preprints.detail.version_doi_title' number=version.version}} {{else}} diff --git a/app/preprints/detail/styles.scss b/app/preprints/detail/styles.scss index 884b910ed61..23d5338b806 100644 --- a/app/preprints/detail/styles.scss +++ b/app/preprints/detail/styles.scss @@ -76,7 +76,7 @@ flex-direction: row; justify-content: flex-start; align-items: flex-start; - + .withdrawn-container { padding: 0 15px; width: 100%; @@ -259,3 +259,22 @@ } } } + +.version-dropdown { + display: inline-block; +} + +.version-picker-list { + list-style: none; + margin: 0; + padding-inline-start: 0; + padding: 10px; + + .version:not(:first-child) { + padding-top: 10px; + } + + .current-version { + font-weight: bold; + } +} diff --git a/app/preprints/detail/template.hbs b/app/preprints/detail/template.hbs index 48a71ea298c..e3aa6c93bb4 100644 --- a/app/preprints/detail/template.hbs +++ b/app/preprints/detail/template.hbs @@ -10,7 +10,42 @@

{{this.displayTitle}}

- {{#unless this.model.preprint.isWithdrawn}} + {{#if this.model.preprint.isWithdrawn}} + + + + + +
    + {{#each this.model.versions as |version|}} +
  • + + {{t 'preprints.detail.preprint_version_number' number=version.version}} + +
  • + {{else}} +
  • {{t 'preprints.detail.no_other_versions'}}
  • + {{/each}} +
+
+
+ {{else}} {{#if (and this.userIsContrib (not this.isPendingWithdrawal))}} {{/if}} - {{/unless}} + {{/if}} {{#if this.model.preprint.canCreateNewVersion}}
{{/if}} - + diff --git a/app/preprints/detail/template.hbs b/app/preprints/detail/template.hbs index fe2aea5a221..160151e1d94 100644 --- a/app/preprints/detail/template.hbs +++ b/app/preprints/detail/template.hbs @@ -233,6 +233,7 @@
{{/if}} From 5877c2f128b18714662fe808e62ca1c192e8db10 Mon Sep 17 00:00:00 2001 From: futa-ikeda <51409893+futa-ikeda@users.noreply.github.com> Date: Thu, 2 Jan 2025 15:55:00 -0500 Subject: [PATCH 09/11] Add link to version in DOI select (#2449) - Ticket: [ENG-6804] - Feature flag: n/a ## Purpose - Add a link to the version when selecting a different version in the DOI selection dropdown ## Summary of Changes - Add link to preprint DOI dropdown - Update tests --- app/preprints/-components/preprint-doi/component-test.ts | 8 ++++++++ app/preprints/-components/preprint-doi/template.hbs | 8 ++++++++ translations/en-us.yml | 1 + 3 files changed, 17 insertions(+) diff --git a/app/preprints/-components/preprint-doi/component-test.ts b/app/preprints/-components/preprint-doi/component-test.ts index 4c81f23ec8a..f22f44463c6 100644 --- a/app/preprints/-components/preprint-doi/component-test.ts +++ b/app/preprints/-components/preprint-doi/component-test.ts @@ -9,12 +9,15 @@ import { ModelInstance } from 'ember-cli-mirage'; import PreprintProviderModel from 'ember-osf-web/models/preprint-provider'; import PreprintModel from 'ember-osf-web/models/preprint'; import { ReviewsState } from 'ember-osf-web/models/provider'; +import { OsfLinkRouterStub } from 'ember-osf-web/tests/integration/helpers/osf-link-router-stub'; module('Integration | Component | preprint-doi', function(hooks) { setupRenderingTest(hooks); setupMirage(hooks); test('it renders', async function(assert) { + this.owner.unregister('service:router'); + this.owner.register('service:router', OsfLinkRouterStub); this.store = this.owner.lookup('service:store'); server.loadFixtures('preprint-providers'); const mirageProvider = server.schema.preprintProviders.find('osf') as ModelInstance; @@ -62,6 +65,9 @@ module('Integration | Component | preprint-doi', function(hooks) { .hasText('Version 2 (Rejected)', 'Dropdown has passed in currentVersiom selected by default'); assert.dom('[data-test-preprint-version="2"]').exists('Version 2 is shown'); + assert.dom('[data-test-view-version-link]').exists('View in OSF button exists'); + assert.dom('[data-test-view-version-link]').hasText('View version 2', 'View version link has correct text'); + // check version2 has DOI text assert.dom('[data-test-no-doi-text]').doesNotExist('No DOI text does not exist'); assert.dom('[data-test-unlinked-doi-url]').exists('Preprint DOI URL exists'); @@ -86,6 +92,8 @@ module('Integration | Component | preprint-doi', function(hooks) { }); test('it renders statuses', async function(assert) { + this.owner.unregister('service:router'); + this.owner.register('service:router', OsfLinkRouterStub); this.store = this.owner.lookup('service:store'); server.loadFixtures('preprint-providers'); const mirageProvider = server.schema.preprintProviders.find('osf') as ModelInstance; diff --git a/app/preprints/-components/preprint-doi/template.hbs b/app/preprints/-components/preprint-doi/template.hbs index 278c1336d92..05df9f3f7e2 100644 --- a/app/preprints/-components/preprint-doi/template.hbs +++ b/app/preprints/-components/preprint-doi/template.hbs @@ -27,6 +27,14 @@

{{t 'preprints.detail.no_versions'}}

{{/if}} {{#if this.selectedVersion}} + + {{t 'preprints.detail.view_version' number=this.selectedVersion.version}} + {{#if this.selectedVersion.preprintDoiUrl}} {{#if this.selectedVersion.preprintDoiCreated}} Date: Fri, 3 Jan 2025 11:40:12 -0500 Subject: [PATCH 10/11] Fix bug where link in doi section would not update (#2454) --- app/preprints/-components/preprint-doi/template.hbs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/preprints/-components/preprint-doi/template.hbs b/app/preprints/-components/preprint-doi/template.hbs index 05df9f3f7e2..2e4ad8cc6d1 100644 --- a/app/preprints/-components/preprint-doi/template.hbs +++ b/app/preprints/-components/preprint-doi/template.hbs @@ -31,7 +31,7 @@ data-test-view-version-link data-analytics-name='View version link' @route='preprints.detail' - @model={{this.selectedVersion}} + @models={{array @provider.id this.selectedVersion.id}} > {{t 'preprints.detail.view_version' number=this.selectedVersion.version}} From e7f936922cea4daf3d470e0972b32a18b5afe2de Mon Sep 17 00:00:00 2001 From: futa-ikeda <51409893+futa-ikeda@users.noreply.github.com> Date: Mon, 6 Jan 2025 11:14:42 -0500 Subject: [PATCH 11/11] [ENG-6814] Show toast message on 409 error (#2456) - Ticket: [ENG-6814] - Feature flag: n/a ## Purpose - Show helpful toast message if the request to create a new version returns a 409 error ## Summary of Changes - Fix logic for how to display toast error - Update template so the "Create new version" button is disabled when the task is running - Update page-not-found reroute logic to be more robust --- .../submit/preprint-state-machine/component.ts | 7 ++----- app/preprints/detail/controller.ts | 8 +++----- app/preprints/detail/route.ts | 6 ++++-- app/preprints/detail/template.hbs | 1 + translations/en-us.yml | 2 -- 5 files changed, 10 insertions(+), 14 deletions(-) diff --git a/app/preprints/-components/submit/preprint-state-machine/component.ts b/app/preprints/-components/submit/preprint-state-machine/component.ts index b079c25e15e..a6209047db7 100644 --- a/app/preprints/-components/submit/preprint-state-machine/component.ts +++ b/app/preprints/-components/submit/preprint-state-machine/component.ts @@ -251,11 +251,8 @@ export default class PreprintStateMachine extends Component{ this.router.transitionTo('preprints.detail', this.provider.id, this.preprint.id); } catch (e) { const errorTitle = this.intl.t('preprints.submit.new-version.error.title'); - let errorMessage = this.intl.t('preprints.submit.new-version.error.description', - { preprintWord: this.provider.documentType.singular }); - if (e.errors[0].status === 409) { // Conflict - errorMessage = this.intl.t('preprints.submit.new-version.error.conflict'); - } + const errorMessage = getApiErrorMessage(e); + captureException(e, { errorMessage }); this.toast.error(errorMessage, errorTitle); } return; diff --git a/app/preprints/detail/controller.ts b/app/preprints/detail/controller.ts index 6d86ac6b3bd..9a62324a24a 100644 --- a/app/preprints/detail/controller.ts +++ b/app/preprints/detail/controller.ts @@ -16,6 +16,7 @@ import { VersionStatusSimpleLabelKey } from 'ember-osf-web/models/preprint'; import { PreprintProviderReviewsWorkFlow, ReviewsState } from 'ember-osf-web/models/provider'; import CurrentUserService from 'ember-osf-web/services/current-user'; import Theme from 'ember-osf-web/services/theme'; +import captureException, { getApiErrorMessage } from 'ember-osf-web/utils/capture-exception'; /** @@ -159,11 +160,8 @@ export default class PrePrintsDetailController extends Controller { this.transitionToRoute('preprints.new-version', this.model.provider.id, newVersion.data.id); } catch (e) { const errorTitle = this.intl.t('preprints.submit.new-version.error.title'); - let errorMessage = this.intl.t('preprints.submit.new-version.error.description', - { preprintWord: this.model.provider.documentType.singular }); - if (e.errors[0].status === 409) { // Conflict - errorMessage = this.intl.t('preprints.submit.new-version.error.conflict'); - } + const errorMessage = getApiErrorMessage(e); + captureException(e, { errorMessage }); this.toast.error(errorMessage, errorTitle); } } diff --git a/app/preprints/detail/route.ts b/app/preprints/detail/route.ts index 37d2a77b374..938d3d347cf 100644 --- a/app/preprints/detail/route.ts +++ b/app/preprints/detail/route.ts @@ -4,6 +4,7 @@ import RouterService from '@ember/routing/router-service'; import { inject as service } from '@ember/service'; import { waitFor } from '@ember/test-waiters'; import { taskFor } from 'ember-concurrency-ts'; +import Intl from 'ember-intl/services/intl'; import { all, restartableTask } from 'ember-concurrency'; import moment from 'moment-timezone'; @@ -16,8 +17,9 @@ import MetaTags, { HeadTagDef } from 'ember-osf-web/services/meta-tags'; import Ready from 'ember-osf-web/services/ready'; import Theme from 'ember-osf-web/services/theme'; import captureException from 'ember-osf-web/utils/capture-exception'; +import { notFoundURL } from 'ember-osf-web/utils/clean-url'; import pathJoin from 'ember-osf-web/utils/path-join'; -import Intl from 'ember-intl/services/intl'; + import PrePrintsDetailController from './controller'; @@ -91,7 +93,7 @@ export default class PreprintsDetail extends Route { } catch (error) { captureException(error); - this.router.transitionTo('not-found', this.router.currentURL.slice(1)); + this.router.transitionTo('not-found', notFoundURL(window.location.pathname)); return null; } } diff --git a/app/preprints/detail/template.hbs b/app/preprints/detail/template.hbs index 160151e1d94..7575d06788b 100644 --- a/app/preprints/detail/template.hbs +++ b/app/preprints/detail/template.hbs @@ -69,6 +69,7 @@ data-test-create-new-version-button data-analytics-name='Create new version' local-class='btn btn-primary' + disabled={{this.createNewVersion.isRunning}} @layout='fake-link' {{on 'click' (perform this.createNewVersion)}} > diff --git a/translations/en-us.yml b/translations/en-us.yml index 2963037a350..9ec6a9550e3 100644 --- a/translations/en-us.yml +++ b/translations/en-us.yml @@ -1422,8 +1422,6 @@ preprints: latest-published: 'A new version can only be created from the latest published version of a {preprintWord}.' error: title: 'Error creating a new version' - description: 'An error occurred while creating a new version of this {preprintWord}. Please try again.' - conflict: 'There is already a new version of this {preprintWord} in progress. Please wait for the current version to be completed.' detail: abstract: 'Abstract' article_doi: 'Peer-reviewed Publication DOI'