diff --git a/src/composables/useApp.js b/src/composables/useApp.js new file mode 100644 index 000000000..a1063717c --- /dev/null +++ b/src/composables/useApp.js @@ -0,0 +1,13 @@ +export function useApp() { + function isOJS() { + return pkp.context.app === 'ojs2'; + } + function isOMP() { + return pkp.context.app === 'omp'; + } + function isOPS() { + return pkp.context.app === 'ops'; + } + + return {isOJS, isOMP, isOPS}; +} diff --git a/src/composables/useDate.js b/src/composables/useDate.js index a9b6975ff..b1442136f 100644 --- a/src/composables/useDate.js +++ b/src/composables/useDate.js @@ -15,5 +15,9 @@ export function useDate() { return moment(dateString).format('DD-MM-YYYY'); } - return {calculateDaysBetweenDates, formatShortDate}; + function formatDateAndTime(dateString) { + return moment(dateString).format('YYYY-MM-DD hh:mm A'); + } + + return {calculateDaysBetweenDates, formatShortDate, formatDateAndTime}; } diff --git a/src/composables/useFetch.js b/src/composables/useFetch.js index f18ddb321..2a154c6db 100644 --- a/src/composables/useFetch.js +++ b/src/composables/useFetch.js @@ -1,6 +1,7 @@ import {ref, unref} from 'vue'; import {ofetch, createFetch} from 'ofetch'; import {useModalStore} from '@/stores/modalStore'; +import {useDebounceFn} from '@vueuse/core'; let ofetchInstance = ofetch; @@ -26,7 +27,8 @@ export function getCSRFToken() { * @param {Object} [options.body] - The request payload, typically used with 'POST', 'PUT', or 'DELETE' requests. * @param {Object} [options.headers] - Additional HTTP headers to be sent with the request. * @param {string} [options.method] - The HTTP method to be used for the request (e.g., 'GET', 'POST', etc.). - * + * @param {number} options.debouncedMs - When the fetch should be debounce, this defines the delay + * @returns {Object} An object containing several reactive properties and a method for performing the fetch operation: * @returns {Ref} return.data - A ref object containing the response data from the fetch operation. * @returns {Ref} return.validationError - A ref object containing validation error data, relevant when `expectValidationError` is true. @@ -62,7 +64,7 @@ export function useFetch(url, options = {}) { let lastRequestController = null; - async function fetch() { + async function _fetch() { if (lastRequestController) { // abort in-flight request lastRequestController.abort(); @@ -123,6 +125,10 @@ export function useFetch(url, options = {}) { } } + let fetch = _fetch; + if (options.debouncedMs) { + fetch = useDebounceFn(_fetch); + } return { data, isSuccess, diff --git a/src/managers/FileManager/fileManagerStore.js b/src/managers/FileManager/fileManagerStore.js index a44afdd00..a7868d363 100644 --- a/src/managers/FileManager/fileManagerStore.js +++ b/src/managers/FileManager/fileManagerStore.js @@ -1,6 +1,6 @@ import {defineComponentStore} from '@/utils/defineComponentStore'; -import {ref, computed} from 'vue'; +import {ref, computed, watch} from 'vue'; import {useFetch} from '@/composables/useFetch'; import {useUrl} from '@/composables/useUrl'; import {useFileManagerActions} from './useFileManagerActions'; @@ -26,16 +26,25 @@ export const useFileManagerStore = defineComponentStore( `submissions/${submissionId.value}/files`, ); + const queryParams = computed(() => ({ + fileStages: managerConfig.value.fileStage, + reviewRoundIds: props.reviewRoundId ? props.reviewRoundId : undefined, + })); + const {data, fetch: fetchFiles} = useFetch(filesApiUrl, { - query: { - fileStages: managerConfig.value.fileStage, - reviewRoundIds: props.reviewRoundId ? props.reviewRoundId : undefined, - }, + query: queryParams, }); const files = computed(() => data.value?.items || []); - fetchFiles(); + watch( + [filesApiUrl, queryParams], + () => { + files.value = null; + fetchFiles(); + }, + {immediate: true}, + ); /** Reload files when data on screen changes */ const {triggerDataChange} = useDataChanged(() => fetchFiles()); diff --git a/src/managers/GalleyManager/useGalleyManagerConfiguration.js b/src/managers/GalleyManager/useGalleyManagerConfiguration.js index dc641310a..0825e48b4 100644 --- a/src/managers/GalleyManager/useGalleyManagerConfiguration.js +++ b/src/managers/GalleyManager/useGalleyManagerConfiguration.js @@ -1,10 +1,11 @@ import {useLocalize} from '@/composables/useLocalize'; +import {useApp} from '@/composables/useApp'; export function useGalleyManagerConfiguration() { const {t} = useLocalize(); - + const {isOPS} = useApp(); function getGalleyGridComponent() { - if (pkp.context.app === 'ops') { + if (isOPS()) { return 'grid.preprintGalleys.PreprintGalleyGridHandler'; } else { return 'grid.articleGalleys.ArticleGalleyGridHandler'; diff --git a/src/pages/dashboard/dashboardPageStore.js b/src/pages/dashboard/dashboardPageStore.js index 7fb681a76..212317cc4 100644 --- a/src/pages/dashboard/dashboardPageStore.js +++ b/src/pages/dashboard/dashboardPageStore.js @@ -201,6 +201,8 @@ export const useDashboardPageStore = defineComponentStore( currentPage, pageSize: countPerPage, query: submissionsQuery, + // to avoid multiple fetch calls while view changing watchers triggers query params recalculation + debouncedMs: 2, }); watch( [submissionsUrl, submissionsQuery, currentPage], diff --git a/src/pages/workflow/components/primary/WorkflowListingEmails.vue b/src/pages/workflow/components/primary/WorkflowListingEmails.vue new file mode 100644 index 000000000..27e202ed9 --- /dev/null +++ b/src/pages/workflow/components/primary/WorkflowListingEmails.vue @@ -0,0 +1,90 @@ + + + diff --git a/src/pages/workflow/components/primary/WorkflowNotificationDisplay.vue b/src/pages/workflow/components/primary/WorkflowNotificationDisplay.vue index 1a0098a4b..bf73a93ed 100644 --- a/src/pages/workflow/components/primary/WorkflowNotificationDisplay.vue +++ b/src/pages/workflow/components/primary/WorkflowNotificationDisplay.vue @@ -1,52 +1,77 @@ diff --git a/src/pages/workflow/components/primary/WorkflowSubmissionStatus.vue b/src/pages/workflow/components/primary/WorkflowSubmissionStatus.vue index 61fc8a2bf..cb3108850 100644 --- a/src/pages/workflow/components/primary/WorkflowSubmissionStatus.vue +++ b/src/pages/workflow/components/primary/WorkflowSubmissionStatus.vue @@ -1,40 +1,117 @@ - diff --git a/src/pages/workflow/components/publication/WorkflowPublicationJats.vue b/src/pages/workflow/components/publication/WorkflowPublicationJats.vue index 58a01f1ce..fc65764c8 100644 --- a/src/pages/workflow/components/publication/WorkflowPublicationJats.vue +++ b/src/pages/workflow/components/publication/WorkflowPublicationJats.vue @@ -10,7 +10,7 @@ { - return [ - { - component: 'WorkflowChangeSubmissionLanguage', - props: { - submission, - canChangeSubmissionLanguage: false, - }, - }, - ]; - }, - getSecondaryItems: ({submission, selectedReviewRound, selectedStageId}) => { - const items = []; - return items; - }, - getActionsItems: ({submission, selectedReviewRound, selectedStageId}) => { + getPrimaryItems: ({ + submission, + permissions, + selectedStageId, + selectedReviewRound, + }) => { + if (!permissions.accessibleStages.includes(selectedStageId)) { + return { + shouldContinue: false, + items: [ + { + component: 'WorkflowPrimaryBasicMetadata', + props: { + body: t('user.authorization.accessibleWorkflowStage'), + }, + }, + ], + }; + } + const items = []; - return items; + + items.push({ + component: 'WorkflowChangeSubmissionLanguage', + props: { + submission, + canChangeSubmissionLanguage: false, + }, + }); + + const shouldContinue = !hasNotSubmissionStartedStage( + submission, + selectedStageId, + ); + + items.push({ + component: 'WorkflowSubmissionStatus', + props: { + submission, + selectedStageId, + selectedReviewRoundId: selectedReviewRound?.id, + }, + }); + + return { + shouldContinue, + items, + }; }, }, [pkp.const.WORKFLOW_STAGE_ID_SUBMISSION]: { @@ -85,38 +118,11 @@ export const WorkflowConfig = { [pkp.const.WORKFLOW_STAGE_ID_EXTERNAL_REVIEW]: { getPrimaryItems: ({submission, selectedStageId, selectedReviewRound}) => { const items = []; - if (!selectedReviewRound) { - return [ - { - component: 'WorkflowPrimaryBasicMetadata', - props: {body: t('editor.review.notInitiated')}, - }, - ]; - } - const {getCurrentReviewRound} = useSubmission(); - - const currentReviewRound = getCurrentReviewRound( - submission, - selectedStageId, - ); - - if (selectedReviewRound.round < currentReviewRound.round) { - items.push({ - component: 'WorkflowPrimaryBasicMetadata', - props: { - body: t( - 'editor.submission.workflowDecision.submission.reviewRound', - ), - }, - }); - } - if (selectedReviewRound.id === currentReviewRound.id) { - items.push({ - component: 'WorkflowReviewRoundStatus', - props: {reviewRound: selectedReviewRound}, - }); - } + items.push({ + component: 'WorkflowListingEmails', + props: {submission, selectedStageId: selectedStageId}, + }); if ( getOpenReviewAssignmentsForRound( @@ -158,20 +164,6 @@ export const WorkflowConfig = { getPrimaryItems: ({submission, selectedStageId, selectedReviewRound}) => { const items = []; - if ( - hasSubmissionPassedStage( - submission, - pkp.const.WORKFLOW_STAGE_ID_EDITING, - ) - ) { - items.push({ - component: 'WorkflowPrimaryBasicMetadata', - props: { - body: t('editor.submission.workflowDecision.submission.production'), - }, - }); - } - items.push({ component: 'DiscussionManager', props: { @@ -195,19 +187,6 @@ export const WorkflowConfig = { [pkp.const.WORKFLOW_STAGE_ID_PRODUCTION]: { getPrimaryItems: ({submission, selectedStageId, selectedReviewRound}) => { const items = []; - if (submission.status === pkp.const.STATUS_PUBLISHED) { - items.push({ - component: 'WorkflowPrimaryBasicMetadata', - props: { - body: t('editor.submission.workflowDecision.submission.published'), - }, - }); - } - - items.push({ - component: 'WorkflowNotificationDisplay', - props: {submission: submission}, - }); items.push({ component: 'DiscussionManager', @@ -236,7 +215,7 @@ export const PublicationConfig = { props: {}, }); } - return items; + return {items, shouldContinue: true}; }, getPublicationControlsLeft: ({ submission, @@ -253,15 +232,7 @@ export const PublicationConfig = { }, }); - return items; - }, - getPublicationControlsRight: ({ - submission, - selectedPublicationId, - selectedPublication, - }) => { - const items = []; - return items; + return {items, shouldContinue: true}; }, }, titleAbstract: { diff --git a/src/pages/workflow/composables/useWorkflowConfig/workflowConfigAuthorOMP.js b/src/pages/workflow/composables/useWorkflowConfig/workflowConfigAuthorOMP.js index 07fe8b848..5019eac46 100644 --- a/src/pages/workflow/composables/useWorkflowConfig/workflowConfigAuthorOMP.js +++ b/src/pages/workflow/composables/useWorkflowConfig/workflowConfigAuthorOMP.js @@ -5,8 +5,6 @@ import {useSubmission} from '@/composables/useSubmission'; const {hasSubmissionPassedStage, getOpenReviewAssignmentsForRound} = useSubmission(); -const {t} = useLocalize(); - export function getHeaderItems({ submission, selectedPublication, @@ -30,27 +28,7 @@ export function getHeaderItems({ } export const WorkflowConfig = { - common: { - getPrimaryItems: ({submission, permissions}) => { - return [ - { - component: 'WorkflowChangeSubmissionLanguage', - props: { - submission, - canChangeSubmissionLanguage: false, - }, - }, - ]; - }, - getSecondaryItems: ({submission, selectedReviewRound, selectedStageId}) => { - const items = []; - return items; - }, - getActionsItems: ({submission, selectedReviewRound, selectedStageId}) => { - const items = []; - return items; - }, - }, + common: {}, [pkp.const.WORKFLOW_STAGE_ID_SUBMISSION]: { getPrimaryItems: ({submission, selectedStageId, selectedReviewRound}) => { const items = []; @@ -85,39 +63,6 @@ export const WorkflowConfig = { [pkp.const.WORKFLOW_STAGE_ID_EXTERNAL_REVIEW]: { getPrimaryItems: ({submission, selectedStageId, selectedReviewRound}) => { const items = []; - if (!selectedReviewRound) { - return [ - { - component: 'WorkflowPrimaryBasicMetadata', - props: {body: t('editor.review.notInitiated')}, - }, - ]; - } - const {getCurrentReviewRound} = useSubmission(); - - const currentReviewRound = getCurrentReviewRound( - submission, - selectedStageId, - ); - - if (selectedReviewRound.round < currentReviewRound.round) { - items.push({ - component: 'WorkflowPrimaryBasicMetadata', - props: { - body: t( - 'editor.submission.workflowDecision.submission.reviewRound', - ), - }, - }); - } - - if (selectedReviewRound.id === currentReviewRound.id) { - items.push({ - component: 'WorkflowReviewRoundStatus', - props: {reviewRound: selectedReviewRound}, - }); - } - if ( getOpenReviewAssignmentsForRound( submission.reviewAssignments, @@ -158,20 +103,6 @@ export const WorkflowConfig = { getPrimaryItems: ({submission, selectedStageId, selectedReviewRound}) => { const items = []; - if ( - hasSubmissionPassedStage( - submission, - pkp.const.WORKFLOW_STAGE_ID_EDITING, - ) - ) { - items.push({ - component: 'WorkflowPrimaryBasicMetadata', - props: { - body: t('editor.submission.workflowDecision.submission.production'), - }, - }); - } - items.push({ component: 'DiscussionManager', props: { @@ -193,16 +124,8 @@ export const WorkflowConfig = { }, }, [pkp.const.WORKFLOW_STAGE_ID_PRODUCTION]: { - getPrimaryItems: ({submission, selectedStageId, selectedReviewRound}) => { + getPrimaryItems: ({submission, selectedStageId}) => { const items = []; - if (submission.status === pkp.const.STATUS_PUBLISHED) { - items.push({ - component: 'WorkflowPrimaryBasicMetadata', - props: { - body: t('editor.submission.workflowDecision.submission.published'), - }, - }); - } items.push({ component: 'WorkflowNotificationDisplay', @@ -223,85 +146,6 @@ export const WorkflowConfig = { }; export const PublicationConfig = { - common: { - getPrimaryItems: ({ - submission, - selectedPublicationId, - selectedPublication, - }) => { - const items = []; - if (selectedPublication.status === pkp.const.STATUS_PUBLISHED) { - items.push({ - component: 'WorkflowPublicationEditDisabled', - props: {}, - }); - } - return items; - }, - getPublicationControlsLeft: ({ - submission, - selectedPublicationId, - selectedPublication, - }) => { - const items = []; - - items.push({ - component: 'WorkflowPublicationVersionControl', - props: { - submission, - selectedPublicationId: selectedPublicationId, - }, - }); - - return items; - }, - getPublicationControlsRight: ({ - submission, - selectedPublicationId, - selectedPublication, - }) => { - const items = []; - return items; - }, - }, - titleAbstract: { - getPrimaryItems: ({ - submission, - selectedPublication, - pageInitConfig, - permissions, - }) => { - return [ - { - component: 'WorkflowPublicationForm', - props: { - formName: 'titleAbstract', - submission, - publication: selectedPublication, - canEdit: permissions.canEditPublication, - }, - }, - ]; - }, - }, - contributors: { - getPrimaryItems: ({ - submission, - selectedPublication, - pageInitConfig, - permissions, - }) => { - return [ - { - component: 'ContributorManager', - props: { - submission: submission, - publication: selectedPublication, - }, - }, - ]; - }, - }, chapters: { getPrimaryItems: ({ submission, @@ -320,60 +164,4 @@ export const PublicationConfig = { ]; }, }, - - metadata: { - getPrimaryItems: ({ - submission, - selectedPublication, - pageInitConfig, - permissions, - }) => { - return [ - { - component: 'WorkflowPublicationForm', - props: { - formName: 'metadata', - submission, - publication: selectedPublication, - noFieldsMessage: 'No metadata fields are currently enabled.', - canEdit: permissions.canEditPublication, - }, - }, - ]; - }, - }, - citations: { - getPrimaryItems: ({ - submission, - selectedPublication, - pageInitConfig, - permissions, - }) => { - return [ - { - component: 'WorkflowPublicationForm', - props: { - formName: 'reference', - submission, - publication: selectedPublication, - canEdit: permissions.canEditPublication, - }, - }, - ]; - }, - }, - galleys: { - getPrimaryItems: ({submission, selectedPublication, permissions}) => { - return [ - { - component: 'GalleyManager', - props: { - submission, - publication: selectedPublication, - canEdit: permissions.canEditPublication, - }, - }, - ]; - }, - }, }; diff --git a/src/pages/workflow/composables/useWorkflowConfig/workflowConfigAuthorOPS.js b/src/pages/workflow/composables/useWorkflowConfig/workflowConfigAuthorOPS.js index 8883ff887..81d6a2335 100644 --- a/src/pages/workflow/composables/useWorkflowConfig/workflowConfigAuthorOPS.js +++ b/src/pages/workflow/composables/useWorkflowConfig/workflowConfigAuthorOPS.js @@ -27,20 +27,6 @@ export const WorkflowConfig = {}; export const PublicationConfig = { common: { - getPrimaryItems: ({ - submission, - selectedPublicationId, - selectedPublication, - }) => { - const items = []; - if (selectedPublication.status === pkp.const.STATUS_PUBLISHED) { - items.push({ - component: 'WorkflowPublicationEditDisabled', - props: {}, - }); - } - return items; - }, getPublicationControlsLeft: ({ submission, selectedPublicationId, @@ -64,107 +50,6 @@ export const PublicationConfig = { return items; }, - getPublicationControlsRight: ({ - submission, - selectedPublicationId, - selectedPublication, - }) => { - const items = []; - return items; - }, - }, - titleAbstract: { - getPrimaryItems: ({ - submission, - selectedPublication, - pageInitConfig, - permissions, - }) => { - return [ - { - component: 'WorkflowPublicationForm', - props: { - formName: 'titleAbstract', - submission, - publication: selectedPublication, - canEdit: permissions.canEditPublication, - }, - }, - ]; - }, - }, - contributors: { - getPrimaryItems: ({ - submission, - selectedPublication, - pageInitConfig, - permissions, - }) => { - return [ - { - component: 'ContributorManager', - props: { - submission: submission, - publication: selectedPublication, - }, - }, - ]; - }, - }, - metadata: { - getPrimaryItems: ({ - submission, - selectedPublication, - pageInitConfig, - permissions, - }) => { - return [ - { - component: 'WorkflowPublicationForm', - props: { - formName: 'metadata', - submission, - publication: selectedPublication, - noFieldsMessage: 'No metadata fields are currently enabled.', - canEdit: permissions.canEditPublication, - }, - }, - ]; - }, - }, - citations: { - getPrimaryItems: ({ - submission, - selectedPublication, - pageInitConfig, - permissions, - }) => { - return [ - { - component: 'WorkflowPublicationForm', - props: { - formName: 'reference', - submission, - publication: selectedPublication, - canEdit: permissions.canEditPublication, - }, - }, - ]; - }, - }, - galleys: { - getPrimaryItems: ({submission, selectedPublication, permissions}) => { - return [ - { - component: 'GalleyManager', - props: { - submission, - publication: selectedPublication, - canEditPublication: permissions.canEditPublication, - }, - }, - ]; - }, }, discussions: { getPrimaryItems: ({submission, selectedPublication, permissions}) => { diff --git a/src/pages/workflow/composables/useWorkflowConfig/workflowConfigEditorialOJS.js b/src/pages/workflow/composables/useWorkflowConfig/workflowConfigEditorialOJS.js index 5b0bd18cf..c6e462e7a 100644 --- a/src/pages/workflow/composables/useWorkflowConfig/workflowConfigEditorialOJS.js +++ b/src/pages/workflow/composables/useWorkflowConfig/workflowConfigEditorialOJS.js @@ -3,20 +3,16 @@ import {Actions} from '../useWorkflowActions'; import {useSubmission} from '@/composables/useSubmission'; import {Actions as WorkflowActions} from '../useWorkflowActions'; import {Actions as DecisionActions} from '../useWorkflowDecisions'; +import {addItemIf} from './workflowConfigHelpers'; const { hasSubmissionPassedStage, getActiveStage, getStageById, isDecisionAvailable, + hasNotSubmissionStartedStage, } = useSubmission(); const {t} = useLocalize(); -export function addItemIf(items, item, condition) { - if (condition) { - items.push(item); - } -} - export function getHeaderItems({ submission, selectedPublication, @@ -68,31 +64,60 @@ export function getHeaderItems({ export const WorkflowConfig = { common: { - getPrimaryItems: ({submission, permissions}) => { - return [ - { - component: 'WorkflowChangeSubmissionLanguage', - props: { - submission, - canChangeSubmissionLanguage: false, - }, + getPrimaryItems: ({ + submission, + permissions, + selectedStageId, + selectedReviewRound, + }) => { + if (!permissions.accessibleStages.includes(selectedStageId)) { + return { + shouldContinue: false, + items: [ + { + component: 'WorkflowPrimaryBasicMetadata', + props: { + body: t('user.authorization.accessibleWorkflowStage'), + }, + }, + ], + }; + } + + const items = []; + + items.push({ + component: 'WorkflowChangeSubmissionLanguage', + props: { + submission, + canChangeSubmissionLanguage: false, }, - ]; + }); + + const shouldContinue = !hasNotSubmissionStartedStage( + submission, + selectedStageId, + ); + + items.push({ + component: 'WorkflowSubmissionStatus', + props: { + submission, + selectedStageId, + selectedReviewRoundId: selectedReviewRound?.id, + }, + }); + + return { + shouldContinue, + items, + }; }, }, [pkp.const.WORKFLOW_STAGE_ID_SUBMISSION]: { getPrimaryItems: ({submission, selectedStageId, selectedReviewRound}) => { const items = []; - if ( - hasSubmissionPassedStage( - submission, - pkp.const.WORKFLOW_STAGE_ID_SUBMISSION, - ) - ) { - items.push({component: 'SubmissionStatus', props: {submission}}); - } - items.push({ component: 'FileManager', props: { @@ -190,38 +215,6 @@ export const WorkflowConfig = { [pkp.const.WORKFLOW_STAGE_ID_EXTERNAL_REVIEW]: { getPrimaryItems: ({submission, selectedStageId, selectedReviewRound}) => { const items = []; - if (!selectedReviewRound) { - return [ - { - component: 'WorkflowPrimaryBasicMetadata', - props: {body: t('editor.review.notInitiated')}, - }, - ]; - } - const {getCurrentReviewRound} = useSubmission(); - - const currentReviewRound = getCurrentReviewRound( - submission, - selectedStageId, - ); - - if (selectedReviewRound.round < currentReviewRound.round) { - items.push({ - component: 'WorkflowPrimaryBasicMetadata', - props: { - body: t( - 'editor.submission.workflowDecision.submission.reviewRound', - ), - }, - }); - } - - if (selectedReviewRound.id === currentReviewRound.id) { - items.push({ - component: 'WorkflowReviewRoundStatus', - props: {reviewRound: selectedReviewRound}, - }); - } items.push({ component: 'FileManager', @@ -263,6 +256,9 @@ export const WorkflowConfig = { }, getSecondaryItems: ({submission, selectedReviewRound, selectedStageId}) => { const items = []; + if (!selectedReviewRound) { + return []; + } // TODO add isDecidingEditor boolean to api to make it more accurate const selectedStage = getStageById(submission, selectedStageId); @@ -289,6 +285,11 @@ export const WorkflowConfig = { }, getActionItems: ({submission, selectedStageId, selectedReviewRound}) => { let items = []; + + if (!selectedReviewRound) { + return []; + } + const {getCurrentReviewRound} = useSubmission(); const currentReviewRound = getCurrentReviewRound( @@ -417,19 +418,10 @@ export const WorkflowConfig = { getPrimaryItems: ({submission, selectedStageId, selectedReviewRound}) => { const items = []; - if ( - hasSubmissionPassedStage( - submission, - pkp.const.WORKFLOW_STAGE_ID_EDITING, - ) - ) { - items.push({ - component: 'WorkflowPrimaryBasicMetadata', - props: { - body: t('editor.submission.workflowDecision.submission.production'), - }, - }); - } + items.push({ + component: 'WorkflowNotificationDisplay', + props: {submission: submission}, + }); items.push({ component: 'FileManager', @@ -461,6 +453,7 @@ export const WorkflowConfig = { }, getSecondaryItems: ({submission, selectedReviewRound, selectedStageId}) => { const items = []; + items.push({ component: 'ParticipantManager', props: { @@ -510,15 +503,6 @@ export const WorkflowConfig = { [pkp.const.WORKFLOW_STAGE_ID_PRODUCTION]: { getPrimaryItems: ({submission, selectedStageId, selectedReviewRound}) => { const items = []; - if (submission.status === pkp.const.STATUS_PUBLISHED) { - items.push({ - component: 'WorkflowPrimaryBasicMetadata', - props: { - body: t('editor.submission.workflowDecision.submission.published'), - }, - }); - } - items.push({ component: 'WorkflowNotificationDisplay', props: {submission: submission}, @@ -609,7 +593,7 @@ export const PublicationConfig = { props: {}, }); } - return items; + return {items, shouldContinue: true}; }, getPublicationControlsLeft: ({ submission, @@ -641,7 +625,7 @@ export const PublicationConfig = { }, }); - return items; + return {items, shouldContinue: true}; }, getPublicationControlsRight: ({ submission, @@ -729,7 +713,7 @@ export const PublicationConfig = { } } - return items; + return {items, shouldContinue: true}; }, }, titleAbstract: { diff --git a/src/pages/workflow/composables/useWorkflowConfig/workflowConfigEditorialOMP.js b/src/pages/workflow/composables/useWorkflowConfig/workflowConfigEditorialOMP.js index 41b455010..185ea4d70 100644 --- a/src/pages/workflow/composables/useWorkflowConfig/workflowConfigEditorialOMP.js +++ b/src/pages/workflow/composables/useWorkflowConfig/workflowConfigEditorialOMP.js @@ -2,10 +2,11 @@ import {useLocalize} from '@/composables/useLocalize'; import {Actions} from '../useWorkflowActions'; import {useSubmission} from '@/composables/useSubmission'; import {Actions as DecisionActions} from '../useWorkflowDecisions'; -import {addItemIf} from './workflowConfigEditorialOJS'; +import {addItemIf} from './workflowConfigHelpers'; const {hasSubmissionPassedStage, getStageById, isDecisionAvailable} = useSubmission(); const {t} = useLocalize(); + export function getHeaderItems({ submission, selectedPublication, @@ -57,50 +58,8 @@ export function getHeaderItems({ export const WorkflowConfig = { [pkp.const.WORKFLOW_STAGE_ID_SUBMISSION]: { - getPrimaryItems: ({submission, selectedStageId, selectedReviewRound}) => { - const items = []; - - if ( - hasSubmissionPassedStage( - submission, - pkp.const.WORKFLOW_STAGE_ID_SUBMISSION, - ) - ) { - items.push({component: 'SubmissionStatus', props: {submission}}); - } - - items.push({ - component: 'FileManager', - props: { - namespace: 'SUBMISSION_FILES', - submission: submission, - submissionStageId: selectedStageId, - }, - }); - - items.push({ - component: 'DiscussionManager', - props: {submissionId: submission.id, stageId: selectedStageId}, - }); - - return items; - }, - getSecondaryItems: ({submission, selectedReviewRound, selectedStageId}) => { - const items = []; - items.push({ - component: 'ParticipantManager', - props: { - submission, - submissionStageId: selectedStageId, - }, - }); - - return items; - }, - getActionItems: ({submission, selectedStageId, selectedReviewRound}) => { const items = []; - addItemIf( items, { @@ -181,38 +140,6 @@ export const WorkflowConfig = { [pkp.const.WORKFLOW_STAGE_ID_INTERNAL_REVIEW]: { getPrimaryItems: ({submission, selectedStageId, selectedReviewRound}) => { const items = []; - if (!selectedReviewRound) { - return [ - { - component: 'WorkflowPrimaryBasicMetadata', - props: {body: t('editor.review.notInitiated')}, - }, - ]; - } - const {getCurrentReviewRound} = useSubmission(); - - const currentReviewRound = getCurrentReviewRound( - submission, - selectedStageId, - ); - - if (selectedReviewRound.round < currentReviewRound.round) { - items.push({ - component: 'WorkflowPrimaryBasicMetadata', - props: { - body: t( - 'editor.submission.workflowDecision.submission.reviewRound', - ), - }, - }); - } - - if (selectedReviewRound.id === currentReviewRound.id) { - items.push({ - component: 'WorkflowReviewRoundStatus', - props: {reviewRound: selectedReviewRound}, - }); - } items.push({ component: 'FileManager', @@ -254,6 +181,9 @@ export const WorkflowConfig = { }, getSecondaryItems: ({submission, selectedReviewRound, selectedStageId}) => { const items = []; + if (!selectedReviewRound) { + return []; + } // TODO add isDecidingEditor boolean to api to make it more accurate const selectedStage = getStageById(submission, selectedStageId); @@ -356,6 +286,22 @@ export const WorkflowConfig = { isDecisionAvailable(submission, pkp.const.DECISION_ACCEPT_INTERNAL), ); + addItemIf( + items, + { + component: 'WorkflowActionButton', + props: { + label: t('editor.submission.createNewRound'), + action: DecisionActions.DECISION_NEW_INTERNAL_ROUND, + actionArgs, + }, + }, + isDecisionAvailable( + submission, + pkp.const.DECISION_NEW_INTERNAL_ROUND, + ), + ); + addItemIf( items, { @@ -452,52 +398,6 @@ export const MarketingConfig = { export const PublicationConfig = { common: { - getPrimaryItems: ({ - submission, - selectedPublicationId, - selectedPublication, - }) => { - const items = []; - if (selectedPublication.status === pkp.const.STATUS_PUBLISHED) { - items.push({ - component: 'WorkflowPublicationEditDisabled', - props: {}, - }); - } - return items; - }, - getPublicationControlsLeft: ({ - submission, - selectedPublicationId, - selectedPublication, - permissions, - }) => { - const items = []; - - if ( - submission.status !== pkp.const.STATUS_PUBLISHED && - submission.publications.length < 2 - ) { - items.push({ - component: 'WorkflowChangeSubmissionLanguage', - props: { - submission, - canChangeSubmissionLanguage: - permissions.canChangeSubmissionLanguage, - }, - }); - } - - items.push({ - component: 'WorkflowPublicationVersionControl', - props: { - submission, - selectedPublicationId: selectedPublicationId, - }, - }); - - return items; - }, getPublicationControlsRight: ({ submission, selectedPublicationId, @@ -534,8 +434,7 @@ export const PublicationConfig = { label: t('publication.publish'), isSecondary: true, - action: - Actions.WORKFLOW_ASSIGN_TO_ISSUE_AND_SCHEDULE_FOR_PUBLICATION, + action: Actions.WORKFLOW_SCHEDULE_FOR_PUBLICATION, }, }); } else if (selectedPublication.status === pkp.const.STATUS_SCHEDULED) { @@ -581,46 +480,7 @@ export const PublicationConfig = { } } - return items; - }, - }, - titleAbstract: { - getPrimaryItems: ({ - submission, - selectedPublication, - pageInitConfig, - permissions, - }) => { - return [ - { - component: 'WorkflowPublicationForm', - props: { - formName: 'titleAbstract', - submission, - publication: selectedPublication, - canEdit: permissions.canEditPublication, - }, - }, - ]; - }, - }, - contributors: { - getPrimaryItems: ({ - submission, - selectedPublication, - pageInitConfig, - permissions, - }) => { - return [ - { - component: 'ContributorManager', - props: { - submission: submission, - publication: selectedPublication, - canEditPublication: permissions.canEditPublication, - }, - }, - ]; + return {items, shouldContinue: true}; }, }, chapters: { @@ -642,68 +502,6 @@ export const PublicationConfig = { }, }, - metadata: { - getPrimaryItems: ({ - submission, - selectedPublication, - pageInitConfig, - permissions, - }) => { - return [ - { - component: 'WorkflowPublicationForm', - props: { - formName: 'metadata', - submission, - publication: selectedPublication, - noFieldsMessage: 'No metadata fields are currently enabled.', - canEdit: permissions.canEditPublication, - }, - }, - ]; - }, - }, - - citations: { - getPrimaryItems: ({ - submission, - selectedPublication, - pageInitConfig, - permissions, - }) => { - return [ - { - component: 'WorkflowPublicationForm', - props: { - formName: 'reference', - submission, - publication: selectedPublication, - canEdit: permissions.canEditPublication, - }, - }, - ]; - }, - }, - identifiers: { - getPrimaryItems: ({ - submission, - selectedPublication, - pageInitConfig, - permissions, - }) => { - return [ - { - component: 'WorkflowPublicationForm', - props: { - formName: 'identifier', - submission, - publication: selectedPublication, - canEdit: permissions.canEditPublication, - }, - }, - ]; - }, - }, publicationFormats: { getPrimaryItems: ({ submission, @@ -743,25 +541,4 @@ export const PublicationConfig = { ]; }, }, - - license: { - getPrimaryItems: ({ - submission, - selectedPublication, - pageInitConfig, - permissions, - }) => { - return [ - { - component: 'WorkflowPublicationForm', - props: { - formName: 'permissionDisclosure', - submission, - publication: selectedPublication, - canEdit: permissions.canEditPublication, - }, - }, - ]; - }, - }, }; diff --git a/src/pages/workflow/composables/useWorkflowConfig/workflowConfigEditorialOPS.js b/src/pages/workflow/composables/useWorkflowConfig/workflowConfigEditorialOPS.js index d7a5dc6a1..ed635faf0 100644 --- a/src/pages/workflow/composables/useWorkflowConfig/workflowConfigEditorialOPS.js +++ b/src/pages/workflow/composables/useWorkflowConfig/workflowConfigEditorialOPS.js @@ -2,7 +2,8 @@ import {useLocalize} from '@/composables/useLocalize'; import {Actions} from '../useWorkflowActions'; import {useSubmission} from '@/composables/useSubmission'; import {Actions as DecisionActions} from '../useWorkflowDecisions'; -import {addItemIf} from './workflowConfigEditorialOJS'; +import {addItemIf} from './workflowConfigHelpers'; + const {hasSubmissionPassedStage, isDecisionAvailable, getActiveStage} = useSubmission(); const {t} = useLocalize(); @@ -50,30 +51,9 @@ export function getHeaderItems({ } export const WorkflowConfig = { - common: { - getPrimaryItems: ({submission, permissions}) => { - return [ - { - component: 'WorkflowChangeSubmissionLanguage', - props: { - submission, - canChangeSubmissionLanguage: false, - }, - }, - ]; - }, - }, [pkp.const.WORKFLOW_STAGE_ID_PRODUCTION]: { getPrimaryItems: ({submission, selectedStageId, selectedReviewRound}) => { const items = []; - if (submission.status === pkp.const.STATUS_PUBLISHED) { - items.push({ - component: 'WorkflowPrimaryBasicMetadata', - props: { - body: t('editor.submission.workflowDecision.submission.published'), - }, - }); - } items.push({ component: 'WorkflowNotificationDisplay', @@ -90,18 +70,6 @@ export const WorkflowConfig = { return items; }, - getSecondaryItems: ({submission, selectedReviewRound, selectedStageId}) => { - const items = []; - items.push({ - component: 'ParticipantManager', - props: { - submission, - submissionStageId: selectedStageId, - }, - }); - - return items; - }, getActionItems: ({submission, selectedStageId, selectedReviewRound}) => { const items = []; @@ -157,20 +125,6 @@ export const WorkflowConfig = { export const PublicationConfig = { common: { - getPrimaryItems: ({ - submission, - selectedPublicationId, - selectedPublication, - }) => { - const items = []; - if (selectedPublication.status === pkp.const.STATUS_PUBLISHED) { - items.push({ - component: 'WorkflowPublicationEditDisabled', - props: {}, - }); - } - return items; - }, getPublicationControlsLeft: ({ submission, selectedPublicationId, @@ -208,7 +162,7 @@ export const PublicationConfig = { }, ]); - return items; + return {items, shouldContinue: true}; }, getPublicationControlsRight: ({ submission, @@ -292,160 +246,7 @@ export const PublicationConfig = { } } - return items; - }, - }, - titleAbstract: { - getPrimaryItems: ({ - submission, - selectedPublication, - pageInitConfig, - permissions, - }) => { - return [ - { - component: 'WorkflowPublicationForm', - props: { - formName: 'titleAbstract', - submission, - publication: selectedPublication, - canEdit: permissions.canEditPublication, - }, - }, - ]; - }, - }, - contributors: { - getPrimaryItems: ({ - submission, - selectedPublication, - pageInitConfig, - permissions, - }) => { - return [ - { - component: 'ContributorManager', - props: { - submission: submission, - publication: selectedPublication, - canEdit: permissions.canEditPublication, - }, - }, - ]; - }, - }, - metadata: { - getPrimaryItems: ({ - submission, - selectedPublication, - pageInitConfig, - permissions, - }) => { - return [ - { - component: 'WorkflowPublicationForm', - props: { - formName: 'metadata', - submission, - publication: selectedPublication, - noFieldsMessage: 'No metadata fields are currently enabled.', - canEdit: permissions.canEditPublication, - }, - }, - ]; - }, - }, - citations: { - getPrimaryItems: ({ - submission, - selectedPublication, - pageInitConfig, - permissions, - }) => { - return [ - { - component: 'WorkflowPublicationForm', - props: { - formName: 'reference', - submission, - publication: selectedPublication, - canEdit: permissions.canEditPublication, - }, - }, - ]; - }, - }, - identifiers: { - getPrimaryItems: ({ - submission, - selectedPublication, - pageInitConfig, - permissions, - }) => { - return [ - { - component: 'WorkflowPublicationForm', - props: { - formName: 'identifier', - submission, - publication: selectedPublication, - canEdit: permissions.canEditPublication, - }, - }, - ]; - }, - }, - jats: { - getPrimaryItems: ({ - submission, - selectedPublication, - pageInitConfig, - permissions, - }) => { - return [ - { - component: 'WorkflowPublicationJats', - props: { - canEdit: permissions.canEditPublication, - submission, - publication: selectedPublication, - }, - }, - ]; - }, - }, - galleys: { - getPrimaryItems: ({submission, selectedPublication, permissions}) => { - return [ - { - component: 'GalleyManager', - props: { - submission, - publication: selectedPublication, - canEdit: permissions.canEditPublication, - }, - }, - ]; - }, - }, - license: { - getPrimaryItems: ({ - submission, - selectedPublication, - pageInitConfig, - permissions, - }) => { - return [ - { - component: 'WorkflowPublicationForm', - props: { - formName: 'permissionDisclosure', - submission, - publication: selectedPublication, - canEdit: permissions.canEditPublication, - }, - }, - ]; + return {items, shouldContinue: true}; }, }, preprintEntry: { diff --git a/src/pages/workflow/composables/useWorkflowConfig/workflowConfigHelpers.js b/src/pages/workflow/composables/useWorkflowConfig/workflowConfigHelpers.js new file mode 100644 index 000000000..00b320dbf --- /dev/null +++ b/src/pages/workflow/composables/useWorkflowConfig/workflowConfigHelpers.js @@ -0,0 +1,26 @@ +// Useful for some common functionality thats covered in Config.common, +// like permissions or Stage not initiated +export function consolidateCommonAndSpecificItems( + Config, + configItemKey, + getterFnName, + itemsArgs, +) { + const commonItems = Config?.common?.[getterFnName]?.(itemsArgs); + + // early return, if common logic decides there should not be any specific items displayed + if (commonItems?.shouldContinue === false) { + return commonItems?.items || []; + } + + return [ + ...(commonItems?.items || []), + ...(Config?.[configItemKey]?.[getterFnName]?.(itemsArgs) || []), + ]; +} + +export function addItemIf(items, item, condition) { + if (condition) { + items.push(item); + } +} diff --git a/src/pages/workflow/workflowStoreOJS.js b/src/pages/workflow/workflowStoreOJS.js index 3860c9aef..9103a4f14 100644 --- a/src/pages/workflow/workflowStoreOJS.js +++ b/src/pages/workflow/workflowStoreOJS.js @@ -34,13 +34,13 @@ import WorkflowActionButton from './components/action/WorkflowActionButton.vue'; import WorkflowRecommendOnlyControls from './components/action/WorkflowRecommendOnlyControls.vue'; import WorkflowRecommendOnlyListingRecommendations from './components/secondary/WorkflowRecommendOnlyListingRecommendations.vue'; import WorkflowNotificationDisplay from './components/primary/WorkflowNotificationDisplay.vue'; +import WorkflowListingEmails from './components/primary/WorkflowListingEmails.vue'; import WorkflowPaymentDropdown from './components/header/WorkflowPaymentDropdown.vue'; import WorkflowPublicationForm from './components/publication/WorkflowPublicationForm.vue'; import WorkflowPublicationJats from './components/publication/WorkflowPublicationJats.vue'; import WorkflowPublicationVersionControl from './components/publication/WorkflowPublicationVersionControl.vue'; import WorkflowChangeSubmissionLanguage from './components/publication/WorkflowChangeSubmissionLanguage.vue'; import WorkflowPrimaryBasicMetadata from './components/primary/WorkflowPrimaryBasicMetadata.vue'; -import WorkflowReviewRoundStatus from './components/primary/WorkflowReviewRoundStatus.vue'; import WorkflowSubmissionStatus from './components/primary/WorkflowSubmissionStatus.vue'; import WorkflowPublicationEditDisabled from './components/publication/WorkflowPublicationEditDisabled.vue'; @@ -203,9 +203,9 @@ export const useWorkflowStore = defineComponentStore('workflow', (props) => { WorkflowRecommendOnlyControls, WorkflowRecommendOnlyListingRecommendations, WorkflowNotificationDisplay, + WorkflowListingEmails, WorkflowPaymentDropdown, WorkflowPrimaryBasicMetadata, - WorkflowReviewRoundStatus, WorkflowPublicationForm, WorkflowPublicationJats, WorkflowPublicationVersionControl, diff --git a/src/pages/workflow/workflowStoreOMP.js b/src/pages/workflow/workflowStoreOMP.js index 16a82cae7..62d4da1b5 100644 --- a/src/pages/workflow/workflowStoreOMP.js +++ b/src/pages/workflow/workflowStoreOMP.js @@ -39,11 +39,11 @@ import WorkflowActionButton from './components/action/WorkflowActionButton.vue'; import WorkflowRecommendOnlyControls from './components/action/WorkflowRecommendOnlyControls.vue'; import WorkflowRecommendOnlyListingRecommendations from './components/secondary/WorkflowRecommendOnlyListingRecommendations.vue'; import WorkflowNotificationDisplay from './components/primary/WorkflowNotificationDisplay.vue'; +import WorkflowListingEmails from './components/primary/WorkflowListingEmails.vue'; import WorkflowPublicationForm from './components/publication/WorkflowPublicationForm.vue'; import WorkflowPublicationVersionControl from './components/publication/WorkflowPublicationVersionControl.vue'; import WorkflowChangeSubmissionLanguage from './components/publication/WorkflowChangeSubmissionLanguage.vue'; import WorkflowPrimaryBasicMetadata from './components/primary/WorkflowPrimaryBasicMetadata.vue'; -import WorkflowReviewRoundStatus from './components/primary/WorkflowReviewRoundStatus.vue'; import WorkflowSubmissionStatus from './components/primary/WorkflowSubmissionStatus.vue'; import WorkflowPublicationEditDisabled from './components/publication/WorkflowPublicationEditDisabled.vue'; @@ -209,8 +209,8 @@ export const useWorkflowStore = defineComponentStore('workflow', (props) => { WorkflowRecommendOnlyControls, WorkflowRecommendOnlyListingRecommendations, WorkflowNotificationDisplay, + WorkflowListingEmails, WorkflowPrimaryBasicMetadata, - WorkflowReviewRoundStatus, WorkflowPublicationForm, WorkflowPublicationVersionControl, WorkflowChangeSubmissionLanguage, diff --git a/src/utils/deepMerge.js b/src/utils/deepMerge.js new file mode 100644 index 000000000..84d045289 --- /dev/null +++ b/src/utils/deepMerge.js @@ -0,0 +1,31 @@ +/** + * Simple object check. + * @param item + * @returns {boolean} + */ +export function isObject(item) { + return item && typeof item === 'object' && !Array.isArray(item); +} + +/** + * Deep merge two objects. + * @param target + * @param ...sources + */ +export function deepMerge(target, ...sources) { + if (!sources.length) return target; + const source = sources.shift(); + + if (isObject(target) && isObject(source)) { + for (const key in source) { + if (isObject(source[key])) { + if (!target[key]) Object.assign(target, {[key]: {}}); + deepMerge(target[key], source[key]); + } else { + Object.assign(target, {[key]: source[key]}); + } + } + } + + return deepMerge(target, ...sources); +}