diff --git a/packages/sanity/src/core/bundles/components/BundlesMenu.tsx b/packages/sanity/src/core/bundles/components/BundlesMenu.tsx index a9e6bd657728..402c22e1b9c9 100644 --- a/packages/sanity/src/core/bundles/components/BundlesMenu.tsx +++ b/packages/sanity/src/core/bundles/components/BundlesMenu.tsx @@ -43,25 +43,20 @@ export const BundlesMenu = memo(function BundlesMenu(props: BundleListProps): Re if (!bundles) return [] return bundles - .filter(({slug, archivedAt}) => !isDraftOrPublished(slug) && !archivedAt) - .sort( - ({slug: aSlug}, {slug: bSlug}) => - Number(deletedBundles[aSlug]) - Number(deletedBundles[bSlug]), - ) + .filter(({_id, archivedAt}) => !isDraftOrPublished(_id) && !archivedAt) + .sort(({_id: aId}, {_id: bId}) => Number(deletedBundles[aId]) - Number(deletedBundles[bId])) }, [bundles, deletedBundles]) const hasBundles = sortedBundlesToDisplay.length > 0 const handleBundleChange = useCallback( - (bundle: Partial) => () => { - if (bundle.slug) { - setPerspective(bundle.slug) - } + (bundleId: string) => () => { + setPerspective(bundleId) }, [setPerspective], ) const isBundleDeleted = useCallback( - (slug: string) => Boolean(deletedBundles[slug]), + (bundleId: string) => Boolean(deletedBundles[bundleId]), [deletedBundles], ) @@ -80,11 +75,11 @@ export const BundlesMenu = memo(function BundlesMenu(props: BundleListProps): Re <> ) : undefined } - onClick={handleBundleChange(LATEST)} + onClick={handleBundleChange('drafts')} pressed={false} text={LATEST.title} data-testid="latest-menu-item" @@ -95,15 +90,15 @@ export const BundlesMenu = memo(function BundlesMenu(props: BundleListProps): Re {sortedBundlesToDisplay.map((bundle) => ( @@ -112,7 +107,7 @@ export const BundlesMenu = memo(function BundlesMenu(props: BundleListProps): Re hue={bundle.hue} icon={bundle.icon} padding={2} - isDisabled={isBundleDeleted(bundle.slug)} + isDisabled={isBundleDeleted(bundle._id)} /> @@ -135,9 +130,9 @@ export const BundlesMenu = memo(function BundlesMenu(props: BundleListProps): Re diff --git a/packages/sanity/src/core/bundles/components/__tests__/BundlesMenu.test.tsx b/packages/sanity/src/core/bundles/components/__tests__/BundlesMenu.test.tsx index fa853d565ea8..87343ccce829 100644 --- a/packages/sanity/src/core/bundles/components/__tests__/BundlesMenu.test.tsx +++ b/packages/sanity/src/core/bundles/components/__tests__/BundlesMenu.test.tsx @@ -33,9 +33,8 @@ describe('BundlesMenu', () => { const mockBundles: BundleDocument[] = [ { hue: 'magenta', - _id: 'db76c50e-358b-445c-a57c-8344c588a5d5', - _type: 'bundle', - slug: 'spring-drop', + _id: 'spring-drop', + _type: 'release', _rev: '6z08CvvPnPe5pWSKJ5zPRR', icon: 'heart-filled', description: 'What a spring drop, allergies galore 🌸', @@ -47,13 +46,12 @@ describe('BundlesMenu', () => { { icon: 'drop', title: 'Autumn Drop', - _type: 'bundle', + _type: 'release', hue: 'yellow', - _id: '0e87530e-4378-45ff-9d6f-58207e89f3ed', + _id: 'autumn-drop', _createdAt: '2024-07-02T11:37:06Z', _rev: '6z08CvvPnPe5pWSKJ5zJiK', _updatedAt: '2024-07-02T11:37:06Z', - slug: 'autumn-drop', authorId: '', }, { @@ -63,10 +61,10 @@ describe('BundlesMenu', () => { description: 'What a summer drop woo hoo! ☀️', _updatedAt: '2024-07-02T11:36:00Z', title: 'Summer Drop', - _type: 'bundle', + _type: 'release', hue: 'red', _id: 'f6b2c2cc-1732-4465-bfb3-dd205b5d78e9', - slug: 'summer-drop', + _id: 'summer-drop', authorId: '', }, ] @@ -157,7 +155,7 @@ describe('BundlesMenu', () => { act(() => { expect(screen.getByText(mockBundles[0].title)).toBeInTheDocument() - expect(screen.getByTestId(`${mockBundles[0].slug}-checkmark-icon`)).toBeInTheDocument() + expect(screen.getByTestId(`${mockBundles[0]._id}-checkmark-icon`)).toBeInTheDocument() }) }) @@ -222,8 +220,8 @@ describe('BundlesMenu', () => { deletedBundles: { 'mock-deleted-bundle': { _id: 'mock-deleted-bundle', - _type: 'bundle', - slug: 'mock-deleted-bundle', + _type: 'release', + _id: 'mock-deleted-bundle', title: 'Mock Deleted Bundle', } as BundleDocument, }, @@ -248,8 +246,8 @@ describe('BundlesMenu', () => { deletedBundles: { 'mock-deleted-bundle': { _id: 'mock-deleted-bundle', - _type: 'bundle', - slug: 'mock-deleted-bundle', + _type: 'release', + _id: 'mock-deleted-bundle', title: 'Mock Deleted Bundle', } as BundleDocument, }, @@ -262,8 +260,8 @@ describe('BundlesMenu', () => { ...mockBundles, { _id: 'mock-deleted-bundle', - _type: 'bundle', - slug: 'mock-deleted-bundle', + _type: 'release', + _id: 'mock-deleted-bundle', title: 'Mock Deleted Bundle', } as BundleDocument, ]} diff --git a/packages/sanity/src/core/bundles/components/dialog/BundleDetailsDialog.tsx b/packages/sanity/src/core/bundles/components/dialog/BundleDetailsDialog.tsx index 1ed3ce2e5b4c..8a350dca91fc 100644 --- a/packages/sanity/src/core/bundles/components/dialog/BundleDetailsDialog.tsx +++ b/packages/sanity/src/core/bundles/components/dialog/BundleDetailsDialog.tsx @@ -1,13 +1,14 @@ import {ArrowRightIcon} from '@sanity/icons' import {Box, Flex, useToast} from '@sanity/ui' import {type FormEvent, useCallback, useState} from 'react' -import {useTranslation} from 'sanity' +import {type FormBundleDocument, useTranslation} from 'sanity' import {Button, Dialog} from '../../../../ui-components' import {type BundleDocument} from '../../../store/bundles/types' import {useBundleOperations} from '../../../store/bundles/useBundleOperations' import {usePerspective} from '../../hooks/usePerspective' -import {BundleForm, DEFAULT_BUNDLE} from './BundleForm' +import {createReleaseId} from '../../util/createReleaseId' +import {BundleForm} from './BundleForm' interface BundleDetailsDialogProps { onCancel: () => void @@ -22,69 +23,56 @@ export function BundleDetailsDialog(props: BundleDetailsDialogProps): JSX.Elemen const formAction = bundle ? 'edit' : 'create' const {t} = useTranslation() - const [value, setValue] = useState>(() => { - if (bundle) { - return { - slug: bundle.slug, - title: bundle.title, - description: bundle.description, - hue: bundle.hue, - icon: bundle.icon, - publishedAt: bundle.publishedAt, - } - } - - return DEFAULT_BUNDLE + const [value, setValue] = useState((): FormBundleDocument => { + return { + _id: bundle?._id || createReleaseId(), + _type: 'release', + title: bundle?.title, + description: bundle?.description, + hue: bundle?.hue || 'gray', + icon: bundle?.icon || 'cube', + publishedAt: bundle?.publishedAt, + } as const }) const [isSubmitting, setIsSubmitting] = useState(false) // TODO MAKE SURE THIS IS HOW WE WANT TO DO THIS const {setPerspective} = usePerspective() - const bundleOperation = useCallback( - (formValue: Partial) => { - if (formAction === 'edit' && bundle?._id) { - const updatedBundle: Partial = { - ...formValue, - _id: bundle._id, - } - - return updateBundle(updatedBundle) - } - return createBundle(formValue) + const submit = useCallback( + (formValue: FormBundleDocument) => { + return formAction === 'edit' ? updateBundle(formValue) : createBundle(formValue) }, - [bundle?._id, createBundle, formAction, updateBundle], + [createBundle, formAction, updateBundle], ) const handleOnSubmit = useCallback( async (event: FormEvent) => { - if (value.slug) { - try { - event.preventDefault() - setIsSubmitting(true) + try { + event.preventDefault() + setIsSubmitting(true) - const submitValue = {...value, title: value.title?.trim()} - await bundleOperation(submitValue) - if (formAction === 'create') { - setPerspective(value.slug) - } - } catch (err) { - console.error(err) - toast.push({ - closable: true, - status: 'error', - title: `Failed to ${formAction} release`, - }) - } finally { - setIsSubmitting(false) - onSubmit() + const submitValue = {...value, title: value.title?.trim()} + await submit(submitValue) + if (formAction === 'create') { + setPerspective(value._id) } + } catch (err) { + console.error(err) + toast.push({ + closable: true, + status: 'error', + title: `Failed to ${formAction} release`, + }) + } finally { + setIsSubmitting(false) + onSubmit() } }, - [bundleOperation, formAction, onSubmit, setPerspective, value, toast], + [value, submit, formAction, setPerspective, toast, onSubmit], ) - const handleOnChange = useCallback((changedValue: Partial) => { + const handleOnChange = useCallback((changedValue: FormBundleDocument) => { setValue(changedValue) }, []) diff --git a/packages/sanity/src/core/bundles/components/dialog/BundleForm.tsx b/packages/sanity/src/core/bundles/components/dialog/BundleForm.tsx index ad2543b11929..bc39cf95bf78 100644 --- a/packages/sanity/src/core/bundles/components/dialog/BundleForm.tsx +++ b/packages/sanity/src/core/bundles/components/dialog/BundleForm.tsx @@ -1,8 +1,9 @@ import {type ColorHueKey} from '@sanity/color' import {type IconSymbol} from '@sanity/icons' import {Flex, Stack, Text, TextArea, TextInput} from '@sanity/ui' -import {useCallback, useMemo, useRef, useState} from 'react' +import {useCallback, useMemo, useState} from 'react' import { + type FormBundleDocument, FormFieldHeaderText, type FormNodeValidation, useDateTimeFormat, @@ -14,7 +15,6 @@ import {DateTimeInput} from '../../../../ui-components/inputs/DateInputs/DateTim import {getCalendarLabels} from '../../../form/inputs/DateInputs/utils' import {type BundleDocument} from '../../../store/bundles/types' import {BundleIconEditorPicker, type BundleIconEditorPickerValue} from './BundleIconEditorPicker' -import {useGetBundleSlug} from './useGetBundleSlug' interface BaseBundleDocument extends Partial { hue: ColorHueKey @@ -22,7 +22,6 @@ interface BaseBundleDocument extends Partial { } export const DEFAULT_BUNDLE: BaseBundleDocument = { - slug: '', title: '', description: '', hue: 'gray', @@ -30,19 +29,18 @@ export const DEFAULT_BUNDLE: BaseBundleDocument = { } export function BundleForm(props: { - onChange: (params: Partial) => void - value: Partial + onChange: (params: FormBundleDocument) => void + value: FormBundleDocument }): JSX.Element { const {onChange, value} = props const {title, description, icon, hue, publishedAt} = value // derive the action from whether the initial value prop has a slug // only editing existing bundles will provide a value.slug - const {current: action} = useRef(value.slug ? 'edit' : 'create') - const isEditing = action === 'edit' const {t} = useTranslation() const dateFormatter = useDateTimeFormat() + // todo: figure out if these are needed const [titleErrors, setTitleErrors] = useState([]) const [dateErrors, setDateErrors] = useState([]) @@ -60,22 +58,15 @@ export function BundleForm(props: { [icon, hue], ) - const generateSlugFromTitle = useGetBundleSlug() - const handleBundleTitleChange = useCallback( (event: React.ChangeEvent) => { const pickedTitle = event.target.value - const {slug: existingSlug} = value - - const nextSlug = (isEditing && existingSlug) || generateSlugFromTitle(pickedTitle) - onChange({ ...value, title: pickedTitle, - slug: nextSlug, }) }, - [generateSlugFromTitle, isEditing, onChange, value], + [onChange, value], ) const handleBundleDescriptionChange = useCallback( diff --git a/packages/sanity/src/core/bundles/components/dialog/__tests__/BundleDetailsDialog.test.tsx b/packages/sanity/src/core/bundles/components/dialog/__tests__/BundleDetailsDialog.test.tsx index 5cd4bb1f62d3..ba152e28738c 100644 --- a/packages/sanity/src/core/bundles/components/dialog/__tests__/BundleDetailsDialog.test.tsx +++ b/packages/sanity/src/core/bundles/components/dialog/__tests__/BundleDetailsDialog.test.tsx @@ -70,11 +70,10 @@ describe('BundleDetailsDialog', () => { it('should call createBundle, setPerspective, and onCreate when form is submitted with a valid slug', async () => { const value: Partial = { - slug: 'bundle-1', + _type: 'release', title: 'Bundle 1', hue: 'gray', icon: 'cube', - description: '', //publishAt: undefined, } @@ -84,9 +83,14 @@ describe('BundleDetailsDialog', () => { const submitButton = screen.getByTestId('submit-release-button') fireEvent.click(submitButton) - await expect(useBundleOperations().createBundle).toHaveBeenCalledWith(value) + await expect(useBundleOperations().createBundle).toHaveBeenCalledWith( + expect.objectContaining({ + _id: expect.stringMatching(/r\w{8}/), + ...value, + }), + ) - expect(usePerspective().setPerspective).toHaveBeenCalledWith(value.slug) + expect(usePerspective().setPerspective).toHaveBeenCalledWith(expect.stringMatching(/r\w{8}/)) expect(onSubmitMock).toHaveBeenCalled() }) }) @@ -95,8 +99,8 @@ describe('BundleDetailsDialog', () => { const onCancelMock = jest.fn() const onSubmitMock = jest.fn() const existingBundleValue: BundleDocument = { - _id: '123', - _type: 'bundle', + _id: 'existing-bundle', + _type: 'release', _rev: '123', _createdAt: '2024-07-02T11:37:51Z', _updatedAt: '2024-07-12T10:39:32Z', @@ -104,7 +108,6 @@ describe('BundleDetailsDialog', () => { description: 'Existing bundle description', hue: 'magenta', icon: 'cube', - slug: 'existing-bundle', title: 'Existing bundle', } @@ -157,13 +160,12 @@ describe('BundleDetailsDialog', () => { }) fireEvent.click(screen.getByTestId('submit-release-button')) - const {hue, icon, slug, _id} = existingBundleValue + const {hue, icon, _id} = existingBundleValue expect(useBundleOperations().updateBundle).toHaveBeenCalledWith({ _id, + _type: 'release', hue, icon, - // slug has not been updated - slug, title: 'New title', description: 'New description', }) diff --git a/packages/sanity/src/core/bundles/components/dialog/__tests__/BundleForm.test.tsx b/packages/sanity/src/core/bundles/components/dialog/__tests__/BundleForm.test.tsx index fed92ba131c7..9339b53b7a5c 100644 --- a/packages/sanity/src/core/bundles/components/dialog/__tests__/BundleForm.test.tsx +++ b/packages/sanity/src/core/bundles/components/dialog/__tests__/BundleForm.test.tsx @@ -1,6 +1,6 @@ import {beforeEach, describe, expect, it, jest} from '@jest/globals' import {fireEvent, render, screen} from '@testing-library/react' -import {type BundleDocument, useDateTimeFormat} from 'sanity' +import {type BundleDocument, type FormBundleDocument, useDateTimeFormat} from 'sanity' import {createTestProvider} from '../../../../../../test/testUtils/TestProvider' import {useBundles} from '../../../../store/bundles' @@ -20,7 +20,9 @@ const mockUseDateTimeFormat = useDateTimeFormat as jest.Mock describe('BundleForm', () => { const onChangeMock = jest.fn() const onErrorMock = jest.fn() - const valueMock: Partial = { + const valueMock: FormBundleDocument = { + _id: 'very-random', + _type: 'release', title: '', description: '', icon: 'cube', @@ -43,8 +45,7 @@ describe('BundleForm', () => { title: 'Spring Drop', icon: 'heart-filled', _id: 'db76c50e-358b-445c-a57c-8344c588a5d5', - _type: 'bundle', - slug: 'spring-drop', + _type: 'release', hue: 'magenta', _createdAt: '2024-07-02T11:37:51Z', }, @@ -76,7 +77,7 @@ describe('BundleForm', () => { const titleInput = screen.getByTestId('bundle-form-title') fireEvent.change(titleInput, {target: {value: 'Bundle 1'}}) - expect(onChangeMock).toHaveBeenCalledWith({...valueMock, title: 'Bundle 1', slug: 'bundle-1'}) + expect(onChangeMock).toHaveBeenCalledWith({...valueMock, title: 'Bundle 1'}) }) it('should call onChange when description textarea value changes', () => { @@ -100,25 +101,6 @@ describe('BundleForm', () => { expect(onChangeMock).toHaveBeenCalledWith({...valueMock, publishAt: ''}) })*/ - it('should allow for a "drafts" title bundle to be created', () => { - const titleInput = screen.getByTestId('bundle-form-title') - - fireEvent.change(titleInput, {target: {value: 'drafts'}}) - - expect(onChangeMock).toHaveBeenCalledWith({...valueMock, title: 'drafts', slug: 'drafts-1'}) - }) - - it('should allow for a "published" title bundle to be created', () => { - const titleInput = screen.getByTestId('bundle-form-title') - fireEvent.change(titleInput, {target: {value: 'published'}}) - - expect(onChangeMock).toHaveBeenCalledWith({ - ...valueMock, - title: 'published', - slug: 'published-1', - }) - }) - /*it('should show an error when the publishAt input value is invalid', () => { const publishAtInput = screen.getByTestId('bundle-form-publish-at') fireEvent.change(publishAtInput, {target: {value: 'invalid-date'}}) @@ -133,7 +115,6 @@ describe('BundleForm', () => { description: 'Summer time', icon: 'heart-filled', hue: 'magenta', - slug: 'summer-drop', } as BundleDocument beforeEach(async () => { onChangeMock.mockClear() @@ -148,9 +129,8 @@ describe('BundleForm', () => { authorId: 'pzAhBTkNX', title: 'Spring Drop', icon: 'heart-filled', - _id: 'db76c50e-358b-445c-a57c-8344c588a5d5', - _type: 'bundle', - slug: 'spring-drop', + _id: 'db76c50e', + _type: 'release', hue: 'magenta', _createdAt: '2024-07-02T11:37:51Z', }, @@ -162,7 +142,12 @@ describe('BundleForm', () => { const wrapper = await createTestProvider() render( - , + , { wrapper, }, diff --git a/packages/sanity/src/core/bundles/components/dialog/__tests__/useGetBundleSlug.test.ts b/packages/sanity/src/core/bundles/components/dialog/__tests__/useGetBundleSlug.test.ts deleted file mode 100644 index bb16737e87a7..000000000000 --- a/packages/sanity/src/core/bundles/components/dialog/__tests__/useGetBundleSlug.test.ts +++ /dev/null @@ -1,101 +0,0 @@ -import {describe, expect, it, jest} from '@jest/globals' -import {renderHook} from '@testing-library/react' - -import {type BundleDocument, useBundles} from '../../../../store/bundles' -import {useGetBundleSlug} from '../useGetBundleSlug' - -jest.mock('../../../../store/bundles', () => ({ - useBundles: jest.fn(), -})) - -const mockUseBundles = useBundles as jest.Mock - -const generateMockUseBundles = (bundles: {slug: string}[] | null) => { - mockUseBundles.mockReturnValue({ - data: bundles as BundleDocument[], - loading: false, - error: undefined, - dispatch: jest.fn(), - deletedBundles: {}, - }) -} - -describe('useGetBundleSlug', () => { - it('should generate a new slug when there are no existing bundles', () => { - generateMockUseBundles([]) - - const { - result: {current}, - } = renderHook(useGetBundleSlug) - - expect(current('New Bundle')).toEqual('new-bundle') - }) - - it("should generate a new slug when the slug doesn't already exist", () => { - generateMockUseBundles([{slug: 'test-bundle-1'}]) - - const { - result: {current}, - } = renderHook(useGetBundleSlug) - - expect(current('New Bundle')).toEqual('new-bundle') - }) - - it.each([ - [[{slug: 'test-bundle'}], 'Test Bundle', 'test-bundle-1'], - [[{slug: 'test-bundle'}], 'Test Bundle 3', 'test-bundle-3'], - [ - [{slug: 'test-bundle'}, {slug: 'test-bundle-1'}, {slug: 'test-bundle-2'}], - 'Test Bundle', - 'test-bundle-3', - ], - [ - [{slug: 'test-bundle'}, {slug: 'test-bundle-3'}, {slug: 'test-bundle-2'}], - 'Test Bundle', - 'test-bundle-1', - ], - [[{slug: 'test-bundle-3'}, {slug: 'test-bundle-2'}], 'Test Bundle', 'test-bundle'], - ])( - 'should generate the next lowest suffix when the slug already exists', - (existingBundleSlugs, requestBundleTitle, resultSlug) => { - generateMockUseBundles(existingBundleSlugs) - - const { - result: {current}, - } = renderHook(useGetBundleSlug) - - expect(current(requestBundleTitle)).toEqual(resultSlug) - }, - ) - - it('should generate a new slug when a suffix count is already provided', () => { - generateMockUseBundles([{slug: 'test-bundle-1-2'}]) - - const { - result: {current}, - } = renderHook(useGetBundleSlug) - - expect(current('Test Bundle 1 2')).toEqual('test-bundle-1-2-1') - }) - - it('should handle protected slugs', () => { - generateMockUseBundles([]) - - const { - result: {current}, - } = renderHook(useGetBundleSlug) - - expect(current('Drafts')).toEqual('drafts-1') - expect(current('published')).toEqual('published-1') - }) - - it('should handle no bundles', () => { - generateMockUseBundles(null) - - const { - result: {current}, - } = renderHook(useGetBundleSlug) - - expect(current('New Bundle')).toEqual('new-bundle') - }) -}) diff --git a/packages/sanity/src/core/bundles/components/dialog/useGetBundleSlug.ts b/packages/sanity/src/core/bundles/components/dialog/useGetBundleSlug.ts deleted file mode 100644 index 1f0fbd598b47..000000000000 --- a/packages/sanity/src/core/bundles/components/dialog/useGetBundleSlug.ts +++ /dev/null @@ -1,63 +0,0 @@ -import {useCallback} from 'react' -import speakingurl from 'speakingurl' - -import {useBundles} from '../../../store/bundles' - -const PROTECTED_SLUGS = ['drafts', 'published'] - -const NO_EXISTING_SLUG: number = 0 - -export function useGetBundleSlug() { - const {data: bundles} = useBundles() - - // From existing bundles: - // if slug doesn't exist, return NO_EXISTING_SLUG - // if slug does exist, returns lowest suffix number available - const getMinimumAvailableSuffixForSlug = useCallback( - (baseSlug: string): number => { - if (!bundles) return NO_EXISTING_SLUG - - const suffixRegex = new RegExp(`^${baseSlug}(?:-(\\d+))?$`) - const descExistingSlugSuffixes = [...bundles, ...PROTECTED_SLUGS.map((slug) => ({slug}))] - .reduce((existingSuffixes, {slug: existingBundleSlug}) => { - const isBaseSlugMatch = existingBundleSlug?.match(suffixRegex) - if (!isBaseSlugMatch) return existingSuffixes - - const suffixNumber = parseInt(isBaseSlugMatch[1] ?? String(NO_EXISTING_SLUG), 10) - existingSuffixes.push(suffixNumber) - - return existingSuffixes - }, []) - .sort((aSuffix, bSuffix) => bSuffix - aSuffix) - - if (!descExistingSlugSuffixes.length) return NO_EXISTING_SLUG - const [maxSuffix] = descExistingSlugSuffixes - const maxNextSuffix = - maxSuffix + (descExistingSlugSuffixes.includes(NO_EXISTING_SLUG) ? 1 : 0) - - const lowestAvailableSuffix = - Array.from({length: maxNextSuffix}, (_, index) => index).find( - (index) => !descExistingSlugSuffixes.includes(index), - ) ?? undefined - if (lowestAvailableSuffix === undefined) return maxSuffix + 1 - - return lowestAvailableSuffix - }, - [bundles], - ) - - const generateSlugFromTitle = useCallback( - (pickedTitle: string) => { - const newSlug = speakingurl(pickedTitle) - const nextAvailableSuffixForSlug = getMinimumAvailableSuffixForSlug(newSlug) - - // newSlug doesn't exist yet - if (nextAvailableSuffixForSlug === NO_EXISTING_SLUG) return newSlug - - return `${newSlug}-${nextAvailableSuffixForSlug}` - }, - [getMinimumAvailableSuffixForSlug], - ) - - return generateSlugFromTitle -} diff --git a/packages/sanity/src/core/bundles/components/panes/BundleActions.tsx b/packages/sanity/src/core/bundles/components/panes/BundleActions.tsx index 8cd63dddf960..871eab3056fa 100644 --- a/packages/sanity/src/core/bundles/components/panes/BundleActions.tsx +++ b/packages/sanity/src/core/bundles/components/panes/BundleActions.tsx @@ -22,25 +22,25 @@ interface BundleActionsProps { */ documentId: string documentType: string - bundleSlug?: string + bundleId?: string } /** * @internal */ export function BundleActions(props: BundleActionsProps): ReactNode { - const {currentGlobalBundle, documentType, documentId, bundleSlug} = props + const {currentGlobalBundle, documentType, documentId, bundleId} = props const publishedId = getPublishedId(documentId) - const {slug, title, archivedAt} = currentGlobalBundle + const {_id: globalBundleId, title, archivedAt} = currentGlobalBundle const documentStore = useDocumentStore() const [creatingVersion, setCreatingVersion] = useState(false) const [isInVersion, setIsInVersion] = useState( - () => getVersionFromId(documentId) === slug, + () => getVersionFromId(documentId) === globalBundleId, ) const toast = useToast() - const {newVersion} = useDocumentOperation(publishedId, documentType, bundleSlug) + const {newVersion} = useDocumentOperation(publishedId, documentType, bundleId) const {t} = useTranslation() const handleAddVersion = useCallback(async () => { @@ -52,7 +52,7 @@ export function BundleActions(props: BundleActionsProps): ReactNode { return } // only add to version if there isn't already a version in that bundle of this doc - if (getVersionFromId(documentId) === slug) { + if (getVersionFromId(documentId) === globalBundleId) { toast.push({ status: 'error', title: `There's already a version of this document in the bundle ${title}`, @@ -60,23 +60,23 @@ export function BundleActions(props: BundleActionsProps): ReactNode { return } - const bundleId = getVersionId(documentId, slug) + const versionId = getVersionId(documentId, globalBundleId) setCreatingVersion(true) // set up the listener before executing const createVersionSuccess = firstValueFrom( documentStore.pair - .operationEvents(bundleId, documentType) + .operationEvents(versionId, documentType) .pipe(filter((e) => e.op === 'newVersion' && e.type === 'success')), ) - newVersion.execute(bundleId) + newVersion.execute(versionId) // only change if the version was created successfully await createVersionSuccess setIsInVersion(true) - }, [documentId, slug, documentStore.pair, documentType, newVersion, toast, title]) + }, [documentId, globalBundleId, documentStore.pair, documentType, newVersion, toast, title]) /** TODO what should happen when you add a version if we don't have the ready button */ @@ -84,7 +84,7 @@ export function BundleActions(props: BundleActionsProps): ReactNode { return (