Skip to content

Commit b4d43c0

Browse files
authored
fix: prevent reordering from unpublishing documents that have a newer draft (#16969)
## Summary Backport of #16968 to `3.x`. Reordering a document via the `orderable` drag-and-drop list view could unpublish it when the document had both a published version and a newer draft. The reorder endpoint updated each moved document with `payload.update` without a `draft` flag. With `draft` defaulting to `false`, the update loaded the document's latest version (the draft) as its base and wrote that draft's `_status: 'draft'` into the published main row, effectively unpublishing the document. A subsequent `status: published` query then returned 404 and no "currently published" version remained. This fix detects, for drafts-enabled collections, whether the document's latest version is a draft and, if so, performs the order update with `draft: true`. This preserves the published main document (no unpublish) while still updating the order on the version the list view reads (the list queries with `draft: true`). Published-only documents keep the existing behavior. Reported via support ticket; reproduced on `3.84.1`. ## Changes - `packages/payload/src/config/orderable/index.ts`: in the reorder endpoint, look up the latest version for drafts-enabled collections and pass `draft: true` when the latest version is a draft. - `test/sort/int.spec.ts`: add an integration test covering reordering a published document that has a newer draft, asserting it stays published. ## Test plan - [x] On `main` (#16968): new test fails before the fix (`expected 'draft' to be 'published'`) and passes after; existing reorder tests pass. - [ ] CI on `3.x` validates the suite (local run skipped: installed deps are for the `main`/4.0 toolchain). - [ ] Manual check: collection with `orderable: true` and `versions: { drafts: true }`; publish a doc, edit it into a newer draft, drag-reorder it in the list view, and confirm it stays published. Co-authored-by: German Jablonski <GermanJablo@users.noreply.github.com>
1 parent 29afa77 commit b4d43c0

2 files changed

Lines changed: 92 additions & 0 deletions

File tree

packages/payload/src/config/orderable/index.ts

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,10 @@ import { APIError } from '../../errors/index.js'
1010
import { sanitizeField } from '../../fields/config/sanitize.js'
1111
import { combineWhereConstraints } from '../../utilities/combineWhereConstraints.js'
1212
import { commitTransaction } from '../../utilities/commitTransaction.js'
13+
import { hasDraftsEnabled } from '../../utilities/getVersionsConfig.js'
1314
import { initTransaction } from '../../utilities/initTransaction.js'
1415
import { killTransaction } from '../../utilities/killTransaction.js'
16+
import { getLatestCollectionVersion } from '../../versions/getLatestCollectionVersion.js'
1517
import { generateKeyBetween, generateNKeysBetween } from './fractional-indexing.js'
1618
import { getJoinScopeContext } from './utils/getJoinScopeContext.js'
1719
import { getJoinScopeWhereFromDocData } from './utils/getJoinScopeWhereFromDocData.js'
@@ -289,15 +291,36 @@ export const addOrderableEndpoint = (
289291
? generateNKeysBetween(targetKey, adjacentDocKey, docsToMove.length)
290292
: generateNKeysBetween(adjacentDocKey, targetKey, docsToMove.length)
291293

294+
const draftsEnabled = hasDraftsEnabled(collection)
295+
292296
// Update each document with its new order value
293297
for (const [index, id] of docsToMove.entries()) {
298+
let draft: boolean | undefined
299+
300+
if (draftsEnabled) {
301+
const latestVersion = await getLatestCollectionVersion({
302+
id,
303+
config: collection,
304+
payload: req.payload,
305+
query: {
306+
collection: collection.slug,
307+
req,
308+
where: { id: { equals: id } },
309+
},
310+
req,
311+
})
312+
313+
draft = latestVersion?._status === 'draft'
314+
}
315+
294316
await req.payload.update({
295317
id,
296318
collection: collection.slug,
297319
data: {
298320
[orderableFieldName]: orderValues[index],
299321
},
300322
depth: 0,
323+
draft,
301324
req,
302325
})
303326
}

test/sort/int.spec.ts

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -594,6 +594,75 @@ describe('Sort', () => {
594594
)
595595
})
596596

597+
it('should not unpublish a published document with a newer draft when reordering', async () => {
598+
const publishedDoc = await payload.create({
599+
collection: draftsSlug,
600+
data: {
601+
text: 'Published with newer draft',
602+
_status: 'published',
603+
},
604+
})
605+
606+
const target = await payload.create({
607+
collection: draftsSlug,
608+
data: {
609+
text: 'Reorder target',
610+
_status: 'published',
611+
},
612+
})
613+
614+
// Create a newer draft on top of the published version
615+
await payload.update({
616+
id: publishedDoc.id,
617+
collection: draftsSlug,
618+
data: {
619+
text: 'Published with newer draft - edited',
620+
},
621+
draft: true,
622+
})
623+
624+
const beforeReorder = await payload.findByID({
625+
id: publishedDoc.id,
626+
collection: draftsSlug,
627+
})
628+
629+
expect(beforeReorder._status).toBe('published')
630+
631+
const res = await restClient.POST('/reorder', {
632+
body: JSON.stringify({
633+
collectionSlug: draftsSlug,
634+
docsToMove: [publishedDoc.id],
635+
newKeyWillBe: 'greater',
636+
orderableFieldName: '_order',
637+
target: {
638+
id: target.id,
639+
key: target._order,
640+
},
641+
}),
642+
})
643+
644+
expect(res.status).toStrictEqual(200)
645+
646+
const afterReorder = await payload.findByID({
647+
id: publishedDoc.id,
648+
collection: draftsSlug,
649+
})
650+
651+
// Reordering must not unpublish the document
652+
expect(afterReorder._status).toBe('published')
653+
654+
const published = await payload.find({
655+
collection: draftsSlug,
656+
where: {
657+
id: {
658+
equals: publishedDoc.id,
659+
},
660+
},
661+
})
662+
663+
expect(published.docs).toHaveLength(1)
664+
})
665+
597666
it('should allow to duplicate with reordable', async () => {
598667
const doc = await payload.create({
599668
collection: 'orderable',

0 commit comments

Comments
 (0)