diff --git a/packages/sanity/src/core/releases/components/documentHeader/VersionChip.tsx b/packages/sanity/src/core/releases/components/documentHeader/VersionChip.tsx index cda8dbe7655..c0ed3ef75a0 100644 --- a/packages/sanity/src/core/releases/components/documentHeader/VersionChip.tsx +++ b/packages/sanity/src/core/releases/components/documentHeader/VersionChip.tsx @@ -232,6 +232,7 @@ export const VersionChip = memo(function VersionChip(props: { disabled={contextMenuDisabled} onCreateVersion={handleAddVersion} locked={locked} + type={documentType} /> } fallbackPlacements={[]} diff --git a/packages/sanity/src/core/releases/components/documentHeader/contextMenu/VersionContextMenu.tsx b/packages/sanity/src/core/releases/components/documentHeader/contextMenu/VersionContextMenu.tsx index ec3bffc1fe8..48dbd591eab 100644 --- a/packages/sanity/src/core/releases/components/documentHeader/contextMenu/VersionContextMenu.tsx +++ b/packages/sanity/src/core/releases/components/documentHeader/contextMenu/VersionContextMenu.tsx @@ -7,7 +7,8 @@ import {styled} from 'styled-components' import {MenuGroup} from '../../../../../ui-components/menuGroup/MenuGroup' import {MenuItem} from '../../../../../ui-components/menuItem/MenuItem' import {useTranslation} from '../../../../i18n/hooks/useTranslation' -import {isPublishedId} from '../../../../util/draftUtils' +import {useDocumentPairPermissions} from '../../../../store/_legacy/grants/documentPairPermissions' +import {getPublishedId, isDraftId, isPublishedId} from '../../../../util/draftUtils' import {useReleasesUpsell} from '../../../contexts/upsell/useReleasesUpsell' import {type ReleaseDocument} from '../../../store/types' import {useReleaseOperations} from '../../../store/useReleaseOperations' @@ -33,6 +34,7 @@ export const VersionContextMenu = memo(function VersionContextMenu(props: { onCreateVersion: (targetId: string) => void disabled?: boolean locked?: boolean + type: string }) { const { documentId, @@ -45,6 +47,7 @@ export const VersionContextMenu = memo(function VersionContextMenu(props: { onCreateVersion, disabled, locked, + type, } = props const {t} = useTranslation() const {mode} = useReleasesUpsell() @@ -58,6 +61,13 @@ export const VersionContextMenu = memo(function VersionContextMenu(props: { const [hasCreatePermission, setHasCreatePermission] = useState(null) const releaseId = isVersion ? fromRelease : documentId + const [permissions, isPermissionsLoading] = useDocumentPairPermissions({ + id: getPublishedId(documentId), + type, + version: releaseId, + permission: isDraftId(documentId) ? 'discardDraft' : 'discardVersion', + }) + const hasDiscardPermission = !isPermissionsLoading && permissions?.granted useEffect(() => { checkWithPermissionGuard(createRelease, DEFAULT_RELEASE).then(setHasCreatePermission) @@ -115,7 +125,10 @@ export const VersionContextMenu = memo(function VersionContextMenu(props: { icon={TrashIcon} onClick={onDiscard} text={t('release.action.discard-version')} - disabled={disabled || locked} + disabled={disabled || locked || !hasDiscardPermission} + tooltipProps={{ + content: !hasDiscardPermission && t('release.action.permission.error'), + }} /> )} diff --git a/packages/sanity/src/core/releases/components/documentHeader/contextMenu/__tests__/VersionContextMenu.test.tsx b/packages/sanity/src/core/releases/components/documentHeader/contextMenu/__tests__/VersionContextMenu.test.tsx index 0cc84480f05..ba54c6b5828 100644 --- a/packages/sanity/src/core/releases/components/documentHeader/contextMenu/__tests__/VersionContextMenu.test.tsx +++ b/packages/sanity/src/core/releases/components/documentHeader/contextMenu/__tests__/VersionContextMenu.test.tsx @@ -1,6 +1,7 @@ import {act, fireEvent, render, screen, waitFor} from '@testing-library/react' import {describe, expect, it, vi} from 'vitest' +import {useDocumentPairPermissionsMockReturn} from '../../../../../../../test/mocks/useDocumentPairPermissions.mock' import {createTestProvider} from '../../../../../../../test/testUtils/TestProvider' import { mockUseReleasePermissions, @@ -21,6 +22,10 @@ vi.mock('../../../../store/useReleasePermissions', () => ({ useReleasePermissions: vi.fn(() => useReleasePermissionsMockReturn), })) +vi.mock('../../../../../store/_legacy/grants/documentPairPermissions', () => ({ + useDocumentPairPermissions: vi.fn(() => useDocumentPairPermissionsMockReturn), +})) + describe('VersionContextMenu', () => { const mockReleases: ReleaseDocument[] = [ { @@ -63,6 +68,7 @@ describe('VersionContextMenu', () => { onCreateRelease: vi.fn(), onCreateVersion: vi.fn(), disabled: false, + type: 'document', } it('renders the menu items correctly', async () => { @@ -94,6 +100,7 @@ describe('VersionContextMenu', () => { mockUseReleasePermissions.mockReturnValue({ checkWithPermissionGuard: async () => true, }) + const wrapper = await createTestProvider() render(, {wrapper}) @@ -118,6 +125,7 @@ describe('VersionContextMenu', () => { mockUseReleasePermissions.mockReturnValue({ checkWithPermissionGuard: async () => true, }) + const wrapper = await createTestProvider() const publishedProps = { ...defaultProps, @@ -134,11 +142,16 @@ describe('VersionContextMenu', () => { mockUseReleasePermissions.mockReturnValue({ checkWithPermissionGuard: async () => true, }) + const wrapper = await createTestProvider() render(, {wrapper}) await waitFor(() => { + expect(screen.getByText('Discard version')).not.toBeDisabled() + }) + + await act(() => { fireEvent.click(screen.getByText('Discard version')) }) expect(defaultProps.onDiscard).toHaveBeenCalled() @@ -148,6 +161,7 @@ describe('VersionContextMenu', () => { mockUseReleasePermissions.mockReturnValue({ checkWithPermissionGuard: async () => true, }) + const wrapper = await createTestProvider() render(, {wrapper}) @@ -172,6 +186,7 @@ describe('VersionContextMenu', () => { mockUseReleasePermissions.mockReturnValue({ checkWithPermissionGuard: async () => true, }) + const wrapper = await createTestProvider() render(, {wrapper}) diff --git a/packages/sanity/test/mocks/useDocumentPairPermissions.mock.ts b/packages/sanity/test/mocks/useDocumentPairPermissions.mock.ts new file mode 100644 index 00000000000..75c545b3f29 --- /dev/null +++ b/packages/sanity/test/mocks/useDocumentPairPermissions.mock.ts @@ -0,0 +1,11 @@ +import {type Mock, type Mocked} from 'vitest' + +import {useDocumentPairPermissions} from '../../src/core/store/_legacy/grants/documentPairPermissions' + +export const useDocumentPairPermissionsMockReturn: Mocked< + ReturnType +> = [{granted: true, reason: ''}, false] + +export const mockUseDocumentPairPermissions = useDocumentPairPermissions as Mock< + typeof useDocumentPairPermissions +>