fix(ui): query presets are available for unrelated collections (#11872)
When selecting query presets from the list drawer, all query presets are available for selection, even if unrelated to the underlying collection. When selecting one of these presets, the list view will crash with client-side exceptions because the columns and filters that are applied are incompatible. The fix is to the thread `filterOptions` through the query presets drawer. This will ensure that only related collections are shown.
This commit is contained in:
@@ -65,9 +65,22 @@ export const useQueryPresets = ({
|
||||
collectionSlug: queryPresetsSlug,
|
||||
})
|
||||
|
||||
const filterOptions = useMemo(
|
||||
() => ({
|
||||
'payload-query-presets': {
|
||||
relatedCollection: {
|
||||
equals: collectionSlug,
|
||||
},
|
||||
},
|
||||
}),
|
||||
[collectionSlug],
|
||||
)
|
||||
|
||||
const [ListDrawer, , { closeDrawer: closeListDrawer, openDrawer: openListDrawer }] =
|
||||
useListDrawer({
|
||||
collectionSlugs: [queryPresetsSlug],
|
||||
filterOptions,
|
||||
selectedCollection: queryPresetsSlug,
|
||||
})
|
||||
|
||||
const handlePresetChange = useCallback(
|
||||
|
||||
21
test/query-presets/collections/Posts/index.ts
Normal file
21
test/query-presets/collections/Posts/index.ts
Normal file
@@ -0,0 +1,21 @@
|
||||
import type { CollectionConfig } from 'payload'
|
||||
|
||||
import { postsSlug } from '../../slugs.js'
|
||||
|
||||
export const Posts: CollectionConfig = {
|
||||
slug: postsSlug,
|
||||
admin: {
|
||||
useAsTitle: 'text',
|
||||
},
|
||||
enableQueryPresets: true,
|
||||
lockDocuments: false,
|
||||
fields: [
|
||||
{
|
||||
name: 'text',
|
||||
type: 'text',
|
||||
},
|
||||
],
|
||||
versions: {
|
||||
drafts: true,
|
||||
},
|
||||
}
|
||||
@@ -3,6 +3,7 @@ import path from 'path'
|
||||
|
||||
import { buildConfigWithDefaults } from '../buildConfigWithDefaults.js'
|
||||
import { Pages } from './collections/Pages/index.js'
|
||||
import { Posts } from './collections/Posts/index.js'
|
||||
import { Users } from './collections/Users/index.js'
|
||||
import { roles } from './fields/roles.js'
|
||||
import { seed } from './seed.js'
|
||||
@@ -54,7 +55,7 @@ export default buildConfigWithDefaults({
|
||||
],
|
||||
},
|
||||
},
|
||||
collections: [Pages, Users],
|
||||
collections: [Pages, Users, Posts],
|
||||
onInit: async (payload) => {
|
||||
if (process.env.SEED_IN_CONFIG_ONINIT !== 'false') {
|
||||
await seed(payload)
|
||||
|
||||
@@ -389,4 +389,19 @@ describe('Query Presets', () => {
|
||||
}),
|
||||
).toBeVisible()
|
||||
})
|
||||
|
||||
test('only shows query presets related to the underlying collection', async () => {
|
||||
// no results on `users` collection
|
||||
const postsUrl = new AdminUrlUtil(serverURL, 'posts')
|
||||
await page.goto(postsUrl.list)
|
||||
const drawer = await openQueryPresetDrawer({ page })
|
||||
await expect(drawer.locator('.table table > tbody > tr')).toHaveCount(0)
|
||||
await expect(drawer.locator('.collection-list__no-results')).toBeVisible()
|
||||
|
||||
// results on `pages` collection
|
||||
await page.goto(pagesUrl.list)
|
||||
await openQueryPresetDrawer({ page })
|
||||
await expect(drawer.locator('.table table > tbody > tr')).toHaveCount(3)
|
||||
await drawer.locator('.collection-list__no-results').isHidden()
|
||||
})
|
||||
})
|
||||
|
||||
@@ -1,5 +1,11 @@
|
||||
import type { Page } from '@playwright/test'
|
||||
import type { Locator, Page } from '@playwright/test'
|
||||
|
||||
export async function openQueryPresetDrawer({ page }: { page: Page }) {
|
||||
import { expect } from '@playwright/test'
|
||||
|
||||
export async function openQueryPresetDrawer({ page }: { page: Page }): Promise<Locator> {
|
||||
await page.click('button#select-preset')
|
||||
const drawer = page.locator('dialog[id^="list-drawer_0_"]')
|
||||
await expect(drawer).toBeVisible()
|
||||
await expect(drawer.locator('.collection-list--payload-query-presets')).toBeVisible()
|
||||
return drawer
|
||||
}
|
||||
|
||||
@@ -69,6 +69,7 @@ export interface Config {
|
||||
collections: {
|
||||
pages: Page;
|
||||
users: User;
|
||||
posts: Post;
|
||||
'payload-locked-documents': PayloadLockedDocument;
|
||||
'payload-preferences': PayloadPreference;
|
||||
'payload-migrations': PayloadMigration;
|
||||
@@ -78,13 +79,14 @@ export interface Config {
|
||||
collectionsSelect: {
|
||||
pages: PagesSelect<false> | PagesSelect<true>;
|
||||
users: UsersSelect<false> | UsersSelect<true>;
|
||||
posts: PostsSelect<false> | PostsSelect<true>;
|
||||
'payload-locked-documents': PayloadLockedDocumentsSelect<false> | PayloadLockedDocumentsSelect<true>;
|
||||
'payload-preferences': PayloadPreferencesSelect<false> | PayloadPreferencesSelect<true>;
|
||||
'payload-migrations': PayloadMigrationsSelect<false> | PayloadMigrationsSelect<true>;
|
||||
'payload-query-presets': PayloadQueryPresetsSelect<false> | PayloadQueryPresetsSelect<true>;
|
||||
};
|
||||
db: {
|
||||
defaultIDType: number;
|
||||
defaultIDType: string;
|
||||
};
|
||||
globals: {};
|
||||
globalsSelect: {};
|
||||
@@ -120,7 +122,7 @@ export interface UserAuthOperations {
|
||||
* via the `definition` "pages".
|
||||
*/
|
||||
export interface Page {
|
||||
id: number;
|
||||
id: string;
|
||||
text?: string | null;
|
||||
updatedAt: string;
|
||||
createdAt: string;
|
||||
@@ -131,7 +133,7 @@ export interface Page {
|
||||
* via the `definition` "users".
|
||||
*/
|
||||
export interface User {
|
||||
id: number;
|
||||
id: string;
|
||||
name?: string | null;
|
||||
roles?: ('admin' | 'user' | 'anonymous')[] | null;
|
||||
updatedAt: string;
|
||||
@@ -145,25 +147,40 @@ export interface User {
|
||||
lockUntil?: string | null;
|
||||
password?: string | null;
|
||||
}
|
||||
/**
|
||||
* This interface was referenced by `Config`'s JSON-Schema
|
||||
* via the `definition` "posts".
|
||||
*/
|
||||
export interface Post {
|
||||
id: string;
|
||||
text?: string | null;
|
||||
updatedAt: string;
|
||||
createdAt: string;
|
||||
_status?: ('draft' | 'published') | null;
|
||||
}
|
||||
/**
|
||||
* This interface was referenced by `Config`'s JSON-Schema
|
||||
* via the `definition` "payload-locked-documents".
|
||||
*/
|
||||
export interface PayloadLockedDocument {
|
||||
id: number;
|
||||
id: string;
|
||||
document?:
|
||||
| ({
|
||||
relationTo: 'pages';
|
||||
value: number | Page;
|
||||
value: string | Page;
|
||||
} | null)
|
||||
| ({
|
||||
relationTo: 'users';
|
||||
value: number | User;
|
||||
value: string | User;
|
||||
} | null)
|
||||
| ({
|
||||
relationTo: 'posts';
|
||||
value: string | Post;
|
||||
} | null);
|
||||
globalSlug?: string | null;
|
||||
user: {
|
||||
relationTo: 'users';
|
||||
value: number | User;
|
||||
value: string | User;
|
||||
};
|
||||
updatedAt: string;
|
||||
createdAt: string;
|
||||
@@ -173,10 +190,10 @@ export interface PayloadLockedDocument {
|
||||
* via the `definition` "payload-preferences".
|
||||
*/
|
||||
export interface PayloadPreference {
|
||||
id: number;
|
||||
id: string;
|
||||
user: {
|
||||
relationTo: 'users';
|
||||
value: number | User;
|
||||
value: string | User;
|
||||
};
|
||||
key?: string | null;
|
||||
value?:
|
||||
@@ -196,7 +213,7 @@ export interface PayloadPreference {
|
||||
* via the `definition` "payload-migrations".
|
||||
*/
|
||||
export interface PayloadMigration {
|
||||
id: number;
|
||||
id: string;
|
||||
name?: string | null;
|
||||
batch?: number | null;
|
||||
updatedAt: string;
|
||||
@@ -207,23 +224,23 @@ export interface PayloadMigration {
|
||||
* via the `definition` "payload-query-presets".
|
||||
*/
|
||||
export interface PayloadQueryPreset {
|
||||
id: number;
|
||||
id: string;
|
||||
title: string;
|
||||
isShared?: boolean | null;
|
||||
access?: {
|
||||
read?: {
|
||||
constraint?: ('everyone' | 'onlyMe' | 'specificUsers' | 'specificRoles') | null;
|
||||
users?: (number | User)[] | null;
|
||||
users?: (string | User)[] | null;
|
||||
roles?: ('admin' | 'user' | 'anonymous')[] | null;
|
||||
};
|
||||
update?: {
|
||||
constraint?: ('everyone' | 'onlyMe' | 'specificUsers' | 'specificRoles') | null;
|
||||
users?: (number | User)[] | null;
|
||||
users?: (string | User)[] | null;
|
||||
roles?: ('admin' | 'user' | 'anonymous')[] | null;
|
||||
};
|
||||
delete?: {
|
||||
constraint?: ('everyone' | 'onlyMe' | 'specificUsers') | null;
|
||||
users?: (number | User)[] | null;
|
||||
users?: (string | User)[] | null;
|
||||
};
|
||||
};
|
||||
where?:
|
||||
@@ -244,7 +261,7 @@ export interface PayloadQueryPreset {
|
||||
| number
|
||||
| boolean
|
||||
| null;
|
||||
relatedCollection: 'pages';
|
||||
relatedCollection: 'pages' | 'posts';
|
||||
updatedAt: string;
|
||||
createdAt: string;
|
||||
}
|
||||
@@ -275,6 +292,16 @@ export interface UsersSelect<T extends boolean = true> {
|
||||
loginAttempts?: T;
|
||||
lockUntil?: T;
|
||||
}
|
||||
/**
|
||||
* This interface was referenced by `Config`'s JSON-Schema
|
||||
* via the `definition` "posts_select".
|
||||
*/
|
||||
export interface PostsSelect<T extends boolean = true> {
|
||||
text?: T;
|
||||
updatedAt?: T;
|
||||
createdAt?: T;
|
||||
_status?: T;
|
||||
}
|
||||
/**
|
||||
* This interface was referenced by `Config`'s JSON-Schema
|
||||
* via the `definition` "payload-locked-documents_select".
|
||||
|
||||
@@ -2,4 +2,6 @@ export const usersSlug = 'users'
|
||||
|
||||
export const pagesSlug = 'pages'
|
||||
|
||||
export const collectionSlugs = [usersSlug, pagesSlug]
|
||||
export const postsSlug = 'posts'
|
||||
|
||||
export const collectionSlugs = [usersSlug, pagesSlug, postsSlug]
|
||||
|
||||
@@ -31,7 +31,7 @@
|
||||
}
|
||||
],
|
||||
"paths": {
|
||||
"@payload-config": ["./test/_community/config.ts"],
|
||||
"@payload-config": ["./test/query-presets/config.ts"],
|
||||
"@payloadcms/admin-bar": ["./packages/admin-bar/src"],
|
||||
"@payloadcms/live-preview": ["./packages/live-preview/src"],
|
||||
"@payloadcms/live-preview-react": ["./packages/live-preview-react/src/index.ts"],
|
||||
|
||||
Reference in New Issue
Block a user