Skip to content

Commit 7c814a8

Browse files
fix(core): hide versions.* documents from search, update getPublishedId to account for versions (#7470)
* fix(core): hide versions.* documents from search and lists, show error in document panel * chore(core): update draftUtils to account for version ids * fix(structure): revert structureTitle and DocumentPane changes for version checks * fix: use path separator in getVersionId split Co-authored-by: Ash <[email protected]> --------- Co-authored-by: Ash <[email protected]>
1 parent 4729e84 commit 7c814a8

File tree

6 files changed

+109
-15
lines changed

6 files changed

+109
-15
lines changed

packages/sanity/src/core/search/text-search/createTextSearch.ts

+1
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,7 @@ export const createTextSearch: SearchStrategyFactory<TextSearchResults> = (
142142
searchOptions.includeDrafts === false && "!(_id in path('drafts.**'))",
143143
factoryOptions.filter ? `(${factoryOptions.filter})` : false,
144144
searchTerms.filter ? `(${searchTerms.filter})` : false,
145+
'!(_id in path("versions.**"))',
145146
].filter((baseFilter): baseFilter is string => Boolean(baseFilter))
146147

147148
const textSearchParams: TextSearchParams = {

packages/sanity/src/core/search/weighted/createSearchQuery.test.ts

+9-9
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ describe('createSearchQuery', () => {
4646

4747
expect(query).toEqual(
4848
`// findability-mvi:${FINDABILITY_MVI}\n` +
49-
'*[_type in $__types && (_id match $t0 || _type match $t0 || title match $t0)]' +
49+
'*[_type in $__types && (_id match $t0 || _type match $t0 || title match $t0) && !(_id in path("versions.**"))]' +
5050
'| order(_id asc)' +
5151
'[0...$__limit]' +
5252
'{_type, _id, ...select(_type == "basic-schema-test" => { "w0": _id,"w1": _type,"w2": title })}',
@@ -106,7 +106,7 @@ describe('createSearchQuery', () => {
106106
})
107107

108108
expect(query).toContain(
109-
'*[_type in $__types && (_id match $t0 || _type match $t0 || title match $t0 || object.field match $t0)]',
109+
'*[_type in $__types && (_id match $t0 || _type match $t0 || title match $t0 || object.field match $t0) && !(_id in path("versions.**"))]',
110110
)
111111
})
112112

@@ -117,7 +117,7 @@ describe('createSearchQuery', () => {
117117
})
118118

119119
expect(query).toContain(
120-
'*[_type in $__types && (_id match $t0 || _type match $t0 || title match $t0) && (_id match $t1 || _type match $t1 || title match $t1)]',
120+
'*[_type in $__types && (_id match $t0 || _type match $t0 || title match $t0) && (_id match $t1 || _type match $t1 || title match $t1) && !(_id in path("versions.**"))]',
121121
)
122122
expect(params.t0).toEqual('term0*')
123123
expect(params.t1).toEqual('term1*')
@@ -147,7 +147,7 @@ describe('createSearchQuery', () => {
147147

148148
const result = [
149149
`// findability-mvi:${FINDABILITY_MVI}\n` +
150-
'*[_type in $__types && (_id match $t0 || _type match $t0 || title match $t0)]{_type, _id, object{field}}',
150+
'*[_type in $__types && (_id match $t0 || _type match $t0 || title match $t0) && !(_id in path("versions.**"))]{_type, _id, object{field}}',
151151
'|order(_id asc)[0...$__limit]',
152152
'{_type, _id, ...select(_type == "basic-schema-test" => { "w0": _id,"w1": _type,"w2": title })}',
153153
].join('')
@@ -193,7 +193,7 @@ describe('createSearchQuery', () => {
193193
)
194194

195195
expect(query).toContain(
196-
'*[_type in $__types && (_id match $t0 || _type match $t0 || title match $t0) && (randomCondition == $customParam)]',
196+
'*[_type in $__types && (_id match $t0 || _type match $t0 || title match $t0) && (randomCondition == $customParam) && !(_id in path("versions.**"))]',
197197
)
198198
expect(params.customParam).toEqual('custom')
199199
})
@@ -241,7 +241,7 @@ describe('createSearchQuery', () => {
241241

242242
expect(query).toEqual(
243243
`// findability-mvi:${FINDABILITY_MVI}\n` +
244-
'*[_type in $__types && (_id match $t0 || _type match $t0 || title match $t0)]' +
244+
'*[_type in $__types && (_id match $t0 || _type match $t0 || title match $t0) && !(_id in path("versions.**"))]' +
245245
'| order(exampleField desc)' +
246246
'[0...$__limit]' +
247247
'{_type, _id, ...select(_type == "basic-schema-test" => { "w0": _id,"w1": _type,"w2": title })}',
@@ -275,7 +275,7 @@ describe('createSearchQuery', () => {
275275

276276
const result = [
277277
`// findability-mvi:${FINDABILITY_MVI}\n`,
278-
'*[_type in $__types && (_id match $t0 || _type match $t0 || title match $t0)]| ',
278+
'*[_type in $__types && (_id match $t0 || _type match $t0 || title match $t0) && !(_id in path("versions.**"))]| ',
279279
'order(exampleField desc,anotherExampleField asc,lower(mapWithField) asc)',
280280
'[0...$__limit]{_type, _id, ...select(_type == "basic-schema-test" => { "w0": _id,"w1": _type,"w2": title })}',
281281
].join('')
@@ -291,7 +291,7 @@ describe('createSearchQuery', () => {
291291

292292
expect(query).toEqual(
293293
`// findability-mvi:${FINDABILITY_MVI}\n` +
294-
'*[_type in $__types && (_id match $t0 || _type match $t0 || title match $t0)]' +
294+
'*[_type in $__types && (_id match $t0 || _type match $t0 || title match $t0) && !(_id in path("versions.**"))]' +
295295
'| order(_id asc)' +
296296
'[0...$__limit]' +
297297
'{_type, _id, ...select(_type == "basic-schema-test" => { "w0": _id,"w1": _type,"w2": title })}',
@@ -403,7 +403,7 @@ describe('createSearchQuery', () => {
403403
* This is an improvement over before, where an illegal term was used (number-as-string, ala ["0"]),
404404
* which lead to no hits at all. */
405405
`// findability-mvi:${FINDABILITY_MVI}\n` +
406-
'*[_type in $__types && (_id match $t0 || _type match $t0 || cover[].cards[].title match $t0) && (_id match $t1 || _type match $t1 || cover[].cards[].title match $t1)]' +
406+
'*[_type in $__types && (_id match $t0 || _type match $t0 || cover[].cards[].title match $t0) && (_id match $t1 || _type match $t1 || cover[].cards[].title match $t1) && !(_id in path("versions.**"))]' +
407407
'| order(_id asc)' +
408408
'[0...$__limit]' +
409409
// at this point we could refilter using cover[0].cards[0].title.

packages/sanity/src/core/search/weighted/createSearchQuery.ts

+1
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,7 @@ export function createSearchQuery(
135135
...createConstraints(terms, specs),
136136
filter ? `(${filter})` : '',
137137
searchTerms.filter ? `(${searchTerms.filter})` : '',
138+
'!(_id in path("versions.**"))',
138139
].filter(Boolean)
139140

140141
const selections = specs.map((spec) => {

packages/sanity/src/core/store/_legacy/document/document-store.ts

+4-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import {type LocaleSource} from '../../../i18n'
88
import {type DocumentPreviewStore} from '../../../preview'
99
import {DEFAULT_STUDIO_CLIENT_OPTIONS} from '../../../studioClient'
1010
import {type Template} from '../../../templates'
11-
import {getDraftId, isDraftId} from '../../../util'
11+
import {getDraftId, isDraftId, isVersionId} from '../../../util'
1212
import {type ValidationStatus} from '../../../validation'
1313
import {type HistoryStore} from '../history'
1414
import {checkoutPair, type DocumentVersionEvent, type Pair} from './document-pair/checkoutPair'
@@ -34,6 +34,9 @@ import {type IdPair} from './types'
3434
export type QueryParams = Record<string, string | number | boolean | string[]>
3535

3636
function getIdPairFromPublished(publishedId: string): IdPair {
37+
if (isVersionId(publishedId)) {
38+
throw new Error('editOpsOf does not expect a version id.')
39+
}
3740
if (isDraftId(publishedId)) {
3841
throw new Error('editOpsOf does not expect a draft id.')
3942
}

packages/sanity/src/core/util/draftUtils.test.ts

+46-2
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,14 @@
1-
import {expect, test} from '@jest/globals'
1+
import {describe, expect, it, test} from '@jest/globals'
22
import {type SanityDocument} from '@sanity/types'
33

4-
import {collate, documentIdEquals, removeDupes} from './draftUtils'
4+
import {
5+
collate,
6+
documentIdEquals,
7+
getPublishedId,
8+
getVersionFromId,
9+
getVersionId,
10+
removeDupes,
11+
} from './draftUtils'
512

613
test('collate()', () => {
714
const foo = {_type: 'foo', _id: 'foo'}
@@ -38,3 +45,40 @@ test.each([
3845
])('documentIdEquals(): %s', (_, documentId, equalsDocumentId, shouldEqual) => {
3946
expect(documentIdEquals(documentId, equalsDocumentId)).toEqual(shouldEqual)
4047
})
48+
49+
test.each([
50+
['From published id', 'agot', 'summer-drop', 'versions.summer-drop.agot'],
51+
['From draft id', 'drafts.agot', 'summer-drop', 'versions.summer-drop.agot'],
52+
['From same version id', 'versions.summer-drop.agot', 'summer-drop', 'versions.summer-drop.agot'],
53+
[
54+
'From other version id',
55+
'versions.winter-drop.agot',
56+
'summer-drop',
57+
'versions.summer-drop.agot',
58+
],
59+
])('getVersionId(): %s', (_, documentId, equalsDocumentId, shouldEqual) => {
60+
expect(getVersionId(documentId, equalsDocumentId)).toEqual(shouldEqual)
61+
})
62+
63+
test.each([
64+
['from published id', 'agot', 'agot'],
65+
['from draft id', 'drafts.agot', 'agot'],
66+
['from version id', 'versions.summer-drop.agot', 'agot'],
67+
['from complex id with version', 'versions.summer-drop.foo.agot', 'foo.agot'],
68+
])('getPublishedId(): %s', (_, documentId, shouldEqual) => {
69+
expect(getPublishedId(documentId)).toEqual(shouldEqual)
70+
})
71+
72+
describe('getVersionFromId', () => {
73+
it('should return the bundle slug', () => {
74+
expect(getVersionFromId('versions.summer.my-document-id')).toBe('summer')
75+
})
76+
77+
it('should return the undefined if no bundle slug is found and document is a draft', () => {
78+
expect(getVersionFromId('drafts.my-document-id')).toBe(undefined)
79+
})
80+
81+
it('should return the undefined if no bundle slug is found and document is published', () => {
82+
expect(getVersionFromId('my-document-id')).toBe(undefined)
83+
})
84+
})

packages/sanity/src/core/util/draftUtils.ts

+48-3
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,11 @@ export type PublishedId = Opaque<string, 'publishedId'>
1414

1515
/** @internal */
1616
export const DRAFTS_FOLDER = 'drafts'
17-
const DRAFTS_PREFIX = `${DRAFTS_FOLDER}.`
17+
/** @internal */
18+
export const VERSION_FOLDER = 'versions'
19+
const PATH_SEPARATOR = '.'
20+
const DRAFTS_PREFIX = `${DRAFTS_FOLDER}${PATH_SEPARATOR}`
21+
const VERSION_PREFIX = `${VERSION_FOLDER}${PATH_SEPARATOR}`
1822

1923
/**
2024
*
@@ -55,6 +59,11 @@ export function isDraftId(id: string): id is DraftId {
5559
return id.startsWith(DRAFTS_PREFIX)
5660
}
5761

62+
/** @internal */
63+
export function isVersionId(id: string): boolean {
64+
return id.startsWith(VERSION_PREFIX)
65+
}
66+
5867
/** @internal */
5968
export function getIdPair(id: string): {draftId: DraftId; publishedId: PublishedId} {
6069
return {
@@ -65,17 +74,53 @@ export function getIdPair(id: string): {draftId: DraftId; publishedId: Published
6574

6675
/** @internal */
6776
export function isPublishedId(id: string): id is PublishedId {
68-
return !isDraftId(id)
77+
return !isDraftId(id) && !isVersionId(id)
6978
}
7079

7180
/** @internal */
7281
export function getDraftId(id: string): DraftId {
7382
return isDraftId(id) ? id : ((DRAFTS_PREFIX + id) as DraftId)
7483
}
7584

85+
/** @internal */
86+
export function getVersionId(id: string, bundle: string): string {
87+
if (isVersionId(id)) {
88+
const [_versionPrefix, versionId, ...publishedId] = id.split(PATH_SEPARATOR)
89+
if (versionId === bundle) return id
90+
return `${VERSION_PREFIX}${bundle}${PATH_SEPARATOR}${publishedId}`
91+
}
92+
93+
const publishedId = getPublishedId(id)
94+
95+
return `${VERSION_PREFIX}${bundle}${PATH_SEPARATOR}${publishedId}`
96+
}
97+
98+
/**
99+
* @internal
100+
* Given an id, returns the versionId if it exists.
101+
* e.g. `versions.summer-drop.foo` = `summer-drop`
102+
* e.g. `drafts.foo` = `undefined`
103+
* e.g. `foo` = `undefined`
104+
*/
105+
export function getVersionFromId(id: string): string | undefined {
106+
if (!isVersionId(id)) return undefined
107+
const [_versionPrefix, versionId, ..._publishedId] = id.split(PATH_SEPARATOR)
108+
109+
return versionId
110+
}
111+
76112
/** @internal */
77113
export function getPublishedId(id: string): PublishedId {
78-
return (isDraftId(id) ? id.slice(DRAFTS_PREFIX.length) : id) as PublishedId
114+
if (isVersionId(id)) {
115+
// make sure to only remove the versions prefix and the bundle name
116+
return id.split(PATH_SEPARATOR).slice(2).join(PATH_SEPARATOR) as PublishedId as PublishedId
117+
}
118+
119+
if (isDraftId(id)) {
120+
return id.slice(DRAFTS_PREFIX.length) as PublishedId
121+
}
122+
123+
return id as PublishedId
79124
}
80125

81126
/** @internal */

0 commit comments

Comments
 (0)