diff --git a/lib/osf-components/addon/components/registries/update-dropdown/component.ts b/lib/osf-components/addon/components/registries/update-dropdown/component.ts index 02196129d78..3b4d03a7c45 100644 --- a/lib/osf-components/addon/components/registries/update-dropdown/component.ts +++ b/lib/osf-components/addon/components/registries/update-dropdown/component.ts @@ -1,29 +1,32 @@ import { action } from '@ember/object'; +import RouterService from '@ember/routing/router-service'; import { inject as service } from '@ember/service'; import { waitFor } from '@ember/test-waiters'; import Store from '@ember-data/store'; import Component from '@glimmer/component'; +import { tracked } from '@glimmer/tracking'; import { task } from 'ember-concurrency'; +import { taskFor } from 'ember-concurrency-ts'; import Intl from 'ember-intl/services/intl'; -import { QueryHasManyResult } from 'ember-osf-web/models/osf-model'; +import Media from 'ember-responsive'; +import Toast from 'ember-toastr/services/toast'; +import { QueryHasManyResult } from 'ember-osf-web/models/osf-model'; import RegistrationModel, { RegistrationReviewStates } from 'ember-osf-web/models/registration'; import SchemaResponseModel, { RevisionReviewStates } from 'ember-osf-web/models/schema-response'; import CurrentUserService from 'ember-osf-web/services/current-user'; -import Toast from 'ember-toastr/services/toast'; import captureException, { getApiErrorMessage } from 'ember-osf-web/utils/capture-exception'; -import RouterService from '@ember/routing/router-service'; -import { taskFor } from 'ember-concurrency-ts'; -import { tracked } from '@glimmer/tracking'; interface Args { registration: RegistrationModel; selectedRevisionId: string; + isModeratorMode: boolean; } export default class UpdateDropdown extends Component { @service currentUser!: CurrentUserService; @service intl!: Intl; + @service media!: Media; @service toast!: Toast; @service store!: Store; @service router!: RouterService; @@ -42,6 +45,10 @@ export default class UpdateDropdown extends Component { taskFor(this.getRevisionList).perform(); } + get isDesktop(): boolean { + return this.media.isDesktop || this.media.isJumbo; + } + get hasMore() { return this.currentPage <= this.totalPage; } @@ -53,7 +60,8 @@ export default class UpdateDropdown extends Component { } get shouldShowCreateButton(): boolean { - return this.args.registration.userHasAdminPermission + return Boolean(this.revisions.length) && !this.args.isModeratorMode + && this.args.registration.userHasAdminPermission && [ RegistrationReviewStates.Accepted, RegistrationReviewStates.Embargo, @@ -62,7 +70,8 @@ export default class UpdateDropdown extends Component { } get shouldShowUpdateLink(): boolean { - return this.args.registration.userHasReadPermission + return Boolean(this.revisions.length) && !this.args.isModeratorMode + && this.args.registration.userHasReadPermission && [ RegistrationReviewStates.Accepted, RegistrationReviewStates.Embargo, diff --git a/lib/osf-components/addon/components/registries/update-dropdown/template.hbs b/lib/osf-components/addon/components/registries/update-dropdown/template.hbs index 06abe74ba0e..a2352bdfc95 100644 --- a/lib/osf-components/addon/components/registries/update-dropdown/template.hbs +++ b/lib/osf-components/addon/components/registries/update-dropdown/template.hbs @@ -1,7 +1,7 @@
- {{#if revisionManager.node}} + {{#if revisionManager.registration}} - {{revisionManager.node.title}} > + {{revisionManager.registration.title}} > {{/if}}

diff --git a/mirage/views/review-action.ts b/mirage/views/review-action.ts index d2d4c7ef2e4..37407f46a99 100644 --- a/mirage/views/review-action.ts +++ b/mirage/views/review-action.ts @@ -1,6 +1,7 @@ import { HandlerContext, NormalizedRequestAttrs, Request, Schema } from 'ember-cli-mirage'; import { RegistrationReviewStates } from 'ember-osf-web/models/registration'; import ReviewActionModel, { 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>; @@ -22,6 +23,7 @@ export function createReviewAction(this: HandlerContext, schema: Schema, request case ReviewActionTrigger.AcceptSubmission: case ReviewActionTrigger.RejectWithdrawal: registration.reviewsState = RegistrationReviewStates.Accepted; + registration.revisionState = RevisionReviewStates.Approved; break; case ReviewActionTrigger.RejectSubmission: registration.reviewsState = RegistrationReviewStates.Rejected; diff --git a/tests/engines/registries/acceptance/edit-revision/revision-test.ts b/tests/engines/registries/acceptance/edit-revision/revision-test.ts index 579a0c47a80..772aa479327 100644 --- a/tests/engines/registries/acceptance/edit-revision/revision-test.ts +++ b/tests/engines/registries/acceptance/edit-revision/revision-test.ts @@ -173,6 +173,7 @@ module('Registries | Acceptance | registries revision', hooks => { // justification page assert.equal(currentRouteName(), 'registries.edit-revision.justification', 'Starts at justification page'); + assert.dom('[data-test-link-back-to-registration]').exists('Link back to registration is shown'); assert.dom('[data-test-link="justification"] > [data-test-icon]') .hasClass('fa-dot-circle', 'justification page is current page'); assert.dom('[data-test-link="1-first-page-of-test-schema"] > [data-test-icon]') diff --git a/tests/engines/registries/acceptance/overview/moderator-mode-test.ts b/tests/engines/registries/acceptance/overview/moderator-mode-test.ts index f0b4ea8f065..b0f9ee34f6b 100644 --- a/tests/engines/registries/acceptance/overview/moderator-mode-test.ts +++ b/tests/engines/registries/acceptance/overview/moderator-mode-test.ts @@ -38,6 +38,7 @@ module('Registries | Acceptance | overview.moderator-mode', hooks => { const registration = server.create('registration', { currentUserPermissions: Object.values(Permission), registrationSchema: server.schema.registrationSchemas.find('prereg_challenge'), + revisionState: RevisionReviewStates.RevisionPendingModeration, provider: this.provider, id: 'stayc', }, 'isPending', 'withReviewActions'); @@ -86,6 +87,7 @@ module('Registries | Acceptance | overview.moderator-mode', hooks => { const registration = server.create('registration', { currentUserPermissions: Object.values(Permission), registrationSchema: server.schema.registrationSchemas.find('prereg_challenge'), + revisionState: RevisionReviewStates.RevisionPendingModeration, provider: this.provider, id: 'stayc', }, 'isPending', 'withReviewActions'); @@ -107,6 +109,7 @@ module('Registries | Acceptance | overview.moderator-mode', hooks => { const registration = server.create('registration', { currentUserPermissions: Object.values(Permission), registrationSchema: server.schema.registrationSchemas.find('prereg_challenge'), + revisionState: RevisionReviewStates.Approved, provider: this.provider, id: 'stayc', }, 'isPendingWithdrawRequest', 'withReviewActions'); @@ -144,6 +147,7 @@ module('Registries | Acceptance | overview.moderator-mode', hooks => { const registration = server.create('registration', { currentUserPermissions: Object.values(Permission), registrationSchema: server.schema.registrationSchemas.find('prereg_challenge'), + revisionState: RevisionReviewStates.Approved, provider: this.provider, id: 'stayc', }, 'isPendingWithdraw', 'withReviewActions'); @@ -185,6 +189,7 @@ module('Registries | Acceptance | overview.moderator-mode', hooks => { const registration = server.create('registration', { currentUserPermissions: Object.values(Permission), registrationSchema: server.schema.registrationSchemas.find('prereg_challenge'), + revisionState: RevisionReviewStates.Approved, provider: this.provider, id: 'stayc', }, 'isPendingWithdraw', 'withReviewActions'); @@ -209,6 +214,7 @@ module('Registries | Acceptance | overview.moderator-mode', hooks => { const registration = server.create('registration', { currentUserPermissions: Object.values(Permission), registrationSchema: server.schema.registrationSchemas.find('prereg_challenge'), + revisionState: RevisionReviewStates.Approved, provider: this.provider, id: 'stayc', }, 'isPublic', 'withReviewActions'); @@ -247,6 +253,7 @@ module('Registries | Acceptance | overview.moderator-mode', hooks => { const registration = server.create('registration', { currentUserPermissions: Object.values(Permission), registrationSchema: server.schema.registrationSchemas.find('prereg_challenge'), + revisionState: RevisionReviewStates.Approved, provider: this.provider, id: 'stayc', }, 'isEmbargo', 'withReviewActions'); @@ -289,6 +296,7 @@ module('Registries | Acceptance | overview.moderator-mode', hooks => { const registration = server.create('registration', { currentUserPermissions: Object.values(Permission), registrationSchema: server.schema.registrationSchemas.find('prereg_challenge'), + revisionState: RevisionReviewStates.Approved, provider: this.provider, id: 'stayc', }, 'isPendingEmbargoTermination', 'withReviewActions'); diff --git a/tests/engines/registries/acceptance/overview/topbar-test.ts b/tests/engines/registries/acceptance/overview/topbar-test.ts index 8a08f0e352c..1777841566b 100644 --- a/tests/engines/registries/acceptance/overview/topbar-test.ts +++ b/tests/engines/registries/acceptance/overview/topbar-test.ts @@ -1,3 +1,4 @@ +import { camelize } from '@ember/string'; import { triggerEvent } from '@ember/test-helpers'; import { ModelInstance } from 'ember-cli-mirage'; import { setupMirage } from 'ember-cli-mirage/test-support'; @@ -12,6 +13,7 @@ import { RegistrationReviewStates } from 'ember-osf-web/models/registration'; import { click, visit } from 'ember-osf-web/tests/helpers'; import { setupEngineApplicationTest } from 'ember-osf-web/tests/helpers/engines'; import stripHtmlTags from 'ember-osf-web/utils/strip-html-tags'; +import { RevisionReviewStates } from 'ember-osf-web/models/schema-response'; const registrationStates: Record = { + approved: { + revisionState: RevisionReviewStates.Approved, + translationKey: RegistrationReviewStates.Accepted, + }, + unapproved: { + revisionState: RevisionReviewStates.Unapproved, + translationKey: RevisionReviewStates.Unapproved, + }, + inProgress: { + revisionState: RevisionReviewStates.RevisionInProgress, + translationKey: camelize(RevisionReviewStates.RevisionInProgress), + }, + revisionPendingModeration: { + revisionState: RevisionReviewStates.RevisionPendingModeration, + translationKey: camelize(RevisionReviewStates.RevisionPendingModeration), + }, +}; + module('Registries | Acceptance | overview.topbar', hooks => { setupEngineApplicationTest(hooks, 'registries'); setupMirage(hooks); @@ -199,10 +223,11 @@ module('Registries | Acceptance | overview.topbar', hooks => { assert.ok(Boolean(reg.forkIds.length)); }); - test('state description has correct text', async assert => { + test('reviews state description has correct text', async assert => { for (const [state, stateInfo] of Object.entries(registrationStates)) { const reg = server.create('registration', { registrationSchema: server.schema.registrationSchemas.find('prereg_challenge'), + revisionState: RevisionReviewStates.Approved, currentUserPermissions: Object.values(Permission), }, stateInfo.trait); await visit(`/${reg.id}/`); @@ -235,6 +260,36 @@ module('Registries | Acceptance | overview.topbar', hooks => { } }); + test('revision state description has correct text', async assert => { + for (const stateInfo of Object.values(revisionStates)) { + const reg = server.create('registration', { + registrationSchema: server.schema.registrationSchemas.find('prereg_challenge'), + currentUserPermissions: Object.values(Permission), + revisionState: stateInfo.revisionState, + }, 'isPublic'); + await visit(`/${reg.id}/`); + assert.dom('[data-test-state-button]').hasText( + t(`registries.overview.${stateInfo.translationKey}.text`).toString(), + ); + + await click('[data-test-state-button]'); + assert.dom('[data-test-state-admin-actions]').isVisible(); + assert.dom('[data-test-state-description-short]').exists(); + assert.dom('[data-test-state-description-short]').hasText( + t(`registries.overview.${stateInfo.translationKey}.short_description`).toString(), + ); + + assert.dom('[data-test-state-description-long]').hasText( + stripHtmlTags( + t(`registries.overview.${stateInfo.translationKey}.long_description`, { + projectUrl: 'fake.url', + }).toString(), + ), + ); + assert.dom('[data-test-state-icon]').hasClass('fa-eye'); + } + }); + test('non-moderators cannot see moderator top-bar', async assert => { const reg = server.create('registration', { diff --git a/translations/en-us.yml b/translations/en-us.yml index e357914e971..8e4407fa76a 100644 --- a/translations/en-us.yml +++ b/translations/en-us.yml @@ -1386,15 +1386,15 @@ registries: please_note: 'Please note:' email_support: 'Changes to any files (1) in the projects or components being registered, (2) uploaded or selected as prompt responses, including those connected through add-ons during archiving will result in archiving failure and loss of your registration timestamp. Please do not modify your files until after you have received email confirmation of archiving completion. If this registration has been archiving for more than 72 hours, please email {supportEmail} for assistance.' pendingRegistrationApproval: - text: 'Pending registration' + text: 'Pending approval' short_description: 'Pending registration approval' - long_description: 'This is a pending registration of this project, awaiting approval from project administrators. This registration will be final when all project administrators approve the registration or 48 hours pass, whichever comes first.' + long_description: 'This registration is waiting for approval from its contributors.' pendingEmbargoApproval: - text: 'Pending registration' + text: 'Pending approval' short_description: 'Pending embargo approval' - long_description: 'This registration is pending approval. It will be final and enter an embargo period when all project administrators approve the registration or 48 hours pass, whichever comes first. The embargo will keep the registration private until the embargo period ends.' + long_description: 'This registration is waiting for approval from its contributors. Once approved, the registration will remain private until the embargo ends.' pending: - text: 'Pending registration' + text: 'Pending moderation' short_description: 'Pending moderator approval' long_description: 'This registration is awaiting a decision by the registry moderators. An email will notify all registration contributors of the decision.' accepted: @@ -1413,15 +1413,27 @@ registries: pendingEmbargoTermination: text: 'Embargoed registration' short_description: 'Pending embargo termination' - long_description: 'This registration is embargoed. It will remain private until {embargoEndDate}. A request to make this registration public is pending.' + long_description: 'This registration is waiting for approval from its contributors to terminate its embargo and be made public.' pendingWithdrawRequest: - text: 'Public registration' + text: 'Pending withdrawal' short_description: 'Pending withdraw request' - long_description: 'This registration will be withdrawn when all project administrators approve the withdrawal.' + long_description: 'This registration is waiting for approval to be withdrawn by its contributors.' pendingWithdraw: - text: 'Public registration' + text: 'Pending withdrawal' short_description: 'Pending withdrawal moderation' - long_description: 'This registration is awaiting a withdrawal decision by the registry moderators. An email will notify all registration contributors of the decision.' + long_description: 'This registration is waiting for approval to be withdrawn by registry moderators.' + unapproved: + text: 'Update pending' + short_description: 'Update pending approval' + long_description: 'This registration has an update that is waiting for approval from its contributors. Updates will be made available once approved.' + inProgress: + text: 'Update in progress' + short_description: 'Updates being made' + long_description: 'This registration is currently being updated by its contributors. Updates will be made available once approved.' + pendingModeration: + text: 'Update pending review' + short_description: 'Update pending moderator approval' + long_description: 'This registration has an update that is waiting for moderation. Updates will be made available once approved.' bookmark: add: text: Bookmark