diff --git a/addons/core/translations/resources/en-us.yaml b/addons/core/translations/resources/en-us.yaml index e4119f53d..6cc9cc3f0 100644 --- a/addons/core/translations/resources/en-us.yaml +++ b/addons/core/translations/resources/en-us.yaml @@ -758,13 +758,13 @@ role: id-actions: ID Actions create: Create a new {resourceType} list: List all {resourceType} resources - read: Read a {resourceType} - update: Update a {resourceType} - delete: Delete a {resourceType} + read: Read {article} {resourceType} + update: Update {article} {resourceType} + delete: Delete {article} {resourceType} read:self: Read the {resourceType} associated with the current user - delete:self: Delete a {resourceType} associated with the current user - cancel: Cancel a {resourceType} - cancel:self: Cancel a {resourceType} associated with the current user + delete:self: Delete {article} {resourceType} associated with the current user + cancel: Cancel {article} {resourceType} + cancel:self: Cancel {article} {resourceType} associated with the current user generic: create: Creates resources list: Lists resources @@ -773,6 +773,8 @@ role: delete: Deletes resources read:self: Read the resource associated with the current user delete:self: Delete a resource associated with the current user + cancel: Cancels resources + cancel:self: Cancel a resource associated with the current user add-members: Add members to a group set-members: Set the full list of members on a group remove-members: Remove members from a group diff --git a/ui/admin/app/components/grant-actions/index.js b/ui/admin/app/components/grant-actions/index.js index 18191cc46..9d703c574 100644 --- a/ui/admin/app/components/grant-actions/index.js +++ b/ui/admin/app/components/grant-actions/index.js @@ -53,7 +53,14 @@ export default class GrantActionsIndex extends Component { const genericKey = `resources.role.edit-grants.actions.generic.${action}`; if (detectedResourceType && this.intl.exists(specificKey)) { - return this.intl.t(specificKey, { resourceType: detectedResourceType }); + const resourceType = Array.isArray(detectedResourceType) + ? this.intl.formatList(detectedResourceType, { type: 'disjunction' }) + : detectedResourceType; + // Determine the appropriate article ("a" or "an") to use based on the + // detected resource type. "user" is a special case that uses "a" instead + // of "an" because it's pronounced "you" so I don't include it below. + const article = /^[aeio]/i.test(resourceType) ? 'an' : 'a'; + return this.intl.t(specificKey, { resourceType, article }); } if (this.intl.exists(genericKey)) { diff --git a/ui/admin/app/utils/grant-completions.js b/ui/admin/app/utils/grant-completions.js index 0ad07ffce..9abf0d56f 100644 --- a/ui/admin/app/utils/grant-completions.js +++ b/ui/admin/app/utils/grant-completions.js @@ -290,21 +290,29 @@ export const analyzeGrantString = (grantsSchema, grantString = '') => { schema.childResourceTypesByParentType[compatibleIdsResourceType] ?? [] ).includes(typeValue); - const detectedResourceType = - typeValue && typeValue !== '*' - ? typeValue - : idsValue - ? getCompatibleResourceTypeForIds(schema, idsValue) - : null; + let detectedResourceType = null; + if (typeValue && typeValue !== '*') { + // Explicit type specified, use it directly + detectedResourceType = typeValue; + } else if (compatibleIdsResourceType && typeValue === '*') { + // Pinned IDs with wildcard type, return the child resource types + const childTypes = + schema.childResourceTypesByParentType[compatibleIdsResourceType] ?? []; + detectedResourceType = childTypes.length ? childTypes : null; + } else if (typeValue !== '*' && idsValue) { + // No type field, infer resource type from the ID prefix + detectedResourceType = getCompatibleResourceTypeForIds(schema, idsValue); + } - const isBothWildcard = idsValue === '*' && typeValue === '*'; + const hasWildcardIds = idsValue === '*'; + const crudlOnly = hasWildcardIds && !hasExplicitType; const actions = idsValue || typeValue ? getActionOptions(schema, typeValue, idsValue) .filter( (action) => - action !== '*' && (!isBothWildcard || CRUDL_ACTIONS.has(action)), + action !== '*' && (!crudlOnly || CRUDL_ACTIONS.has(action)), ) .sort((left, right) => left.localeCompare(right)) : [];