diff --git a/dev/test-studio/sanity.config.ts b/dev/test-studio/sanity.config.ts index 97c3227d51a..be509dbbe81 100644 --- a/dev/test-studio/sanity.config.ts +++ b/dev/test-studio/sanity.config.ts @@ -165,7 +165,7 @@ const defaultWorkspace = { // eslint-disable-next-line camelcase __internal_serverDocumentActions: { // TODO: Switched off because Actions API doesn't support versions (yet). - enabled: false, + enabled: true, }, scheduledPublishing: { enabled: true, diff --git a/packages/sanity/src/core/releases/__telemetry__/releases.telemetry.ts b/packages/sanity/src/core/releases/__telemetry__/releases.telemetry.ts index b23fad4d8d1..8fe0680192e 100644 --- a/packages/sanity/src/core/releases/__telemetry__/releases.telemetry.ts +++ b/packages/sanity/src/core/releases/__telemetry__/releases.telemetry.ts @@ -1,15 +1,16 @@ import {defineEvent} from '@sanity/telemetry' +import {type VersionOriginTypes} from '../../store' + interface VersionInfo { /** * document type that was added */ - schemaType: string /** * the origin of the version created (from a draft or from a version) */ - documentOrigin: 'draft' | 'version' + documentOrigin: VersionOriginTypes } export interface OriginInfo { diff --git a/packages/sanity/src/core/releases/components/dialog/DiscardVersionDialog.tsx b/packages/sanity/src/core/releases/components/dialog/DiscardVersionDialog.tsx index b723db356cc..4f8fcf308c8 100644 --- a/packages/sanity/src/core/releases/components/dialog/DiscardVersionDialog.tsx +++ b/packages/sanity/src/core/releases/components/dialog/DiscardVersionDialog.tsx @@ -6,8 +6,10 @@ import {LoadingBlock} from '../../../components' import {useSchema} from '../../../hooks' import {useTranslation} from '../../../i18n' import {Preview} from '../../../preview' -import {useVersionOperations} from '../../hooks' +import {type ReleaseDocument} from '../../../store' +import {usePerspective, useVersionOperations} from '../../hooks' import {releasesLocaleNamespace} from '../../i18n' +import {getBundleIdFromReleaseDocumentId} from '../../util/getBundleIdFromReleaseDocumentId' /** * @internal @@ -20,7 +22,8 @@ export function DiscardVersionDialog(props: { const {onClose, documentId, documentType} = props const {t} = useTranslation(releasesLocaleNamespace) - const {discardVersion} = useVersionOperations(documentId, documentType) + const {currentGlobalBundle} = usePerspective() + const {discardVersion} = useVersionOperations() const schema = useSchema() const [isDiscarding, setIsDiscarding] = useState(false) @@ -29,11 +32,14 @@ export function DiscardVersionDialog(props: { const handleDiscardVersion = useCallback(async () => { setIsDiscarding(true) - discardVersion() + await discardVersion( + getBundleIdFromReleaseDocumentId((currentGlobalBundle as ReleaseDocument)._id), + documentId, + ) setIsDiscarding(false) onClose() - }, [discardVersion, onClose]) + }, [currentGlobalBundle, discardVersion, documentId, onClose]) return ( void /* change the perspective in the studio based on a release ID */ - setPerspectiveFromRelease: (releaseId: string) => void + setPerspectiveFromReleaseDocumentId: (releaseDocumentId: string) => void + setPerspectiveFromReleaseId: (releaseId: string) => void /* Add/remove excluded perspectives */ toggleExcludedPerspective: (perspectiveId: string) => void /* Check if a perspective is excluded */ @@ -94,11 +95,16 @@ export function usePerspective(): PerspectiveValue { [perspective, selectedBundle], ) - const setPerspectiveFromRelease = useCallback( - (releaseId: string) => setPerspective(getBundleIdFromReleaseDocumentId(releaseId)), + const setPerspectiveFromReleaseId = useCallback( + (releaseId: string) => setPerspective(releaseId), [setPerspective], ) + const setPerspectiveFromReleaseDocumentId = useCallback( + (releaseId: string) => setPerspectiveFromReleaseId(getBundleIdFromReleaseDocumentId(releaseId)), + [setPerspectiveFromReleaseId], + ) + const bundlesPerspective = useMemo( () => getReleasesPerspective({ @@ -142,7 +148,8 @@ export function usePerspective(): PerspectiveValue { perspective, excludedPerspectives, setPerspective, - setPerspectiveFromRelease, + setPerspectiveFromReleaseDocumentId: setPerspectiveFromReleaseDocumentId, + setPerspectiveFromReleaseId: setPerspectiveFromReleaseId, toggleExcludedPerspective, currentGlobalBundle, currentGlobalBundleId: isPublishedPerspective(currentGlobalBundle) @@ -154,12 +161,13 @@ export function usePerspective(): PerspectiveValue { [ perspective, excludedPerspectives, - bundlesPerspective, - currentGlobalBundle, - isPerspectiveExcluded, setPerspective, - setPerspectiveFromRelease, + setPerspectiveFromReleaseDocumentId, + setPerspectiveFromReleaseId, toggleExcludedPerspective, + currentGlobalBundle, + bundlesPerspective, + isPerspectiveExcluded, ], ) } diff --git a/packages/sanity/src/core/releases/hooks/useVersionOperations.tsx b/packages/sanity/src/core/releases/hooks/useVersionOperations.tsx index 9d8df6e4d94..fc55106563d 100644 --- a/packages/sanity/src/core/releases/hooks/useVersionOperations.tsx +++ b/packages/sanity/src/core/releases/hooks/useVersionOperations.tsx @@ -1,67 +1,45 @@ import {useTelemetry} from '@sanity/telemetry/react' import {useToast} from '@sanity/ui' -import {filter, firstValueFrom} from 'rxjs' -import {useClient, useDocumentOperation} from '../../hooks' import {Translate, useTranslation} from '../../i18n' -import {useDocumentStore} from '../../store' -import {DEFAULT_STUDIO_CLIENT_OPTIONS} from '../../studioClient' -import {getPublishedId, getVersionFromId, getVersionId} from '../../util' +import {useReleaseOperations} from '../../store' import {AddedVersion} from '../__telemetry__/releases.telemetry' -import {getBundleIdFromReleaseDocumentId} from '../util/getBundleIdFromReleaseDocumentId' import {getCreateVersionOrigin} from '../util/util' import {usePerspective} from './usePerspective' /** @internal */ -export function useVersionOperations( - documentId: string, - documentType: string, -): { - createVersion: (releaseId: string) => void - discardVersion: () => void +export function useVersionOperations(): { + createVersion: (releaseId: string, documentId: string) => Promise + discardVersion: (releaseId: string, documentId: string) => Promise } { - const publishedId = getPublishedId(documentId) - - const documentStore = useDocumentStore() const telemetry = useTelemetry() - const {createVersion} = useDocumentOperation( - publishedId, - documentType, - getVersionFromId(documentId), - ) - const {setPerspectiveFromRelease, setPerspective} = usePerspective() + const {createVersion, discardVersion} = useReleaseOperations() + + const {setPerspectiveFromReleaseId} = usePerspective() const toast = useToast() - const client = useClient(DEFAULT_STUDIO_CLIENT_OPTIONS) const {t} = useTranslation() - const {currentGlobalBundle} = usePerspective() - - const handleCreateVersion = async (releaseId: string) => { - // set up the listener before executing to make sure it's successful - const createVersionSuccess = firstValueFrom( - documentStore.pair - .operationEvents(getPublishedId(documentId), documentType) - .pipe(filter((e) => e.op === 'createVersion' && e.type === 'success')), - ) - - const docId = getVersionId(publishedId, getBundleIdFromReleaseDocumentId(releaseId)) + const handleCreateVersion = async (releaseId: string, documentId: string) => { const origin = getCreateVersionOrigin(documentId) - createVersion.execute(docId, origin) - - // only change if the version was created successfully - await createVersionSuccess - setPerspectiveFromRelease(releaseId) - - telemetry.log(AddedVersion, { - schemaType: documentType, - documentOrigin: origin, - }) + try { + await createVersion(releaseId, documentId) + setPerspectiveFromReleaseId(releaseId) + telemetry.log(AddedVersion, { + documentOrigin: origin, + }) + } catch (err) { + toast.push({ + closable: true, + status: 'error', + title: t('release.action.create-version.failure'), + description: err.message, + }) + } } - const handleDiscardVersion = async () => { + const handleDiscardVersion = async (releaseId: string, documentId: string) => { try { - /** @todo eventually change this from using document operations */ - await client.delete(documentId) + await discardVersion(releaseId, documentId) toast.push({ closable: true, @@ -74,11 +52,12 @@ export function useVersionOperations( /> ), }) - } catch (e) { + } catch (err) { toast.push({ closable: true, status: 'error', title: t('release.action.discard-version.failure'), + description: err.message, }) } } diff --git a/packages/sanity/src/core/releases/navbar/GlobalPerspectiveMenuItem.tsx b/packages/sanity/src/core/releases/navbar/GlobalPerspectiveMenuItem.tsx index d4708e4f5ee..f19905a6b0d 100644 --- a/packages/sanity/src/core/releases/navbar/GlobalPerspectiveMenuItem.tsx +++ b/packages/sanity/src/core/releases/navbar/GlobalPerspectiveMenuItem.tsx @@ -83,7 +83,7 @@ export const GlobalPerspectiveMenuItem = forwardRef< const {release, rangePosition} = props const { currentGlobalBundleId, - setPerspectiveFromRelease, + setPerspectiveFromReleaseDocumentId, setPerspective, toggleExcludedPerspective, isPerspectiveExcluded, @@ -124,8 +124,8 @@ export const GlobalPerspectiveMenuItem = forwardRef< () => isReleasePublishedPerspective ? setPerspective(releaseId) - : setPerspectiveFromRelease(releaseId), - [releaseId, isReleasePublishedPerspective, setPerspective, setPerspectiveFromRelease], + : setPerspectiveFromReleaseDocumentId(releaseId), + [releaseId, isReleasePublishedPerspective, setPerspective, setPerspectiveFromReleaseDocumentId], ) const canReleaseBeExcluded = !isPublishedPerspective(release) && inRange && !last diff --git a/packages/sanity/src/core/releases/tool/detail/AddDocumentSearch.tsx b/packages/sanity/src/core/releases/tool/detail/AddDocumentSearch.tsx index 08d6aaeb526..4cea77f5e4d 100644 --- a/packages/sanity/src/core/releases/tool/detail/AddDocumentSearch.tsx +++ b/packages/sanity/src/core/releases/tool/detail/AddDocumentSearch.tsx @@ -24,9 +24,9 @@ export function AddDocumentSearch({ const telemetry = useTelemetry() const addDocument = useCallback( - (item: Pick) => { + async (item: Pick) => { try { - createVersion(item._id, getBundleIdFromReleaseDocumentId(releaseId)) + await createVersion(getBundleIdFromReleaseDocumentId(releaseId), item._id) toast.push({ closable: true, @@ -37,7 +37,6 @@ export function AddDocumentSearch({ const origin = getCreateVersionOrigin(item._id) telemetry.log(AddedVersion, { - schemaType: item._type, documentOrigin: origin, }) } catch (error) { diff --git a/packages/sanity/src/core/releases/tool/detail/ReleaseDashboardDetails.tsx b/packages/sanity/src/core/releases/tool/detail/ReleaseDashboardDetails.tsx index f94229f0371..383688b4a81 100644 --- a/packages/sanity/src/core/releases/tool/detail/ReleaseDashboardDetails.tsx +++ b/packages/sanity/src/core/releases/tool/detail/ReleaseDashboardDetails.tsx @@ -23,15 +23,16 @@ export function ReleaseDashboardDetails({release}: {release: ReleaseDocument}) { const {t: tRelease} = useTranslation(releasesLocaleNamespace) - const {currentGlobalBundleId, setPerspective, setPerspectiveFromRelease} = usePerspective() + const {currentGlobalBundleId, setPerspective, setPerspectiveFromReleaseDocumentId} = + usePerspective() const handlePinRelease = useCallback(() => { if (_id === currentGlobalBundleId) { setPerspective('drafts') } else { - setPerspectiveFromRelease(_id) + setPerspectiveFromReleaseDocumentId(_id) } - }, [_id, currentGlobalBundleId, setPerspective, setPerspectiveFromRelease]) + }, [_id, currentGlobalBundleId, setPerspective, setPerspectiveFromReleaseDocumentId]) return ( diff --git a/packages/sanity/src/core/releases/tool/overview/ReleasesOverviewColumnDefs.tsx b/packages/sanity/src/core/releases/tool/overview/ReleasesOverviewColumnDefs.tsx index 480c7e79033..9916243629c 100644 --- a/packages/sanity/src/core/releases/tool/overview/ReleasesOverviewColumnDefs.tsx +++ b/packages/sanity/src/core/releases/tool/overview/ReleasesOverviewColumnDefs.tsx @@ -48,7 +48,8 @@ const ReleaseNameCell: Column['cell'] = ({cellProps, datum: releas const router = useRouter() const {t} = useTranslation(releasesLocaleNamespace) const {t: tCore} = useTranslation() - const {currentGlobalBundleId, setPerspective, setPerspectiveFromRelease} = usePerspective() + const {currentGlobalBundleId, setPerspective, setPerspectiveFromReleaseDocumentId} = + usePerspective() const {state, _id} = release const isArchived = state === 'archived' @@ -56,9 +57,9 @@ const ReleaseNameCell: Column['cell'] = ({cellProps, datum: releas if (_id === currentGlobalBundleId) { setPerspective('drafts') } else { - setPerspectiveFromRelease(_id) + setPerspectiveFromReleaseDocumentId(_id) } - }, [_id, currentGlobalBundleId, setPerspective, setPerspectiveFromRelease]) + }, [_id, currentGlobalBundleId, setPerspective, setPerspectiveFromReleaseDocumentId]) const cardProps: TableRowProps = release.isDeleted ? {tone: 'transparent'} diff --git a/packages/sanity/src/core/store/_legacy/document/document-pair/operationEvents.ts b/packages/sanity/src/core/store/_legacy/document/document-pair/operationEvents.ts index c3999755fac..7f11426628e 100644 --- a/packages/sanity/src/core/store/_legacy/document/document-pair/operationEvents.ts +++ b/packages/sanity/src/core/store/_legacy/document/document-pair/operationEvents.ts @@ -26,7 +26,6 @@ import {consistencyStatus} from './consistencyStatus' import {operationArgs} from './operationArgs' import {type OperationArgs, type OperationsAPI} from './operations' import {commit} from './operations/commit' -import {createVersion} from './operations/createVersion' import {del} from './operations/delete' import {discardChanges} from './operations/discardChanges' import {duplicate} from './operations/duplicate' @@ -62,7 +61,6 @@ const operationImpls = { unpublish, duplicate, restore, - createVersion, } as const //as we add server operations one by one, we can add them here diff --git a/packages/sanity/src/core/store/_legacy/document/document-pair/operations/createVersion.ts b/packages/sanity/src/core/store/_legacy/document/document-pair/operations/createVersion.ts deleted file mode 100644 index fd5f5e4627d..00000000000 --- a/packages/sanity/src/core/store/_legacy/document/document-pair/operations/createVersion.ts +++ /dev/null @@ -1,44 +0,0 @@ -import {omit} from 'lodash' - -import {type OperationImpl, type VersionOriginTypes} from './types' - -const omitProps = ['_createdAt', '_updatedAt'] - -export const createVersion: OperationImpl< - [baseDocumentId: string, origin?: VersionOriginTypes], - 'NO_NEW_VERSION' -> = { - disabled: ({snapshots}) => { - return snapshots.published || snapshots.draft ? false : 'NO_NEW_VERSION' - }, - execute: ( - {schema, client, snapshots, typeName}, - ...extra: [documentId: string, origin: VersionOriginTypes] - ) => { - const [documentId, origin] = extra - const sourceMap = { - version: snapshots.version, - draft: snapshots.draft, - published: snapshots.published, - } - - const source = sourceMap[origin] || snapshots.draft || snapshots.published - - if (!source) { - throw new Error('cannot execute on empty document') - } - - return client.observable.create( - { - ...omit(source, omitProps), - // we don't need to get a draft id or check live editing, we'll always want to create a new version based on the dupeId - // we have guardrails for this on the front - _id: documentId, - _type: source._type, - }, - { - tag: 'document.createVersion', - }, - ) - }, -} diff --git a/packages/sanity/src/core/store/_legacy/document/document-pair/operations/helpers.ts b/packages/sanity/src/core/store/_legacy/document/document-pair/operations/helpers.ts index 3d4617d8563..4c5c970cacd 100644 --- a/packages/sanity/src/core/store/_legacy/document/document-pair/operations/helpers.ts +++ b/packages/sanity/src/core/store/_legacy/document/document-pair/operations/helpers.ts @@ -8,19 +8,12 @@ import {publish as serverPublish} from '../serverOperations/publish' import {restore as serverRestore} from '../serverOperations/restore' import {unpublish as serverUnpublish} from '../serverOperations/unpublish' import {commit} from './commit' -import {createVersion} from './createVersion' import {del} from './delete' import {discardChanges} from './discardChanges' import {duplicate} from './duplicate' import {patch} from './patch' import {restore} from './restore' -import { - type Operation, - type OperationArgs, - type OperationImpl, - type OperationsAPI, - type VersionOriginTypes, -} from './types' +import {type Operation, type OperationArgs, type OperationImpl, type OperationsAPI} from './types' import {unpublish} from './unpublish' function createOperationGuard(opName: string): Operation { @@ -45,7 +38,6 @@ export const GUARDED: OperationsAPI = { unpublish: createOperationGuard('unpublish'), duplicate: createOperationGuard('duplicate'), restore: createOperationGuard('restore'), - createVersion: createOperationGuard('createVersion'), } const createEmitter = (operationName: keyof OperationsAPI, idPair: IdPair, typeName: string) => @@ -75,10 +67,6 @@ export function createOperationsAPI(args: OperationArgs): OperationsAPI { unpublish: wrap('unpublish', unpublish, args), duplicate: wrap('duplicate', duplicate, args), restore: wrap('restore', restore, args), - createVersion: wrap('createVersion', createVersion, args) as Operation< - [documentId: string, origin?: VersionOriginTypes], - 'NO_NEW_VERSION' - >, } //as we add server operations one by one, we can add them here diff --git a/packages/sanity/src/core/store/_legacy/document/document-pair/operations/types.ts b/packages/sanity/src/core/store/_legacy/document/document-pair/operations/types.ts index 06710777740..f230502cf81 100644 --- a/packages/sanity/src/core/store/_legacy/document/document-pair/operations/types.ts +++ b/packages/sanity/src/core/store/_legacy/document/document-pair/operations/types.ts @@ -40,9 +40,6 @@ export interface OperationsAPI { unpublish: Operation<[], 'LIVE_EDIT_ENABLED' | 'NOT_PUBLISHED'> | GuardedOperation duplicate: Operation<[documentId: string], 'NOTHING_TO_DUPLICATE'> | GuardedOperation restore: Operation<[revision: string]> | GuardedOperation - createVersion: - | GuardedOperation - | Operation<[documentId: string, origin: VersionOriginTypes], 'NO_NEW_VERSION'> } /** @internal */ diff --git a/packages/sanity/src/core/store/release/createReleaseOperationStore.ts b/packages/sanity/src/core/store/release/createReleaseOperationStore.ts index b96b8ed77df..eba4899fc89 100644 --- a/packages/sanity/src/core/store/release/createReleaseOperationStore.ts +++ b/packages/sanity/src/core/store/release/createReleaseOperationStore.ts @@ -1,8 +1,13 @@ -import {type Action, type SanityClient} from '@sanity/client' +import { + type Action, + type EditAction, + type IdentifiedSanityDocumentStub, + type SanityClient, +} from '@sanity/client' import {type User} from '@sanity/types' import {getBundleIdFromReleaseDocumentId} from '../../releases' -import {getVersionId} from '../../util' +import {getDraftId, getPublishedId, getVersionId} from '../../util' import {RELEASE_METADATA_TMP_DOC_PATH, RELEASE_METADATA_TMP_DOC_TYPE} from './constants' import {type EditableReleaseDocument} from './types' @@ -16,52 +21,79 @@ export interface ReleaseOperationsStore { updateRelease: (release: EditableReleaseDocument) => Promise createRelease: (release: EditableReleaseDocument) => Promise createVersion: (releaseId: string, documentId: string) => Promise + discardVersion: (releaseId: string, documentId: string) => Promise } +const IS_CREATE_VERSION_ACTION_SUPPORTED = false +const IS_RELEASE_METADATA_PROPERTIES_SUPPORTED = false +const IS_RELEASE_EDIT_SUPPORTED = false + export function createReleaseOperationsStore(options: { client: SanityClient currentUser: User }): ReleaseOperationsStore { const {client, currentUser} = options const handleCreateRelease = async (release: EditableReleaseDocument) => { - const bundleId = getBundleIdFromReleaseDocumentId(release._id) - const metadataDocument = { - ...release, - _id: `${RELEASE_METADATA_TMP_DOC_PATH}.${bundleId}`, - _type: RELEASE_METADATA_TMP_DOC_TYPE, - authorId: currentUser?.id, + if (IS_RELEASE_METADATA_PROPERTIES_SUPPORTED) { + await requestAction(client, { + actionType: 'sanity.action.release.create', + releaseId: getBundleIdFromReleaseDocumentId(release._id), + }) + await requestAction(client, { + actionType: 'sanity.action.release.create', + releaseId: getBundleIdFromReleaseDocumentId(release._id), + // @ts-expect-error - this is TBD + metadata: release, + }) + } else { + // todo: remove once metadata properties are supported + const bundleId = getBundleIdFromReleaseDocumentId(release._id) + const metadataDocument = { + ...release, + _id: `${RELEASE_METADATA_TMP_DOC_PATH}.${bundleId}`, + _type: RELEASE_METADATA_TMP_DOC_TYPE, + } + await requestAction(client, { + actionType: 'sanity.action.release.create', + releaseId: getBundleIdFromReleaseDocumentId(release._id), + }) + await client.createIfNotExists(metadataDocument) } - await requestAction(client, { - actionType: 'sanity.action.release.create', - releaseId: getBundleIdFromReleaseDocumentId(release._id), - }) - await client.createIfNotExists(metadataDocument) } const handleUpdateRelease = async (release: EditableReleaseDocument) => { - if (!release._id) { - return - } - const bundleId = getBundleIdFromReleaseDocumentId(release._id) - // todo: update system document when `sanity.action.release.edit` action is supported - const metadataDocument = { - ...release, - _id: `${RELEASE_METADATA_TMP_DOC_PATH}.${bundleId}`, - _type: RELEASE_METADATA_TMP_DOC_TYPE, - authorId: currentUser?.id, - } const unsetKeys = Object.entries(release) .filter(([_, value]) => value === undefined) - .map(([key]) => key) + .map(([key]) => `metadata.${key}`) - let clientOperation = client.patch(metadataDocument._id).set(metadataDocument) - if (unsetKeys.length) { - clientOperation = clientOperation.unset(unsetKeys) - } + if (IS_RELEASE_EDIT_SUPPORTED) { + await requestAction(client, { + actionType: 'sanity.action.release.edit', + releaseId: bundleId, + patch: { + // todo: consider more granular updates here + set: {metadata: release.metadata}, + unset: unsetKeys, + }, + }) + } else { + // todo: delete when `sanity.action.release.edit` action is supported for custom metadata/attributes + const metadataDocument = { + ...release, + _id: `${RELEASE_METADATA_TMP_DOC_PATH}.${bundleId}`, + _type: RELEASE_METADATA_TMP_DOC_TYPE, + authorId: currentUser?.id, + } - await clientOperation.commit() + let clientOperation = client.patch(metadataDocument._id).set(metadataDocument) + if (unsetKeys.length) { + clientOperation = clientOperation.unset(unsetKeys) + } + + await clientOperation.commit() + } } const handlePublishRelease = async (releaseId: string) => @@ -108,11 +140,42 @@ export function createReleaseOperationsStore(options: { ]) } - const handleCreateVersion = async (documentId: string, releaseId: string) => { + const handleCreateVersion = async (releaseId: string, documentId: string) => { + const [draftId, publishedId] = [getDraftId(documentId), getPublishedId(documentId)] // fetch original document - const doc = await client.fetch(`*[_id == $documentId][0]`, {documentId}) + const [draft, published] = await client.getDocuments([publishedId, draftId]) + + if (!draft && !published) { + throw new Error(`Document with id ${documentId} not found`) + } + + const versionDocument = { + ...(draft || published), + _id: getVersionId(documentId, releaseId), + } as IdentifiedSanityDocumentStub - return client.create({...doc, _id: getVersionId(documentId, releaseId)}).then(() => {}) + await (IS_CREATE_VERSION_ACTION_SUPPORTED + ? requestAction(client, [ + { + actionType: 'sanity.action.document.createVersion', + releaseId: getBundleIdFromReleaseDocumentId(releaseId), + attributes: versionDocument, + }, + ]) + : client.create(versionDocument)) + } + + const handleDiscardVersion = async (releaseId: string, documentId: string) => { + if (!document) { + throw new Error(`Document with id ${documentId} not found`) + } + + await requestAction(client, [ + { + actionType: 'sanity.action.document.discard', + draftId: getVersionId(documentId, releaseId), + }, + ]) } return { @@ -124,6 +187,7 @@ export function createReleaseOperationsStore(options: { updateRelease: handleUpdateRelease, publishRelease: handlePublishRelease, createVersion: handleCreateVersion, + discardVersion: handleDiscardVersion, } } @@ -158,10 +222,17 @@ interface CreateReleaseApiAction { releaseId: string } -// Todo: implement - not supported by backend yet +interface CreateVersionReleaseApiAction { + actionType: 'sanity.action.document.createVersion' + releaseId: string + attributes: IdentifiedSanityDocumentStub +} + +// Todo: not supported by backend yet – this is me guessing what it will look like interface EditReleaseApiAction { actionType: 'sanity.action.release.edit' releaseId: string + patch: EditAction['patch'] } type ReleaseAction = @@ -169,9 +240,11 @@ type ReleaseAction = | ScheduleApiAction | PublishApiAction | CreateReleaseApiAction + | EditReleaseApiAction | UnscheduleApiAction | ArchiveApiAction | UnarchiveApiAction + | CreateVersionReleaseApiAction function requestAction(client: SanityClient, actions: ReleaseAction | ReleaseAction[]) { const {dataset} = client.config() diff --git a/packages/sanity/src/structure/panes/document/documentPanel/DocumentPanel.tsx b/packages/sanity/src/structure/panes/document/documentPanel/DocumentPanel.tsx index dcdbdf86bd7..baeee5c2d7a 100644 --- a/packages/sanity/src/structure/panes/document/documentPanel/DocumentPanel.tsx +++ b/packages/sanity/src/structure/panes/document/documentPanel/DocumentPanel.tsx @@ -145,13 +145,7 @@ export const DocumentPanel = function DocumentPanel(props: DocumentPanelProps) { const banners = useMemo(() => { if (!existsInBundle && currentPerspectiveIsRelease) { - return ( - - ) + return } if (activeView.type === 'form' && isLiveEdit && ready) { @@ -183,7 +177,6 @@ export const DocumentPanel = function DocumentPanel(props: DocumentPanelProps) { currentPerspectiveIsRelease, displayed, documentId, - documentType, existsInBundle, isLiveEdit, isPermissionsLoading, @@ -191,6 +184,7 @@ export const DocumentPanel = function DocumentPanel(props: DocumentPanelProps) { ready, requiredPermission, schemaType, + value._id, ]) return ( diff --git a/packages/sanity/src/structure/panes/document/documentPanel/banners/AddToReleaseBanner.tsx b/packages/sanity/src/structure/panes/document/documentPanel/banners/AddToReleaseBanner.tsx index cfa25f52689..753385fe586 100644 --- a/packages/sanity/src/structure/panes/document/documentPanel/banners/AddToReleaseBanner.tsx +++ b/packages/sanity/src/structure/panes/document/documentPanel/banners/AddToReleaseBanner.tsx @@ -1,6 +1,7 @@ import {Flex, Text} from '@sanity/ui' import {type CSSProperties, useCallback} from 'react' import { + getBundleIdFromReleaseDocumentId, getReleaseTone, LATEST, type ReleaseDocument, @@ -15,24 +16,22 @@ import {Banner} from './Banner' export function AddToReleaseBanner({ documentId, - documentType, currentRelease, }: { documentId: string - documentType: string currentRelease: ReleaseDocument }): JSX.Element { const tone = getReleaseTone(currentRelease ?? LATEST) const {t} = useTranslation(structureLocaleNamespace) const {t: tCore} = useTranslation() - const {createVersion} = useVersionOperations(documentId, documentType) + const {createVersion} = useVersionOperations() - const handleAddToRelease = useCallback(() => { + const handleAddToRelease = useCallback(async () => { if (currentRelease._id) { - createVersion(currentRelease._id) + await createVersion(getBundleIdFromReleaseDocumentId(currentRelease._id), documentId) } - }, [createVersion, currentRelease._id]) + }, [createVersion, currentRelease._id, documentId]) return ( setContextMenuPoint(undefined), []) @@ -131,10 +131,10 @@ export const VersionChip = memo(function VersionChip(props: { const handleAddVersion = useCallback( async (targetRelease: string) => { - createVersion(targetRelease) + await createVersion(getBundleIdFromReleaseDocumentId(targetRelease), docId) close() }, - [createVersion, close], + [createVersion, docId, close], ) const referenceElement = useMemo(() => { diff --git a/packages/sanity/src/structure/panes/document/documentPanel/header/perspective/dialog/CreateReleaseDialog.tsx b/packages/sanity/src/structure/panes/document/documentPanel/header/perspective/dialog/CreateReleaseDialog.tsx index 00aa4425b7f..35477a76232 100644 --- a/packages/sanity/src/structure/panes/document/documentPanel/header/perspective/dialog/CreateReleaseDialog.tsx +++ b/packages/sanity/src/structure/panes/document/documentPanel/header/perspective/dialog/CreateReleaseDialog.tsx @@ -65,7 +65,7 @@ export function CreateReleaseDialog(props: { await createRelease(value) - handleAddVersion() + await handleAddVersion() telemetry.log(CreatedRelease, {origin: 'document-panel'}) } catch (err) { console.error(err) @@ -73,6 +73,7 @@ export function CreateReleaseDialog(props: { closable: true, status: 'error', title: `Failed to create release`, + description: err.message, }) } finally { setIsSubmitting(false)