diff --git a/packages/sanity/src/core/index.ts b/packages/sanity/src/core/index.ts index 9bd8039b01c..a48fe6d1ae1 100644 --- a/packages/sanity/src/core/index.ts +++ b/packages/sanity/src/core/index.ts @@ -34,11 +34,13 @@ export { isReleasePerspective, isReleaseScheduledOrScheduling, LATEST, + PUBLISHED, type ReleaseDocument, RELEASES_INTENT, RELEASES_STUDIO_CLIENT_OPTIONS, useActiveReleases, useArchivedReleases, + useDocumentVersionList, useDocumentVersions, useIsReleaseActive, useReleasesIds, diff --git a/packages/sanity/src/core/releases/components/VersionInlineBadge.tsx b/packages/sanity/src/core/releases/components/VersionInlineBadge.tsx index c6490855c0a..fcf8d60ba2a 100644 --- a/packages/sanity/src/core/releases/components/VersionInlineBadge.tsx +++ b/packages/sanity/src/core/releases/components/VersionInlineBadge.tsx @@ -12,8 +12,8 @@ const StyledVersionInlineBadge = styled.span<{$tone?: BadgeTone}>((props) => { color: var(--card-badge-${$tone ?? 'default'}-fg-color); background-color: var(--card-badge-${$tone ?? 'default'}-bg-color); border-radius: 3px; - text-decoration: none; padding: 0px 2px; + text-decoration: none; font-weight: 500; ` }) diff --git a/packages/sanity/src/core/releases/hooks/index.ts b/packages/sanity/src/core/releases/hooks/index.ts index 9fd6022cbc8..fb790020e32 100644 --- a/packages/sanity/src/core/releases/hooks/index.ts +++ b/packages/sanity/src/core/releases/hooks/index.ts @@ -1,3 +1,4 @@ +export * from './useDocumentVersionList' export * from './useDocumentVersions' export * from './useIsReleaseActive' export * from './useVersionOperations' diff --git a/packages/sanity/src/core/releases/hooks/useDocumentVersionList.ts b/packages/sanity/src/core/releases/hooks/useDocumentVersionList.ts new file mode 100644 index 00000000000..b6ce485dd5b --- /dev/null +++ b/packages/sanity/src/core/releases/hooks/useDocumentVersionList.ts @@ -0,0 +1,58 @@ +import {useMemo} from 'react' + +import {getVersionFromId, isVersionId} from '../../util/draftUtils' +import {type ReleaseDocument, type ReleaseType} from '../store/types' +import {useActiveReleases} from '../store/useActiveReleases' +import {getReleaseIdFromReleaseDocumentId} from '../util/getReleaseIdFromReleaseDocumentId' +import {useDocumentVersions} from './useDocumentVersions' + +const orderedReleaseTypes: ReleaseType[] = ['asap', 'scheduled', 'undecided'] + +interface useDocumentVersionListState { + sortedDocumentList: ReleaseDocument[] + onlyHasVersions: boolean +} + +/** + * Fetches the document versions for a given document and sorts them by release type + * Returns a boolean if the document has only versions + * + * @param documentId - document id related to the document version list + * @returns object with sortedDocumentList and if the document has only versions + * + * @beta + */ +export const useDocumentVersionList = ({ + documentId, +}: { + documentId: string +}): useDocumentVersionListState => { + const {data: releases} = useActiveReleases() + const {data: documentVersions} = useDocumentVersions({documentId}) + + const sortedDocumentList = releases + .filter(({_id}) => { + return documentVersions.some( + (id) => getVersionFromId(id) === getReleaseIdFromReleaseDocumentId(_id), + ) + }) + .sort((a, b) => { + return ( + orderedReleaseTypes.indexOf(a.metadata.releaseType) - + orderedReleaseTypes.indexOf(b.metadata.releaseType) + ) + }) + + const onlyHasVersions = + documentVersions && + documentVersions.length > 0 && + !documentVersions.some((version) => !isVersionId(version)) + + return useMemo( + () => ({ + sortedDocumentList: sortedDocumentList, + onlyHasVersions, + }), + [sortedDocumentList, onlyHasVersions], + ) +} diff --git a/packages/sanity/src/structure/i18n/resources.ts b/packages/sanity/src/structure/i18n/resources.ts index c507db49a95..8355b123970 100644 --- a/packages/sanity/src/structure/i18n/resources.ts +++ b/packages/sanity/src/structure/i18n/resources.ts @@ -136,6 +136,14 @@ const structureLocaleStrings = defineLocalesResources('structure', { 'This reference has been removed since you opened it.', /** The text that appears for the action button to add the current document to the global release */ 'banners.release.action.add-to-release': 'Add to release', + /** The text that appears for the action button to add the current document to the global release */ + 'banners.release.action.open-to-edit': 'Open release to edit', + /** The text for the banner that appears when a document only has versions but is in a draft or published pinned release */ + 'banners.release.navigate-to-edit-description': 'The document only exists in the', + /** The text for the banner that appears when a document only has versions but is in a draft or published pinned release */ + 'banners.release.navigate-to-edit-description-end_one': 'release', + /** The text for the banner that appears when a document only has versions but is in a draft or published pinned release */ + 'banners.release.navigate-to-edit-description-end_other': 'releases', /** The text for the banner that appears when a document is not in the current global release */ 'banners.release.not-in-release': 'Not in the {{title}} release.', diff --git a/packages/sanity/src/structure/panes/document/DocumentPaneProvider.tsx b/packages/sanity/src/structure/panes/document/DocumentPaneProvider.tsx index 9a7e5004285..a457ba74d8f 100644 --- a/packages/sanity/src/structure/panes/document/DocumentPaneProvider.tsx +++ b/packages/sanity/src/structure/panes/document/DocumentPaneProvider.tsx @@ -22,6 +22,7 @@ import { getDraftId, getExpandOperations, getPublishedId, + getReleaseIdFromReleaseDocumentId, getVersionFromId, isGoingToUnpublish, isPublishedPerspective, @@ -39,6 +40,8 @@ import { useCopyPaste, useDocumentOperation, useDocumentValuePermissions, + useDocumentVersionList, + useDocumentVersions, useEditState, useFormState, useInitialValue, @@ -126,6 +129,7 @@ export const DocumentPaneProvider = memo((props: DocumentPaneProviderProps) => { const params = useUnique(paneRouter.params) || EMPTY_PARAMS const perspective = usePerspective() + const {data: documentVersions} = useDocumentVersions({documentId}) const {isReleaseLocked, selectedReleaseId, selectedPerspectiveName} = useMemo(() => { // TODO: COREL - Remove this after updating sanity-assist to use @@ -169,9 +173,34 @@ export const DocumentPaneProvider = memo((props: DocumentPaneProviderProps) => { const initialValue = useUnique(initialValueRaw) const isInitialValueLoading = initialValue.loading + // if it only has versions then we need to make sure that whatever the first document that is allowed + // is a version document, but also that it has the right order + // this will make sure that then the right document appears and so does the right chip within the document header + const {sortedDocumentList, onlyHasVersions} = useDocumentVersionList({documentId}) + const firstVersion = + sortedDocumentList.length > 0 + ? documentVersions.find( + (id) => + getVersionFromId(id) === getReleaseIdFromReleaseDocumentId(sortedDocumentList[0]._id), + ) + : undefined + const {patch} = useDocumentOperation(documentId, documentType, selectedReleaseId) const schemaType = schema.get(documentType) as ObjectSchemaType | undefined - const editState = useEditState(documentId, documentType, 'default', selectedReleaseId) + const id = useMemo(() => { + if (selectedReleaseId) { + return selectedReleaseId + } + // check if the selected version is the only version, if it isn't and it doesn't exist in hte release + // then it needs to use the documentVersions + if (!documentVersions || !onlyHasVersions) { + return selectedReleaseId + } + return getVersionFromId(firstVersion ?? '') + }, [documentVersions, onlyHasVersions, selectedReleaseId, firstVersion]) + + const editState = useEditState(documentId, documentType, 'default', id) + const {validation: validationRaw} = useValidationStatus( documentId, documentType, @@ -190,6 +219,10 @@ export const DocumentPaneProvider = memo((props: DocumentPaneProviderProps) => { (liveEdit ? initialValue.value : {_id: documentId, _type: documentType}) ) } + // if no version is selected, but there is only version, it should default to the version version it finds + if (!selectedPerspectiveName && onlyHasVersions) { + return editState.version || editState.draft || editState.published || initialValue.value + } return editState.draft || editState.published || initialValue.value }, [ documentId, @@ -199,6 +232,7 @@ export const DocumentPaneProvider = memo((props: DocumentPaneProviderProps) => { editState.version, initialValue.value, liveEdit, + onlyHasVersions, selectedPerspectiveName, selectedReleaseId, ]) @@ -607,6 +641,10 @@ export const DocumentPaneProvider = memo((props: DocumentPaneProviderProps) => { return true } + if (!selectedPerspectiveName && onlyHasVersions) { + return true + } + return ( willBeUnpublished || !ready || @@ -633,6 +671,7 @@ export const DocumentPaneProvider = memo((props: DocumentPaneProviderProps) => { selectedPerspectiveName, selectedReleaseId, value._id, + onlyHasVersions, willBeUnpublished, ready, revisionId, diff --git a/packages/sanity/src/structure/panes/document/documentPanel/DocumentPanel.tsx b/packages/sanity/src/structure/panes/document/documentPanel/DocumentPanel.tsx index 95f1cfa0e7b..fbddc5eebb4 100644 --- a/packages/sanity/src/structure/panes/document/documentPanel/DocumentPanel.tsx +++ b/packages/sanity/src/structure/panes/document/documentPanel/DocumentPanel.tsx @@ -6,6 +6,7 @@ import { isReleaseScheduledOrScheduling, type ReleaseDocument, ScrollContainer, + useDocumentVersionList, usePerspective, VirtualizerScrollInstanceProvider, } from 'sanity' @@ -26,6 +27,7 @@ import { import {AddToReleaseBanner} from './banners/AddToReleaseBanner' import {ArchivedReleaseDocumentBanner} from './banners/ArchivedReleaseDocumentBanner' import {DraftLiveEditBanner} from './banners/DraftLiveEditBanner' +import {OpenReleaseToEditBanner} from './banners/OpenReleaseToEditBanner' import {ScheduledReleaseBanner} from './banners/ScheduledReleaseBanner' import {UnpublishedDocumentBanner} from './banners/UnpublishedDocumentBanner' import {FormView} from './documentViews' @@ -80,6 +82,7 @@ export const DocumentPanel = function DocumentPanel(props: DocumentPanelProps) { const [_portalElement, setPortalElement] = useState(null) const [documentScrollElement, setDocumentScrollElement] = useState(null) const formContainerElement = useRef(null) + const {onlyHasVersions} = useDocumentVersionList({documentId}) const requiredPermission = value._createdAt ? 'update' : 'create' @@ -150,18 +153,23 @@ export const DocumentPanel = function DocumentPanel(props: DocumentPanelProps) { if (params?.historyVersion) { return } - const isCreatingDocument = displayed && !displayed._createdAt const isScheduledRelease = isReleaseDocument(selectedPerspective) && isReleaseScheduledOrScheduling(selectedPerspective) - if (isScheduledRelease) { return } + const isDraftOrPublish: boolean = + selectedPerspective === 'drafts' || selectedPerspective === 'published' + + if (isDraftOrPublish && onlyHasVersions) { + return + } + if ( displayed?._id && getVersionFromId(displayed._id) !== selectedReleaseId && ready && - !isCreatingDocument + !isDraftOrPublish ) { return ( activeReleases.find((version) => version._id.includes(releaseId)), + [activeReleases, releaseId], + ) + const {data: documentVersions} = useDocumentVersions({documentId}) + + const documentVersionsTitleList = useMemo( + () => + activeReleases + .filter((version) => { + return documentVersions.find((release) => { + const r = getVersionFromId(release) ?? '' + return version._id.includes(r) + }) + }) + .map((version) => version.metadata.title), + [activeReleases, documentVersions], + ) + const tone = currentVersion && getReleaseTone(currentVersion) + const {t} = useTranslation(structureLocaleNamespace) + + const handleGoToEdit = useCallback(async () => { + setPerspective(releaseId as ReleaseId) + }, [releaseId, setPerspective]) + + if (isDraftId(documentId) || isPublishedId(documentId)) { + return null + } + + return ( + + + + {t('banners.release.navigate-to-edit-description')} + {documentVersionsTitleList.map((title) => ( + {title} + ))} + {t('banners.release.navigate-to-edit-description-end', { + count: documentVersionsTitleList.length, + })} + + + +