From d8fb40bb3ae68f54f8716ee273e6487de6be70b7 Mon Sep 17 00:00:00 2001 From: Blesilda Ramirez Date: Fri, 28 Nov 2025 00:31:09 -0500 Subject: [PATCH 01/12] pkp/pkp-lib#11826 Add missing locale keys for task template form --- public/globals.js | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/public/globals.js b/public/globals.js index 5fcf4898c..2c9038335 100644 --- a/public/globals.js +++ b/public/globals.js @@ -27,7 +27,6 @@ window.pkp = { * */ context: { - id: 1, apiBaseUrl: 'https://mock/index.php/publicknowledge/api/v1/', pageBaseUrl: 'https://mock/index.php/publicknowledge/', currentLocale: 'en', @@ -189,6 +188,12 @@ window.pkp = { 'admin.jobs.failed.action.redispatch': 'Try Again', 'admin.jobs.failed.action.redispatch.all': 'Requeue All Failed Jobs', 'admin.jobs.list.actions': 'Actions', + 'admin.workflow.email.userGroup.assign.unrestricted': + 'Mark as unrestricted', + 'admin.workflow.email.userGroup.limitAccess': + 'Limit Access to Specific User Groups', + 'admin.workflow.email.userGroup.unrestricted.template.note': + 'Unrestricted templates will be accessible to all user groups.', 'article.article': 'Article', 'article.metadata': 'Metadata', 'author.users.contributor.principalContact': 'Primary Contact', From 5fdabc6bb41dd13456bae03cad748813fb87d9fe Mon Sep 17 00:00:00 2001 From: Blesilda Ramirez Date: Fri, 28 Nov 2025 00:32:07 -0500 Subject: [PATCH 02/12] pkp/pkp-lib#11826 Add Mark as Unrestricted and Limit Access to User Groups field to task template form --- .../useTaskTemplateManagerForm.js | 37 +++++++++++++++---- 1 file changed, 29 insertions(+), 8 deletions(-) diff --git a/src/managers/TaskTemplateManager/useTaskTemplateManagerForm.js b/src/managers/TaskTemplateManager/useTaskTemplateManagerForm.js index cf97428cc..1dcb2143e 100644 --- a/src/managers/TaskTemplateManager/useTaskTemplateManagerForm.js +++ b/src/managers/TaskTemplateManager/useTaskTemplateManagerForm.js @@ -37,7 +37,10 @@ export function useTaskTemplateManagerForm({ const dataBody = { title: formData.title, stageId, - userGroupIds: formData.userGroupIds, + isUnrestricted: formData.isUnrestricted, + assignedUserGroupIds: formData.isUnrestricted + ? null + : formData.assignedUserGroupIds, include: formData.include, dueInterval: isTask.value ? formData.dueInterval : null, description: formData.description, @@ -78,8 +81,8 @@ export function useTaskTemplateManagerForm({ }; } - function getParticipantOptions() { - const {apiUrl: userGroupsApiUrl} = useUrl('userGroups'); + function getUserGroupOptions() { + const {apiUrl: userGroupsApiUrl} = useUrl(`userGroups?stageIds=${stageId}`); const {items: userGroupsData, fetch: fetchUserGroups} = useFetchPaginated( userGroupsApiUrl, @@ -202,14 +205,32 @@ export function useTaskTemplateManagerForm({ isRequired: true, }); - addFieldOptions('userGroupIds', 'checkbox', { + addFieldOptions('isUnrestricted', 'radio', { groupId: 'details', - label: t('editor.submission.stageParticipants'), - description: t('discussion.form.detailsParticipantsDescription'), - name: 'userGroupIds', - options: getParticipantOptions(), + label: t('admin.workflow.email.userGroup.assign.unrestricted'), + description: t('admin.workflow.email.userGroup.unrestricted.template.note'), + name: 'isUnrestricted', + options: [ + { + value: true, + label: t('admin.workflow.email.userGroup.assign.unrestricted'), + }, + { + value: false, + label: t('admin.workflow.email.userGroup.limitAccess'), + }, + ], + value: taskTemplate?.isUnrestricted ?? true, + }); + + addFieldOptions('assignedUserGroupIds', 'checkbox', { + groupId: 'details', + label: t('admin.workflow.email.userGroup.limitAccess'), + name: 'assignedUserGroupIds', + options: getUserGroupOptions(), value: taskTemplate?.userGroups?.map(({id}) => id) || [], isRequired: true, + showWhen: ['isUnrestricted', false], }); addGroup('taskInformation', { From e35a1c5ea4830e0bad81df95c47016e147893bde Mon Sep 17 00:00:00 2001 From: Blesilda Ramirez Date: Fri, 28 Nov 2025 00:34:12 -0500 Subject: [PATCH 03/12] pkp/pkp-lib#11826 Update task template story and test data --- .../TaskTemplateManager.stories.js | 37 +++- src/mockFactories/userGroupMock.js | 188 +++++++++++++----- 2 files changed, 176 insertions(+), 49 deletions(-) diff --git a/src/managers/TaskTemplateManager/TaskTemplateManager.stories.js b/src/managers/TaskTemplateManager/TaskTemplateManager.stories.js index ef38e321f..e7631da7c 100644 --- a/src/managers/TaskTemplateManager/TaskTemplateManager.stories.js +++ b/src/managers/TaskTemplateManager/TaskTemplateManager.stories.js @@ -63,9 +63,40 @@ const mswHandlers = [ }, ), - http.get('https://mock/index.php/publicknowledge/api/v1/userGroups', () => { - return HttpResponse.json(UserGroupMock); - }), + http.get( + 'https://mock/index.php/publicknowledge/api/v1/userGroups', + ({request}) => { + const url = new URL(request.url); + const stageId = url.searchParams.get('stageIds'); + switch (stageId) { + case '1': + return HttpResponse.json({ + items: UserGroupMock.WORKFLOW_STAGE_ID_SUBMISSION, + itemsMax: UserGroupMock.WORKFLOW_STAGE_ID_SUBMISSION.length, + }); + case '3': + return HttpResponse.json({ + items: UserGroupMock.WORKFLOW_STAGE_ID_EXTERNAL_REVIEW, + itemsMax: UserGroupMock.WORKFLOW_STAGE_ID_EXTERNAL_REVIEW.length, + }); + case '4': + return HttpResponse.json({ + items: UserGroupMock.WORKFLOW_STAGE_ID_EDITING, + itemsMax: UserGroupMock.WORKFLOW_STAGE_ID_EDITING.length, + }); + case '5': + return HttpResponse.json({ + items: UserGroupMock.WORKFLOW_STAGE_ID_PRODUCTION, + itemsMax: UserGroupMock.WORKFLOW_STAGE_ID_PRODUCTION.length, + }); + default: + return HttpResponse.json({ + items: [], + itemsMax: 0, + }); + } + }, + ), ]; export const Default = { diff --git a/src/mockFactories/userGroupMock.js b/src/mockFactories/userGroupMock.js index 189f62626..467decf40 100644 --- a/src/mockFactories/userGroupMock.js +++ b/src/mockFactories/userGroupMock.js @@ -1,131 +1,227 @@ export const UserGroupMock = { - itemsMax: 18, - items: [ + WORKFLOW_STAGE_ID_SUBMISSION: [ { - id: 2, - roleId: null, + id: 3, + roleId: 16, + isDefault: true, + showTitle: true, + name: 'Journal editor', + }, + { + id: 5, + roleId: 17, + isDefault: true, + showTitle: true, + name: 'Section editor', + }, + { + id: 6, + roleId: 17, + isDefault: true, + showTitle: true, + name: 'Guest editor', + }, + { + id: 9, + roleId: 4097, + isDefault: true, + showTitle: true, + name: 'Funding coordinator', + }, + { + id: 14, + roleId: 65536, isDefault: true, showTitle: true, - name: 'Journal manager', + name: 'Author', }, + { + id: 15, + roleId: 65536, + isDefault: true, + showTitle: true, + name: 'Translator', + }, + ], + WORKFLOW_STAGE_ID_EXTERNAL_REVIEW: [ { id: 3, - roleId: null, + roleId: 16, + isDefault: true, + showTitle: true, + name: 'Journal editor', + }, + { + id: 5, + roleId: 17, + isDefault: true, + showTitle: true, + name: 'Section editor', + }, + { + id: 6, + roleId: 17, + isDefault: true, + showTitle: true, + name: 'Guest editor', + }, + { + id: 9, + roleId: 4097, + isDefault: true, + showTitle: true, + name: 'Funding coordinator', + }, + { + id: 14, + roleId: 65536, + isDefault: true, + showTitle: true, + name: 'Author', + }, + { + id: 15, + roleId: 65536, + isDefault: true, + showTitle: true, + name: 'Translator', + }, + { + id: 16, + roleId: 4096, + isDefault: true, + showTitle: true, + name: 'Reviewer', + }, + ], + WORKFLOW_STAGE_ID_EDITING: [ + { + id: 3, + roleId: 16, isDefault: true, showTitle: true, name: 'Journal editor', }, { id: 4, - roleId: null, + roleId: 16, isDefault: true, showTitle: true, name: 'Production editor', }, { id: 5, - roleId: null, + roleId: 17, isDefault: true, showTitle: true, name: 'Section editor', }, { id: 6, - roleId: null, + roleId: 17, isDefault: true, showTitle: true, name: 'Guest editor', }, { id: 7, - roleId: null, + roleId: 4097, isDefault: true, showTitle: true, name: 'Copyeditor', }, { - id: 8, - roleId: null, + id: 12, + roleId: 4097, isDefault: true, showTitle: true, - name: 'Designer', + name: 'Marketing and sales coordinator', }, { - id: 9, - roleId: null, + id: 14, + roleId: 65536, isDefault: true, showTitle: true, - name: 'Funding coordinator', + name: 'Author', }, { - id: 10, - roleId: null, + id: 15, + roleId: 65536, isDefault: true, showTitle: true, - name: 'Indexer', + name: 'Translator', }, + ], + WORKFLOW_STAGE_ID_PRODUCTION: [ { - id: 11, - roleId: null, + id: 3, + roleId: 16, isDefault: true, showTitle: true, - name: 'Layout Editor', + name: 'Journal editor', }, { - id: 12, - roleId: null, + id: 4, + roleId: 16, isDefault: true, showTitle: true, - name: 'Marketing and sales coordinator', + name: 'Production editor', }, { - id: 13, - roleId: null, + id: 5, + roleId: 17, isDefault: true, showTitle: true, - name: 'Proofreader', + name: 'Section editor', }, { - id: 14, - roleId: null, + id: 6, + roleId: 17, isDefault: true, showTitle: true, - name: 'Author', + name: 'Guest editor', }, { - id: 15, - roleId: null, + id: 8, + roleId: 4097, isDefault: true, showTitle: true, - name: 'Translator', + name: 'Designer', }, { - id: 16, - roleId: null, + id: 10, + roleId: 4097, isDefault: true, showTitle: true, - name: 'Reviewer', + name: 'Indexer', }, { - id: 17, - roleId: null, + id: 11, + roleId: 4097, isDefault: true, showTitle: true, - name: 'Reader', + name: 'Layout Editor', }, { - id: 18, - roleId: null, + id: 13, + roleId: 4097, isDefault: true, showTitle: true, - name: 'Subscription Manager', + name: 'Proofreader', }, { - id: 19, - roleId: null, + id: 14, + roleId: 65536, isDefault: true, showTitle: true, - name: 'Editorial Board Member', + name: 'Author', + }, + { + id: 15, + roleId: 65536, + isDefault: true, + showTitle: true, + name: 'Translator', }, ], }; From a4b00f52e43ef2f6dc7e7636feff5a7fd19ba404 Mon Sep 17 00:00:00 2001 From: Blesilda Ramirez Date: Mon, 8 Dec 2025 14:45:47 -0500 Subject: [PATCH 04/12] pkp/pkp-lib#11826 Update locale strings for mark as unrestricted fields --- public/globals.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/public/globals.js b/public/globals.js index 2c9038335..7d44bcc0c 100644 --- a/public/globals.js +++ b/public/globals.js @@ -191,9 +191,9 @@ window.pkp = { 'admin.workflow.email.userGroup.assign.unrestricted': 'Mark as unrestricted', 'admin.workflow.email.userGroup.limitAccess': - 'Limit Access to Specific User Groups', + 'Limit access to specific roles', 'admin.workflow.email.userGroup.unrestricted.template.note': - 'Unrestricted templates will be accessible to all user groups.', + 'Unrestricted templates will be accessible to all roles.', 'article.article': 'Article', 'article.metadata': 'Metadata', 'author.users.contributor.principalContact': 'Primary Contact', From d0af3f210594ede3945e953c2d384afdb415a113 Mon Sep 17 00:00:00 2001 From: Blesilda Ramirez Date: Mon, 8 Dec 2025 14:54:01 -0500 Subject: [PATCH 05/12] pkp/pkp-lib#11826 Remove setting participants data from applying task template --- src/managers/DiscussionManager/useDiscussionManagerForm.js | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/managers/DiscussionManager/useDiscussionManagerForm.js b/src/managers/DiscussionManager/useDiscussionManagerForm.js index 77e994a74..e7003c203 100644 --- a/src/managers/DiscussionManager/useDiscussionManagerForm.js +++ b/src/managers/DiscussionManager/useDiscussionManagerForm.js @@ -254,10 +254,6 @@ export function useDiscussionManagerForm( isTask.value = templateData.value.type === pkp.const.EDITORIAL_TASK_TYPE_TASK; setValue('title', templateData.value.title); - setValue( - 'participants', - templateData.value.participants.map((p) => p.userId) || [], - ); setValue('taskInfoAdd', isTask.value); await nextTick(); // wait for the date due & assignee fields to re-render based on isTask value From 87aba73879abd39f0b7846946e50ca7ad80b89a3 Mon Sep 17 00:00:00 2001 From: Blesilda Ramirez Date: Mon, 8 Dec 2025 14:55:46 -0500 Subject: [PATCH 06/12] pkp/pkp-lib#11826 Include restrictToUserGroups and userGroupIds to the payload when saving task template --- .../useTaskTemplateManagerForm.js | 24 +++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/src/managers/TaskTemplateManager/useTaskTemplateManagerForm.js b/src/managers/TaskTemplateManager/useTaskTemplateManagerForm.js index 1dcb2143e..13a9608d8 100644 --- a/src/managers/TaskTemplateManager/useTaskTemplateManagerForm.js +++ b/src/managers/TaskTemplateManager/useTaskTemplateManagerForm.js @@ -37,10 +37,10 @@ export function useTaskTemplateManagerForm({ const dataBody = { title: formData.title, stageId, - isUnrestricted: formData.isUnrestricted, - assignedUserGroupIds: formData.isUnrestricted - ? null - : formData.assignedUserGroupIds, + restrictToUserGroups: formData.restrictToUserGroups, + userGroupIds: formData.restrictToUserGroups + ? formData.userGroupIds + : null, include: formData.include, dueInterval: isTask.value ? formData.dueInterval : null, description: formData.description, @@ -205,32 +205,32 @@ export function useTaskTemplateManagerForm({ isRequired: true, }); - addFieldOptions('isUnrestricted', 'radio', { + addFieldOptions('restrictToUserGroups', 'radio', { groupId: 'details', label: t('admin.workflow.email.userGroup.assign.unrestricted'), description: t('admin.workflow.email.userGroup.unrestricted.template.note'), - name: 'isUnrestricted', + name: 'restrictToUserGroups', options: [ { - value: true, + value: false, label: t('admin.workflow.email.userGroup.assign.unrestricted'), }, { - value: false, + value: true, label: t('admin.workflow.email.userGroup.limitAccess'), }, ], - value: taskTemplate?.isUnrestricted ?? true, + value: !!taskTemplate?.restrictToUserGroups, }); - addFieldOptions('assignedUserGroupIds', 'checkbox', { + addFieldOptions('userGroupIds', 'checkbox', { groupId: 'details', label: t('admin.workflow.email.userGroup.limitAccess'), - name: 'assignedUserGroupIds', + name: 'userGroupIds', options: getUserGroupOptions(), value: taskTemplate?.userGroups?.map(({id}) => id) || [], isRequired: true, - showWhen: ['isUnrestricted', false], + showWhen: ['restrictToUserGroups', true], }); addGroup('taskInformation', { From 0a7963049ac0d1d118625e8343afdd2f93e2e3b0 Mon Sep 17 00:00:00 2001 From: Blesilda Ramirez Date: Wed, 3 Dec 2025 00:14:03 -0500 Subject: [PATCH 07/12] pkp/pkp-lib#11825 Use new participants api to map the participants options --- .../useDiscussionManagerForm.js | 72 +++---------------- 1 file changed, 8 insertions(+), 64 deletions(-) diff --git a/src/managers/DiscussionManager/useDiscussionManagerForm.js b/src/managers/DiscussionManager/useDiscussionManagerForm.js index e7003c203..c77bd96a6 100644 --- a/src/managers/DiscussionManager/useDiscussionManagerForm.js +++ b/src/managers/DiscussionManager/useDiscussionManagerForm.js @@ -6,7 +6,6 @@ import {useUrl} from '@/composables/useUrl'; import {useLocalize} from '@/composables/useLocalize'; import {useFetch} from '@/composables/useFetch'; import {useCurrentUser} from '@/composables/useCurrentUser'; -import {useSubmission} from '@/composables/useSubmission'; import {useDiscussionMessages} from './useDiscussionMessages'; import { useDiscussionManagerStatusUpdater, @@ -35,7 +34,6 @@ export function useDiscussionManagerForm( const {updateStatus, startWorkItem} = useDiscussionManagerStatusUpdater( submission.id, ); - const {getCurrentReviewAssignments} = useSubmission(); const closeModal = inject('closeModal'); const currentUser = useCurrentUser(); @@ -73,35 +71,24 @@ export function useDiscussionManagerForm( function mapParticipantOptions(withSubLabel) { return (participant) => { - const userName = participant.userName && `(${participant.userName})`; - let label = `${participant.fullName} ${userName}`; + const username = participant.username && `(${participant.username})`; + let label = `${participant.fullName} ${username}`; - if (participant.userName === currentUser.getCurrentUserName()) { + if (participant.username === currentUser.getCurrentUserName()) { label += ` (${t('common.me')})`; } return { label, - subLabel: withSubLabel ? participant.roleName : null, - value: participant.id, + subLabel: withSubLabel ? participant.roles?.[0]?.name : null, + value: participant.userId, }; }; } async function getAllParticipants() { - const reviewers = getCurrentReviewAssignments( - submission, - submissionStageId, - ).map((r) => ({ - fullName: r.reviewerFullName, - userName: r.reviewerUserName || '', - id: r.reviewerId, - roleName: t('user.role.reviewer'), - roleId: pkp.const.ROLE_ID_REVIEWER, - })); - const {apiUrl: participantsApiUrl} = useUrl( - `submissions/${encodeURIComponent(submission.id)}/participants/${submissionStageId}`, + `submissions/${encodeURIComponent(submission.id)}/stages/${submissionStageId}/tasks/participants`, ); const {data: participantsData, fetch: fetchParticipants} = @@ -109,50 +96,7 @@ export function useDiscussionManagerForm( await fetchParticipants(); - const isParticipant = participantsData.value?.some( - (p) => p.id === currentUser.getCurrentUserId(), - ); - - // If the current user is a site admin but not already in the participants list, add them as "Unassigned" - // This ensures site admins can always assign tasks to themselves - const siteAdmin = - currentUser.isCurrentUserSiteAdmin() && !isParticipant - ? [ - { - fullName: currentUser.getCurrentUserFullName(), - userName: currentUser.getCurrentUserName(), - id: currentUser.getCurrentUserId(), - roleName: t('submission.status.unassigned'), - roleId: pkp.const.ROLE_ID_SITE_ADMIN, - }, - ] - : []; - - const list = []; - participantsData.value?.forEach((participant) => { - participant.stageAssignments?.forEach((stageAssignment) => { - list.push({ - id: participant.id, - fullName: participant.fullName, - userName: participant.userName, - roleName: stageAssignment.stageAssignmentUserGroup.name, - roleId: stageAssignment.stageAssignmentUserGroup.roleId, - userGroupId: stageAssignment.stageAssignmentUserGroup.id, - }); - }); - }); - - list.sort((participantA, participantB) => { - // First, compare by roleId - if (participantA.roleId !== participantB.roleId) { - return participantA.roleId - participantB.roleId; - } - - // If roleIds are equal, compare by userGroupId - return participantA.userGroupId - participantB.userGroupId; - }); - - return list.concat(siteAdmin).concat(reviewers); + return participantsData.value || []; } const participantOptions = computed(() => @@ -162,7 +106,7 @@ export function useDiscussionManagerForm( const assigneeOptions = computed(() => { return participants.value .filter((participant) => - selectedParticipants.value.includes(participant.id), + selectedParticipants.value.includes(participant.userId), ) .map(mapParticipantOptions()); }); From 3fba8a41e171390925a2f5466b51f8794d666f09 Mon Sep 17 00:00:00 2001 From: Blesilda Ramirez Date: Wed, 3 Dec 2025 01:31:58 -0500 Subject: [PATCH 08/12] pkp/pkp-lib#11825 Filter the task templates by stage using the api --- .../DiscussionManager/useDiscussionManagerForm.js | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/src/managers/DiscussionManager/useDiscussionManagerForm.js b/src/managers/DiscussionManager/useDiscussionManagerForm.js index c77bd96a6..00a099e83 100644 --- a/src/managers/DiscussionManager/useDiscussionManagerForm.js +++ b/src/managers/DiscussionManager/useDiscussionManagerForm.js @@ -168,19 +168,16 @@ export function useDiscussionManagerForm( return []; } - const {apiUrl: taskTemplatesApiUrl} = useUrl('editTaskTemplates'); + const {apiUrl: taskTemplatesApiUrl} = useUrl( + `editTaskTemplates?stageId=${submissionStageId}`, + ); const {data: taskTemplatesData, fetch: fetchTaskTemplates} = useFetch(taskTemplatesApiUrl); fetchTaskTemplates(); - return computed( - () => - taskTemplatesData.value?.data?.filter( - (data) => data.stageId === submissionStageId, - ) || [], - ); + return computed(() => taskTemplatesData.value?.data || []); } async function setValuesFromTemplate(template) { From c34b420c6a7ed94292a235520f209c32d45999c2 Mon Sep 17 00:00:00 2001 From: Blesilda Ramirez Date: Tue, 9 Dec 2025 11:44:42 -0500 Subject: [PATCH 09/12] pkp/pkp-lib#11826 Use participant's user id for comparing with current user --- src/managers/DiscussionManager/useDiscussionManagerForm.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/managers/DiscussionManager/useDiscussionManagerForm.js b/src/managers/DiscussionManager/useDiscussionManagerForm.js index 00a099e83..eb20dc09e 100644 --- a/src/managers/DiscussionManager/useDiscussionManagerForm.js +++ b/src/managers/DiscussionManager/useDiscussionManagerForm.js @@ -74,7 +74,7 @@ export function useDiscussionManagerForm( const username = participant.username && `(${participant.username})`; let label = `${participant.fullName} ${username}`; - if (participant.username === currentUser.getCurrentUserName()) { + if (participant.userId === currentUser.getCurrentUserId()) { label += ` (${t('common.me')})`; } From 9873bc4a88012d9b8e872b5efd9cfb11777e21dc Mon Sep 17 00:00:00 2001 From: Blesilda Ramirez Date: Tue, 9 Dec 2025 11:57:48 -0500 Subject: [PATCH 10/12] pkp/pkp-lib#11826 Display all user roles of the participant --- src/managers/DiscussionManager/useDiscussionManagerForm.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/managers/DiscussionManager/useDiscussionManagerForm.js b/src/managers/DiscussionManager/useDiscussionManagerForm.js index eb20dc09e..57c30d4c1 100644 --- a/src/managers/DiscussionManager/useDiscussionManagerForm.js +++ b/src/managers/DiscussionManager/useDiscussionManagerForm.js @@ -78,9 +78,13 @@ export function useDiscussionManagerForm( label += ` (${t('common.me')})`; } + const participantRoles = participant.roles + ?.map((role) => role.name) + .join(', '); + return { label, - subLabel: withSubLabel ? participant.roles?.[0]?.name : null, + subLabel: withSubLabel ? participantRoles : null, value: participant.userId, }; }; From 02d6fe1c6484d6f1df5593df5ed19442b7a6f26e Mon Sep 17 00:00:00 2001 From: Blesilda Ramirez Date: Tue, 9 Dec 2025 12:52:41 -0500 Subject: [PATCH 11/12] pkp/pkp-lib#11826 Add description to 'Limit access to specific roles' locale key --- public/globals.js | 2 ++ src/managers/TaskTemplateManager/useTaskTemplateManagerForm.js | 1 + 2 files changed, 3 insertions(+) diff --git a/public/globals.js b/public/globals.js index 7d44bcc0c..d0dedf802 100644 --- a/public/globals.js +++ b/public/globals.js @@ -192,6 +192,8 @@ window.pkp = { 'Mark as unrestricted', 'admin.workflow.email.userGroup.limitAccess': 'Limit access to specific roles', + 'admin.workflow.email.userGroup.limitAccess.template.note': + 'Select the roles that can access this template.', 'admin.workflow.email.userGroup.unrestricted.template.note': 'Unrestricted templates will be accessible to all roles.', 'article.article': 'Article', diff --git a/src/managers/TaskTemplateManager/useTaskTemplateManagerForm.js b/src/managers/TaskTemplateManager/useTaskTemplateManagerForm.js index 13a9608d8..fffa6a28a 100644 --- a/src/managers/TaskTemplateManager/useTaskTemplateManagerForm.js +++ b/src/managers/TaskTemplateManager/useTaskTemplateManagerForm.js @@ -226,6 +226,7 @@ export function useTaskTemplateManagerForm({ addFieldOptions('userGroupIds', 'checkbox', { groupId: 'details', label: t('admin.workflow.email.userGroup.limitAccess'), + description: t('admin.workflow.email.userGroup.limitAccess.template.note'), name: 'userGroupIds', options: getUserGroupOptions(), value: taskTemplate?.userGroups?.map(({id}) => id) || [], From b51b8a6bbbb94bd9a885aade32de1446de465c2d Mon Sep 17 00:00:00 2001 From: Blesilda Ramirez Date: Wed, 10 Dec 2025 12:24:07 -0500 Subject: [PATCH 12/12] pkp/pkp-lib#11826 Use common.commaListSeparator for joining participant roles --- src/managers/DiscussionManager/useDiscussionManagerForm.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/managers/DiscussionManager/useDiscussionManagerForm.js b/src/managers/DiscussionManager/useDiscussionManagerForm.js index 57c30d4c1..2b00153aa 100644 --- a/src/managers/DiscussionManager/useDiscussionManagerForm.js +++ b/src/managers/DiscussionManager/useDiscussionManagerForm.js @@ -80,7 +80,7 @@ export function useDiscussionManagerForm( const participantRoles = participant.roles ?.map((role) => role.name) - .join(', '); + .join(t('common.commaListSeparator')); return { label,