diff --git a/src/managers/GalleyManager/galleyManagerStore.js b/src/managers/GalleyManager/galleyManagerStore.js index 4e75137e6..b2ae5215f 100644 --- a/src/managers/GalleyManager/galleyManagerStore.js +++ b/src/managers/GalleyManager/galleyManagerStore.js @@ -103,7 +103,9 @@ export const useGalleyManagerStore = defineComponentStore( /** * Actions */ - const _galleyActionsFns = useGalleyManagerActions(); + const _galleyActionsFns = useGalleyManagerActions({ + galleyGridComponent: _galleyConfigurationFns.getGalleyGridComponent(), + }); function getActionArgs() { return { canEdit: props.canEdit, diff --git a/src/managers/GalleyManager/useGalleyManagerActions.js b/src/managers/GalleyManager/useGalleyManagerActions.js index 95f4de0f8..90b9a380e 100644 --- a/src/managers/GalleyManager/useGalleyManagerActions.js +++ b/src/managers/GalleyManager/useGalleyManagerActions.js @@ -9,7 +9,7 @@ export const Actions = { GALLEY_DELETE: 'galleyDelete', }; -export function useGalleyManagerActions() { +export function useGalleyManagerActions({galleyGridComponent}) { const {t} = useLocalize(); function getBottomActions({canEdit}) { @@ -76,7 +76,7 @@ export function useGalleyManagerActions() { function galleyAdd({submission, publication}, finishedCallback) { const {openLegacyModal} = useLegacyGridUrl({ - component: 'grid.articleGalleys.ArticleGalleyGridHandler', + component: galleyGridComponent, op: 'addGalley', params: { submissionId: submission.id, @@ -123,7 +123,7 @@ export function useGalleyManagerActions() { function galleyEdit({submission, publication, galley}, finishedCallback) { const {openLegacyModal} = useLegacyGridUrl({ - component: 'grid.articleGalleys.ArticleGalleyGridHandler', + component: galleyGridComponent, op: 'editGalley', params: { submissionId: submission.id, @@ -153,7 +153,7 @@ export function useGalleyManagerActions() { // http://localhost:7002/index.php/publicknowledge/$$$call$$$/grid/article-galleys/article-galley-grid/delete-galley // ?submissionId=17&publicationId=22&representationId=9 const {url} = useLegacyGridUrl({ - component: 'grid.articleGalleys.ArticleGalleyGridHandler', + component: galleyGridComponent, op: 'deleteGalley', params: { submissionId: submission.id, diff --git a/src/managers/GalleyManager/useGalleyManagerConfiguration.js b/src/managers/GalleyManager/useGalleyManagerConfiguration.js index 546b0d3f1..dc641310a 100644 --- a/src/managers/GalleyManager/useGalleyManagerConfiguration.js +++ b/src/managers/GalleyManager/useGalleyManagerConfiguration.js @@ -3,6 +3,14 @@ import {useLocalize} from '@/composables/useLocalize'; export function useGalleyManagerConfiguration() { const {t} = useLocalize(); + function getGalleyGridComponent() { + if (pkp.context.app === 'ops') { + return 'grid.preprintGalleys.PreprintGalleyGridHandler'; + } else { + return 'grid.articleGalleys.ArticleGalleyGridHandler'; + } + } + function getColumns() { const columns = []; @@ -29,5 +37,5 @@ export function useGalleyManagerConfiguration() { return columns; } - return {getColumns}; + return {getColumns, getGalleyGridComponent}; } diff --git a/src/pages/workflow/WorkflowPage.vue b/src/pages/workflow/WorkflowPage.vue index 76bd1c434..ffc9988a6 100644 --- a/src/pages/workflow/WorkflowPage.vue +++ b/src/pages/workflow/WorkflowPage.vue @@ -47,12 +47,29 @@ #publication-controls-left >
- + > +
+
+ +
+
+ +
+ + diff --git a/src/pages/workflow/components/publication/WorkflowPublicationRelationDropdownOPS.vue b/src/pages/workflow/components/publication/WorkflowPublicationRelationDropdownOPS.vue new file mode 100644 index 000000000..f18ce5c8d --- /dev/null +++ b/src/pages/workflow/components/publication/WorkflowPublicationRelationDropdownOPS.vue @@ -0,0 +1,50 @@ + + + + diff --git a/src/pages/workflow/composables/useWorkflowConfig/useWorkflowConfigOMP.js b/src/pages/workflow/composables/useWorkflowConfig/useWorkflowConfigOMP.js index 24b29d1e4..abfe194db 100644 --- a/src/pages/workflow/composables/useWorkflowConfig/useWorkflowConfigOMP.js +++ b/src/pages/workflow/composables/useWorkflowConfig/useWorkflowConfigOMP.js @@ -1,8 +1,8 @@ import {useLocalize} from '@/composables/useLocalize'; import {DashboardPageTypes} from '@/pages/dashboard/dashboardPageStore'; -import * as ConfigAuthorShared from './workflowConfigAuthorOJS'; -import * as ConfigEditorialShared from './workflowConfigEditorialOJS'; +import * as ConfigAuthorOJS from './workflowConfigAuthorOJS'; +import * as ConfigEditorialOJS from './workflowConfigEditorialOJS'; import * as ConfigAuthorOMP from './workflowConfigAuthorOMP'; import * as ConfigEditorialOMP from './workflowConfigEditorialOMP'; @@ -16,11 +16,11 @@ export function useWorkflowConfigOMP({dashboardPage}) { Configs = { getHeaderItems: ConfigEditorialOMP.getHeaderItems, WorkflowConfig: { - ...ConfigEditorialShared.WorkflowConfig, + ...ConfigEditorialOJS.WorkflowConfig, ...ConfigEditorialOMP.WorkflowConfig, }, PublicationConfig: { - ...ConfigEditorialShared.PublicationConfig, + ...ConfigEditorialOJS.PublicationConfig, ...ConfigEditorialOMP.PublicationConfig, }, MarketingConfig: ConfigEditorialOMP.MarketingConfig, @@ -29,11 +29,11 @@ export function useWorkflowConfigOMP({dashboardPage}) { Configs = { getHeaderItems: ConfigEditorialOMP.getHeaderItems, WorkflowConfig: { - ...ConfigAuthorShared.WorkflowConfig, + ...ConfigAuthorOJS.WorkflowConfig, ...ConfigAuthorOMP.WorkflowConfig, }, PublicationConfig: { - ...ConfigAuthorShared.PublicationConfig, + ...ConfigAuthorOJS.PublicationConfig, ...ConfigAuthorOMP.PublicationConfig, }, }; diff --git a/src/pages/workflow/composables/useWorkflowConfig/useWorkflowConfigOPS.js b/src/pages/workflow/composables/useWorkflowConfig/useWorkflowConfigOPS.js new file mode 100644 index 000000000..b0bd76d5e --- /dev/null +++ b/src/pages/workflow/composables/useWorkflowConfig/useWorkflowConfigOPS.js @@ -0,0 +1,134 @@ +import {useLocalize} from '@/composables/useLocalize'; +import {DashboardPageTypes} from '@/pages/dashboard/dashboardPageStore'; + +import * as ConfigAuthorOPS from './workflowConfigAuthorOPS'; +import * as ConfigEditorialOPS from './workflowConfigEditorialOPS'; + +export function useWorkflowConfigOPS({dashboardPage}) { + const {t} = useLocalize(); + + let Configs = null; + + if (dashboardPage === DashboardPageTypes.EDITORIAL_DASHBOARD) { + Configs = { + getHeaderItems: ConfigEditorialOPS.getHeaderItems, + WorkflowConfig: { + //...ConfigEditorialShared.WorkflowConfig, + ...ConfigEditorialOPS.WorkflowConfig, + }, + PublicationConfig: { + //...ConfigEditorialShared.PublicationConfig, + ...ConfigEditorialOPS.PublicationConfig, + }, + }; + } else { + Configs = { + getHeaderItems: ConfigEditorialOPS.getHeaderItems, + WorkflowConfig: { + ...ConfigAuthorOPS.WorkflowConfig, + }, + PublicationConfig: { + ...ConfigAuthorOPS.PublicationConfig, + }, + }; + } + + function _getItems( + getterFnName, + { + selectedMenuState, + submission, + pageInitConfig, + selectedPublication, + selectedPublicationId, + selectedReviewRound, + permissions, + }, + ) { + if (selectedMenuState.stageId) { + const itemsArgs = { + submission, + selectedPublication, + selectedPublicationId, + selectedStageId: selectedMenuState.stageId, + selectedReviewRound, + permissions, + }; + if (!submission) { + return []; + } + + if (!permissions.accessibleStages.includes(selectedMenuState.stageId)) { + if (getterFnName === 'getPrimaryItems') { + return [ + { + component: 'PrimaryBasicMetadata', + props: {body: t('user.authorization.accessibleWorkflowStage')}, + }, + ]; + } else { + return []; + } + } + + return [ + ...(Configs.WorkflowConfig?.common?.[getterFnName]?.(itemsArgs) || []), + ...(Configs.WorkflowConfig[selectedMenuState.stageId]?.[getterFnName]?.( + itemsArgs, + ) || []), + ]; + } else if (selectedMenuState.primaryMenuItem === 'publication') { + const itemsArgs = { + submission, + pageInitConfig: pageInitConfig, + selectedPublication, + selectedPublicationId, + permissions, + }; + if (!submission || !selectedPublication) { + return []; + } + + return [ + ...(Configs.PublicationConfig?.common?.[getterFnName]?.(itemsArgs) || + []), + ...(Configs.PublicationConfig[selectedMenuState.secondaryMenuItem]?.[ + getterFnName + ]?.(itemsArgs) || []), + ]; + } + } + + function getHeaderItems(args) { + return Configs.getHeaderItems(args); + } + + function getPrimaryItems(args) { + return _getItems('getPrimaryItems', args); + } + + function getSecondaryItems(args) { + return _getItems('getSecondaryItems', args); + } + + function getActionItems(args) { + return _getItems('getActionItems', args); + } + + function getPublicationControlsLeft(args) { + return _getItems('getPublicationControlsLeft', args); + } + + function getPublicationControlsRight(args) { + return _getItems('getPublicationControlsRight', args); + } + + return { + getHeaderItems, + getPrimaryItems, + getSecondaryItems, + getActionItems, + getPublicationControlsLeft, + getPublicationControlsRight, + }; +} diff --git a/src/pages/workflow/composables/useWorkflowConfig/workflowConfigAuthorOPS.js b/src/pages/workflow/composables/useWorkflowConfig/workflowConfigAuthorOPS.js new file mode 100644 index 000000000..8883ff887 --- /dev/null +++ b/src/pages/workflow/composables/useWorkflowConfig/workflowConfigAuthorOPS.js @@ -0,0 +1,182 @@ +import {useLocalize} from '@/composables/useLocalize'; +import {Actions} from '../useWorkflowActions'; + +export function getHeaderItems({ + submission, + selectedPublication, + publicationSettings, +}) { + if (!submission) { + return []; + } + const {t} = useLocalize(); + const actions = []; + + actions.push({ + component: 'WorkflowActionButton', + props: { + label: t('editor.submissionLibrary'), + action: Actions.WORKFLOW_VIEW_LIBRARY, + }, + }); + + return actions; +} + +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, + }, + }, + { + component: 'WorkflowPublicationRelationDropdownOPS', + props: {publication: selectedPublication}, + }, + ]); + + 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}) => { + return [ + { + component: 'DiscussionManager', + props: { + submissionId: submission.id, + stageId: pkp.const.WORKFLOW_STAGE_ID_PRODUCTION, + }, + }, + ]; + }, + }, +}; diff --git a/src/pages/workflow/composables/useWorkflowConfig/workflowConfigEditorialOJS.js b/src/pages/workflow/composables/useWorkflowConfig/workflowConfigEditorialOJS.js index 8f4f02b13..8aba7d3c6 100644 --- a/src/pages/workflow/composables/useWorkflowConfig/workflowConfigEditorialOJS.js +++ b/src/pages/workflow/composables/useWorkflowConfig/workflowConfigEditorialOJS.js @@ -511,7 +511,7 @@ export const WorkflowConfig = { label: t('editor.submission.schedulePublication'), isPrimary: true, action: 'navigateToMenu', - actionArgs: {key: 'publication_titleAbstract'}, + actionArgs: 'publication_titleAbstract', }, }); diff --git a/src/pages/workflow/composables/useWorkflowConfig/workflowConfigEditorialOPS.js b/src/pages/workflow/composables/useWorkflowConfig/workflowConfigEditorialOPS.js new file mode 100644 index 000000000..80be03ca6 --- /dev/null +++ b/src/pages/workflow/composables/useWorkflowConfig/workflowConfigEditorialOPS.js @@ -0,0 +1,461 @@ +import {useLocalize} from '@/composables/useLocalize'; +import {Actions} from '../useWorkflowActions'; +import {useSubmission} from '@/composables/useSubmission'; +import {Actions as DecisionActions} from '../useWorkflowDecisions'; +const {hasSubmissionPassedStage, hasNotSubmissionStartedStage} = + useSubmission(); +const {t} = useLocalize(); + +export function getHeaderItems({ + submission, + selectedPublication, + publicationSettings, + permissions, +}) { + if (!submission) { + return []; + } + const {t} = useLocalize(); + const actions = []; + + if (submission.status === pkp.const.STATUS_PUBLISHED) { + actions.push({ + component: 'WorkflowActionButton', + props: { + label: t('common.view'), + action: Actions.WORKFLOW_VIEW_PUBLISHED_SUBMISSION, + }, + }); + } + + if (permissions.canAccessEditorialHistory) { + actions.push({ + component: 'WorkflowActionButton', + props: { + label: t('editor.activityLog'), + action: Actions.WORKFLOW_VIEW_ACTIVITY_LOG, + }, + }); + } + actions.push({ + component: 'WorkflowActionButton', + props: { + label: t('editor.submissionLibrary'), + action: Actions.WORKFLOW_VIEW_LIBRARY, + }, + }); + + return actions; +} + +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', + props: {submission: submission}, + }); + + 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 = []; + if ( + hasNotSubmissionStartedStage( + submission, + pkp.const.WORKFLOW_STAGE_ID_PRODUCTION, + ) || + hasSubmissionPassedStage( + submission, + pkp.const.WORKFLOW_STAGE_ID_PRODUCTION, + ) + ) { + return []; + } + + items.push({ + component: 'WorkflowActionButton', + props: { + label: t('editor.submission.schedulePublication'), + isPrimary: true, + action: 'navigateToMenu', + actionArgs: 'publication_titleAbstract', + }, + }); + + items.push({ + component: 'WorkflowActionButton', + props: { + label: t('editor.submission.decision.decline'), + isWarnable: true, + action: DecisionActions.DECISION_INITIAL_DECLINE, + }, + }); + + return items; + }, + }, +}; + +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, + }, + }); + } + + // publication controls left supports subarray for horizontal items, and array for vertical + items.push([ + { + component: 'WorkflowPublicationVersionControl', + props: { + submission, + selectedPublicationId: selectedPublicationId, + }, + }, + { + component: 'WorkflowPublicationRelationDropdownOPS', + props: {publication: selectedPublication}, + }, + ]); + + return items; + }, + getPublicationControlsRight: ({ + submission, + selectedPublicationId, + selectedPublication, + permissions, + }) => { + const items = []; + const {t} = useLocalize(); + + if (!permissions.canPublish) { + return []; + } + if (selectedPublication.status === pkp.const.STATUS_QUEUED) { + if ( + hasSubmissionPassedStage( + submission, + pkp.const.WORKFLOW_STAGE_ID_EXTERNAL_REVIEW, + ) + ) { + items.push({ + component: 'WorkflowActionButton', + props: { + label: t('common.preview'), + isSecondary: true, + action: Actions.WORKFLOW_PREVIEW_PUBLICATION, + }, + }); + } + + items.push({ + component: 'WorkflowActionButton', + props: { + // {{ submission.status === getConstant('STATUS_PUBLISHED') ? publishLabel : schedulePublicationLabel }} + + label: + submission.status === pkp.const.STATUS_PUBLISHED + ? t('publication.publish') + : t('editor.submission.schedulePublication'), + isSecondary: true, + action: + Actions.WORKFLOW_ASSIGN_TO_ISSUE_AND_SCHEDULE_FOR_PUBLICATION, + }, + }); + } else if (selectedPublication.status === pkp.const.STATUS_SCHEDULED) { + items.push({ + component: 'WorkflowActionButton', + props: { + label: t('dashboard.summary.preview'), + isSecondary: true, + action: Actions.WORKFLOW_PREVIEW_PUBLICATION, + }, + }); + + items.push({ + component: 'WorkflowActionButton', + props: { + label: t('publication.unschedule'), + isWarnable: true, + action: Actions.WORKFLOW_UNSCHEDULE_PUBLICATION, + }, + }); + } else if (selectedPublication.status === pkp.const.STATUS_PUBLISHED) { + items.push({ + component: 'WorkflowActionButton', + props: { + label: t('publication.unpublish'), + isWarnable: true, + action: Actions.WORKFLOW_UNPUBLISH_PUBLICATION, + }, + }); + + const {getLatestPublication} = useSubmission(); + const latestPublication = getLatestPublication(submission); + + if (latestPublication.id === selectedPublication.id) { + items.push({ + component: 'WorkflowActionButton', + props: { + label: t('publication.createVersion'), + isSecondary: true, + action: Actions.WORKFLOW_CREATE_NEW_VERSION, + }, + }); + } + } + + 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, + }, + }, + ]; + }, + }, + preprintEntry: { + getPrimaryItems: ({ + submission, + selectedPublication, + pageInitConfig, + permissions, + }) => { + return [ + { + component: 'WorkflowPublicationForm', + props: { + formName: 'issue', + submission, + publication: selectedPublication, + canEdit: permissions.canEditPublication, + }, + }, + ]; + }, + }, +}; diff --git a/src/pages/workflow/composables/useWorkflowNavigationConfig/useWorkflowNavigationConfigOPS.js b/src/pages/workflow/composables/useWorkflowNavigationConfig/useWorkflowNavigationConfigOPS.js new file mode 100644 index 000000000..13867ecfa --- /dev/null +++ b/src/pages/workflow/composables/useWorkflowNavigationConfig/useWorkflowNavigationConfigOPS.js @@ -0,0 +1,277 @@ +import {useSubmission} from '@/composables/useSubmission'; +import {useLocalize} from '@/composables/useLocalize'; +import {DashboardPageTypes} from '@/pages/dashboard/dashboardPageStore'; + +const {t} = useLocalize(); + +const StageColors = { + [pkp.const.WORKFLOW_STAGE_ID_SUBMISSION]: 'border-stage-desk-review', + [pkp.const.WORKFLOW_STAGE_ID_EXTERNAL_REVIEW]: 'border-stage-in-review', + [pkp.const.WORKFLOW_STAGE_ID_EDITING]: 'border-stage-copyediting', + [pkp.const.WORKFLOW_STAGE_ID_PRODUCTION]: 'border-stage-production', +}; + +export function getPublicationItem({label, name}) { + return { + key: `publication_${name}`, + label: label, + action: 'selectMenu', + actionArgs: { + primaryMenuItem: 'publication', + secondaryMenuItem: name, + title: getPublicationTitle(label), + }, + }; +} + +export function getWorkflowItem({stageId, label, isActive, isDisabled, items}) { + return { + key: `workflow_${stageId}`, + label: label, + colorStripe: isActive ? StageColors[stageId] : null, + action: isDisabled ? undefined : 'selectMenu', + actionArgs: { + primaryMenuItem: 'workflow', + stageId: stageId, + title: getWorkflowTitle(label), + }, + items, + }; +} + +export function getWorkflowTitle(stageLabel) { + return `${t('semicolon', {label: t('manager.workflow')})} ${stageLabel} `; +} + +export function getPublicationTitle(publicationMenuTitle) { + return `${t('semicolon', { + label: t('submission.publication'), + })} ${publicationMenuTitle}`; +} + +export function getReviewItems({submission, stageId, title}) { + const {getActiveStage, getCurrentReviewRound} = useSubmission(); + + const activeStage = getActiveStage(submission); + + const activeReviewRound = getCurrentReviewRound(submission, stageId); + + const reviewMenuItems = []; + + const {getReviewRoundsForStage} = useSubmission(); + const reviewRounds = getReviewRoundsForStage(submission, stageId); + + reviewRounds.forEach((reviewRound) => { + reviewMenuItems.push( + getReviewItem({ + stageId, + reviewRound, + isActive: + activeStage.id === stageId && activeReviewRound.id === reviewRound.id, + title: title, + }), + ); + }); + + return reviewMenuItems; +} + +export function getReviewItem({stageId, reviewRound, isActive, title}) { + return { + key: `workflow_${stageId}_${reviewRound.id}`, + label: t('dashboard.workflow.reviewRoundN', {number: reviewRound.round}), + colorStripe: isActive ? StageColors[stageId] : null, + action: 'selectMenu', + actionArgs: { + primaryMenuItem: 'workflow', + stageId: stageId, + reviewRoundId: reviewRound.id, + title: title, + }, + }; +} + +export function useWorkflowNavigationConfigOPS(pageInitConfig) { + const {publicationSettings} = pageInitConfig; + const {t} = useLocalize(); + + function getWorkflowItems({submission}) { + const {getActiveStage} = useSubmission(); + + const activeStage = getActiveStage(submission); + + const items = []; + + items.push( + getWorkflowItem({ + stageId: pkp.const.WORKFLOW_STAGE_ID_PRODUCTION, + label: t('dashboard.stage.production'), + isActive: activeStage.id === pkp.const.WORKFLOW_STAGE_ID_PRODUCTION, + }), + ); + + return items; + } + + function getPublicationItemsAuthor({submission, permissions}) { + const items = []; + + items.push( + getPublicationItem({ + name: 'titleAbstract', + label: t('publication.titleAbstract'), + }), + ); + + items.push( + getPublicationItem({ + name: 'contributors', + label: t('publication.contributors'), + }), + ); + + items.push( + getPublicationItem({ + name: 'metadata', + label: t('submission.informationCenter.metadata'), + }), + ); + + if (publicationSettings.supportsCitations) { + items.push( + getPublicationItem({ + name: 'citations', + label: t('submission.citations'), + }), + ); + } + + items.push( + getPublicationItem({ + name: 'galleys', + label: t('submission.layout.galleys'), + }), + ); + + items.push( + getPublicationItem({ + name: 'discussions', + label: t('submission.queries.production'), + }), + ); + + return items; + } + + function getPublicationItemsEditorial({submission, permissions}) { + const items = []; + + items.push( + getPublicationItem({ + name: 'titleAbstract', + label: t('publication.titleAbstract'), + }), + ); + + items.push( + getPublicationItem({ + name: 'contributors', + label: t('publication.contributors'), + }), + ); + + items.push( + getPublicationItem({ + name: 'metadata', + label: t('submission.informationCenter.metadata'), + }), + ); + + if (publicationSettings.supportsCitations) { + items.push( + getPublicationItem({ + name: 'citations', + label: t('submission.citations'), + }), + ); + } + + if (publicationSettings.identifiersEnabled) { + items.push( + getPublicationItem({ + name: 'identifiers', + label: t('submission.identifiers'), + }), + ); + } + + if (permissions.canAccessProduction) { + items.push( + getPublicationItem({ + name: 'galleys', + label: t('submission.layout.galleys'), + }), + ); + + items.push( + getPublicationItem({ + name: 'license', + label: t('publication.publicationLicense'), + }), + ); + + items.push( + getPublicationItem({ + name: 'preprintEntry', + label: t('preprint.entry'), + }), + ); + } + + return items; + } + + function getMenuItems({submission, permissions}) { + if (!submission) { + return []; + } + + const menuItems = []; + + if ( + pageInitConfig.dashboardPage === DashboardPageTypes.EDITORIAL_DASHBOARD + ) { + menuItems.push({ + key: 'workflow', + label: t('manager.workflow'), + icon: 'Dashboard', + items: getWorkflowItems({submission, permissions}), + }); + } + + menuItems.push({ + key: 'publication', + label: t('submission.publication'), + icon: 'MySubmissions', + items: + pageInitConfig.dashboardPage === DashboardPageTypes.EDITORIAL_DASHBOARD + ? getPublicationItemsEditorial({submission, permissions}) + : getPublicationItemsAuthor({submission, permissions}), + }); + + return menuItems; + } + + function getInitialSelectionItemKey(submission) { + if ( + submission.stageId === pkp.const.WORKFLOW_STAGE_ID_PRODUCTION && + submission.status !== pkp.const.STATUS_QUEUED + ) { + return `publication_titleAbstract`; + } else { + return `workflow_${submission.stageId}`; + } + } + + return {getMenuItems, getInitialSelectionItemKey}; +} diff --git a/src/pages/workflow/workflowStoreOPS.js b/src/pages/workflow/workflowStoreOPS.js new file mode 100644 index 000000000..5faaba5aa --- /dev/null +++ b/src/pages/workflow/workflowStoreOPS.js @@ -0,0 +1,248 @@ +import {computed, watch, markRaw} from 'vue'; + +import {defineComponentStore} from '@/utils/defineComponentStore'; +import { + useWorkflowActions, + Actions as WorkflowActions, +} from './composables/useWorkflowActions'; + +import { + useWorkflowDecisions, + Actions as DecisionActions, +} from './composables/useWorkflowDecisions'; + +import {useDataChangedProvider} from '@/composables/useDataChangedProvider'; + +import {wrapActionFns} from '@/utils/wrapActionFns'; + +import {useWorkflowConfigOPS as useWorkflowConfig} from './composables/useWorkflowConfig/useWorkflowConfigOPS'; +import {useWorkflowNavigationConfigOPS as useWorkflowNavigationConfig} from './composables/useWorkflowNavigationConfig/useWorkflowNavigationConfigOPS'; + +import {useWorkflowDataSubmissionPublication} from './composables/useWorkflowDataSubmissionPublication'; +import {useWorkflowPermissions} from './composables/useWorkflowPermissions'; +import {useWorkflowMenu} from './composables/useWorkflowMenu'; +import {useWorkflowItems} from './composables/useWorkflowItems'; +import {useSubmission} from '@/composables/useSubmission'; + +import FileManager from '@/managers/FileManager/FileManager.vue'; +import ReviewerManager from '@/managers/ReviewerManager/ReviewerManager.vue'; +import DiscussionManager from '@/managers/DiscussionManager/DiscussionManager.vue'; +import ContributorManager from '@/managers/ContributorManager/ContributorManager.vue'; +import ParticipantManager from '@/managers/ParticipantManager/ParticipantManager.vue'; +import GalleyManager from '@/managers/GalleyManager/GalleyManager.vue'; +import WorkflowActionButton from './components/action/WorkflowActionButton.vue'; +import WorkflowNotificationDisplay from './components/primary/WorkflowNotificationDisplay.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 WorkflowPublicationRelationDropdownOPS from './components/publication/WorkflowPublicationRelationDropdownOPS.vue'; +import WorkflowSubmissionStatus from './components/primary/WorkflowSubmissionStatus.vue'; +import WorkflowPublicationEditDisabled from './components/publication/WorkflowPublicationEditDisabled.vue'; + +export const useWorkflowStore = defineComponentStore('workflow', (props) => { + const dashboardPage = props.pageInitConfig.dashboardPage; + + /** + * Submission & Publication + */ + const { + submission, + submissionId, + selectPublicationId, + selectedPublication, + selectedPublicationId, + refetchSubmissionPublication, + } = useWorkflowDataSubmissionPublication({submissionId: props.submissionId}); + + const {getExtendedStage, getExtendedStageLabel} = useSubmission(); + + /** + * Current Stage Indication + */ + const extendedStage = computed( + () => submission.value && getExtendedStage(submission.value), + ); + const stageLabel = computed( + () => submission.value && getExtendedStageLabel(submission.value), + ); + + /** + * Data changes tracking + */ + const {triggerDataChange} = useDataChangedProvider(() => { + return refetchSubmissionPublication(); + }); + + /** + * UI Permissions + */ + const {permissions} = useWorkflowPermissions({ + submission, + selectedPublication, + }); + + /** + * Navigation + */ + + const {getMenuItems, getInitialSelectionItemKey} = + useWorkflowNavigationConfig(props.pageInitConfig); + + const menuItems = computed(() => + getMenuItems({ + submission: submission.value, + permissions: permissions.value, + }), + ); + + const { + menuTitle, + navigateToMenu, + selectedMenuState, + selectedReviewRound, + setExpandedKeys, + sideMenuProps, + } = useWorkflowMenu({menuItems, submission}); + + setExpandedKeys(['workflow', 'publication']); + + /** When submission is loaded initially - select relevant menu */ + watch(submission, (newSubmission, oldSubmission) => { + // Once the submission is fetched, select relevant stage in navigaton + if (!oldSubmission && newSubmission) { + navigateToMenu(getInitialSelectionItemKey(newSubmission)); + } + }); + + /** + * Expose workflow actions + * + */ + const _workflowActionsFns = useWorkflowActions(props.pageInitConfig); + const workflowActions = wrapActionFns( + WorkflowActions, + _workflowActionsFns, + (actionFn, actionArgs, finishedCallback = null) => + actionFn( + { + ...actionArgs, + submission: submission.value, + selectedPublication: selectedPublication.value, + reviewRoundId: selectedReviewRound.value?.id, + store, + }, + (finishedData) => { + triggerDataChange(); + if (finishedCallback) { + finishedCallback(finishedData); + } + }, + ), + ); + + /** + * Expose decision functions + * + * */ + const _workflowDecisionsFns = useWorkflowDecisions(); + const decisionActions = wrapActionFns( + DecisionActions, + _workflowDecisionsFns, + (actionFn, actionArgs) => + actionFn({ + ...actionArgs, + submission: submission.value, + selectedPublication: selectedPublication.value, + reviewRoundId: selectedReviewRound.value?.id, + }), + ); + + /** + * Items + * + * */ + + const _workflowConfigFns = useWorkflowConfig({dashboardPage}); + + const { + headerItems, + primaryItems, + secondaryItems, + actionItems, + publicationControlsLeft, + publicationControlsRight, + } = useWorkflowItems(_workflowConfigFns, () => ({ + selectedMenuState: selectedMenuState.value, + submission: submission.value, + pageInitConfig: props.pageInitConfig, + selectedPublication: selectedPublication.value, + selectedPublicationId: selectedPublicationId.value, + selectedReviewRound: selectedReviewRound.value, + permissions: permissions.value, + publicationSettings: props.pageInitConfig.publicationSettings, + })); + + const Components = markRaw({ + FileManager, + ReviewerManager, + DiscussionManager, + ContributorManager, + ParticipantManager, + GalleyManager, + WorkflowActionButton, + WorkflowNotificationDisplay, + WorkflowPrimaryBasicMetadata, + WorkflowPublicationForm, + WorkflowPublicationRelationDropdownOPS, + WorkflowPublicationVersionControl, + WorkflowChangeSubmissionLanguage, + WorkflowSubmissionStatus, + WorkflowPublicationEditDisabled, + }); + + const store = { + dashboardPage, + submission, + submissionId, + selectedPublication, + selectPublicationId, + extendedStage, + stageLabel, + + /** + * Navigation + * */ + sideMenuProps, + selectedMenuState, + navigateToMenu, + + /** Actions + * + */ + ...workflowActions, + ...decisionActions, + + /** + * Summary + */ + menuTitle, + headerItems, + primaryItems, + secondaryItems, + actionItems, + publicationControlsLeft, + publicationControlsRight, + + permissions, + /** + * Expose for extensions + */ + + _workflowActionsFns, + _workflowDecisionsFns, + + Components, + }; + return store; +});