fix: overrides entity visibility within drawers (#9546)

When using the `admin.hidden: true` property on a collection, it
rightfully removes all navigation and routing for that particular
collection. However, this also affects the expected behavior of hidden
entities when they are rendered within a drawer, such as the document
drawer or list drawer. For example, when creating a new _admin.hidden_
document through the relationship or join field, the drawer should still
render the view, despite the underlying route for that view being
disabled. This change was a result of the introduction of on-demand
server components in #8364, where we now make a server roundtrip to
render the view in its entirety, which include the logic that redirects
these hidden entities.

Now, we pass a new `overrideEntityVisibility` argument through the
server function that, when true, skips this step. This way documents can
continue to respect `admin.hidden` while also having the ability to
override on a case-by-case basis throughout the UI.
This commit is contained in:
Jacob Fletcher
2024-11-26 18:22:04 -05:00
committed by GitHub
parent defa13e4fe
commit 5d18a5288e
21 changed files with 176 additions and 24 deletions

View File

@@ -1,6 +1,6 @@
import type { CollectionConfig } from 'payload'
import { categoriesSlug, postsSlug } from '../shared.js'
import { categoriesSlug, hiddenPostsSlug, postsSlug } from '../shared.js'
import { singularSlug } from './Singular.js'
export const Categories: CollectionConfig = {
@@ -65,6 +65,12 @@ export const Categories: CollectionConfig = {
collection: postsSlug,
on: 'categoriesLocalized',
},
{
name: 'hiddenPosts',
type: 'join',
collection: hiddenPostsSlug,
on: 'category',
},
{
name: 'group',
type: 'group',

View File

@@ -0,0 +1,23 @@
import type { CollectionConfig } from 'payload'
import { categoriesSlug, hiddenPostsSlug } from '../shared.js'
export const HiddenPosts: CollectionConfig = {
slug: hiddenPostsSlug,
admin: {
useAsTitle: 'title',
hidden: true,
defaultColumns: ['title', 'category'],
},
fields: [
{
name: 'title',
type: 'text',
},
{
name: 'category',
type: 'relationship',
relationTo: categoriesSlug,
},
],
}

View File

@@ -4,6 +4,7 @@ import path from 'path'
import { buildConfigWithDefaults } from '../buildConfigWithDefaults.js'
import { Categories } from './collections/Categories.js'
import { CategoriesVersions } from './collections/CategoriesVersions.js'
import { HiddenPosts } from './collections/HiddenPosts.js'
import { Posts } from './collections/Posts.js'
import { Singular } from './collections/Singular.js'
import { Uploads } from './collections/Uploads.js'
@@ -24,6 +25,7 @@ export default buildConfigWithDefaults({
collections: [
Posts,
Categories,
HiddenPosts,
Uploads,
Versions,
CategoriesVersions,

View File

@@ -56,12 +56,34 @@ test.describe('Admin Panel', () => {
test('should render initial rows within relationship table', async () => {
await navigateToDoc(page, categoriesURL)
const joinField = page.locator('.field-type.join').first()
const joinField = page.locator('#field-relatedPosts.field-type.join')
await expect(joinField).toBeVisible()
await expect(joinField.locator('.relationship-table table')).toBeVisible()
const columns = await joinField.locator('.relationship-table tbody tr').count()
expect(columns).toBe(3)
})
test('should render join field for hidden posts', async () => {
await navigateToDoc(page, categoriesURL)
const joinField = page.locator('#field-hiddenPosts.field-type.join')
await expect(joinField).toBeVisible()
await expect(joinField.locator('.relationship-table table')).toBeVisible()
const columns = await joinField.locator('.relationship-table tbody tr').count()
expect(columns).toBe(1)
const button = joinField.locator('button.doc-drawer__toggler.relationship-table__add-new')
await expect(button).toBeVisible()
await button.click()
const drawer = page.locator('[id^=doc-drawer_hidden-posts_1_]')
await expect(drawer).toBeVisible()
const titleField = drawer.locator('#field-title')
await expect(titleField).toBeVisible()
await titleField.fill('Test Hidden Post')
await drawer.locator('button[id="action-save"]').click()
await expect(joinField.locator('.relationship-table tbody tr')).toBeVisible()
const newColumns = await joinField.locator('.relationship-table tbody tr').count()
expect(newColumns).toBe(2)
})
test('should render the create page and create doc with the join field', async () => {
await page.goto(categoriesURL.create)
const nameField = page.locator('#field-name')
@@ -72,7 +94,7 @@ test.describe('Admin Panel', () => {
test('should render collection type in first column of relationship table', async () => {
await navigateToDoc(page, categoriesURL)
const joinField = page.locator('.field-type.join').first()
const joinField = page.locator('#field-relatedPosts.field-type.join')
await expect(joinField).toBeVisible()
const collectionTypeColumn = joinField.locator('thead tr th#heading-collection:first-child')
const text = collectionTypeColumn
@@ -91,7 +113,7 @@ test.describe('Admin Panel', () => {
test('should render drawer toggler without document link in second column of relationship table', async () => {
await navigateToDoc(page, categoriesURL)
const joinField = page.locator('.field-type.join').first()
const joinField = page.locator('#field-relatedPosts.field-type.join')
await expect(joinField).toBeVisible()
const actionColumn = joinField.locator('tbody tr td:nth-child(2)').first()
const toggler = actionColumn.locator('button.doc-drawer__toggler')
@@ -123,7 +145,7 @@ test.describe('Admin Panel', () => {
test('should sort relationship table by clicking on column headers', async () => {
await navigateToDoc(page, categoriesURL)
const joinField = page.locator('.field-type.join').first()
const joinField = page.locator('#field-relatedPosts.field-type.join')
await expect(joinField).toBeVisible()
const titleColumn = joinField.locator('thead tr th#heading-title')
const titleAscButton = titleColumn.locator('button.sort-column__asc')
@@ -143,7 +165,7 @@ test.describe('Admin Panel', () => {
test('should update relationship table when new document is created', async () => {
await navigateToDoc(page, categoriesURL)
const joinField = page.locator('.field-type.join').first()
const joinField = page.locator('#field-relatedPosts.field-type.join')
await expect(joinField).toBeVisible()
const addButton = joinField.locator('.relationship-table__actions button.doc-drawer__toggler', {
@@ -173,7 +195,7 @@ test.describe('Admin Panel', () => {
test('should update relationship table when document is updated', async () => {
await navigateToDoc(page, categoriesURL)
const joinField = page.locator('.field-type.join').first()
const joinField = page.locator('#field-relatedPosts.field-type.join')
await expect(joinField).toBeVisible()
const editButton = joinField.locator(
'tbody tr:first-child td:nth-child(2) button.doc-drawer__toggler',
@@ -194,14 +216,14 @@ test.describe('Admin Panel', () => {
test('should render empty relationship table when creating new document', async () => {
await page.goto(categoriesURL.create)
const joinField = page.locator('.field-type.join').first()
const joinField = page.locator('#field-relatedPosts.field-type.join')
await expect(joinField).toBeVisible()
await expect(joinField.locator('.relationship-table tbody tr')).toBeHidden()
})
test('should update relationship table when new upload is created', async () => {
await navigateToDoc(page, uploadsURL)
const joinField = page.locator('.field-type.join').first()
const joinField = page.locator('#field-relatedPosts.field-type.join')
await expect(joinField).toBeVisible()
// TODO: change this to edit the first row in the join table

View File

@@ -13,6 +13,7 @@ export interface Config {
collections: {
posts: Post;
categories: Category;
'hidden-posts': HiddenPost;
uploads: Upload;
versions: Version;
'categories-versions': CategoriesVersion;
@@ -34,6 +35,7 @@ export interface Config {
'group.relatedPosts': 'posts';
'group.camelCasePosts': 'posts';
filtered: 'posts';
hiddenPosts: 'hidden-posts';
singulars: 'singular';
};
uploads: {
@@ -53,6 +55,7 @@ export interface Config {
collectionsSelect: {
posts: PostsSelect<false> | PostsSelect<true>;
categories: CategoriesSelect<false> | CategoriesSelect<true>;
'hidden-posts': HiddenPostsSelect<false> | HiddenPostsSelect<true>;
uploads: UploadsSelect<false> | UploadsSelect<true>;
versions: VersionsSelect<false> | VersionsSelect<true>;
'categories-versions': CategoriesVersionsSelect<false> | CategoriesVersionsSelect<true>;
@@ -75,9 +78,9 @@ export interface Config {
user: User & {
collection: 'users';
};
jobs?: {
jobs: {
tasks: unknown;
workflows?: unknown;
workflows: unknown;
};
}
export interface UserAuthOperations {
@@ -105,7 +108,6 @@ export interface UserAuthOperations {
export interface Post {
id: string;
title?: string | null;
conditionalField?: string | null;
isFiltered?: boolean | null;
restrictedField?: string | null;
upload?: (string | null) | Upload;
@@ -160,6 +162,10 @@ export interface Category {
docs?: (string | Post)[] | null;
hasNextPage?: boolean | null;
} | null;
hiddenPosts?: {
docs?: (string | HiddenPost)[] | null;
hasNextPage?: boolean | null;
} | null;
group?: {
relatedPosts?: {
docs?: (string | Post)[] | null;
@@ -181,6 +187,17 @@ export interface Category {
updatedAt: string;
createdAt: string;
}
/**
* This interface was referenced by `Config`'s JSON-Schema
* via the `definition` "hidden-posts".
*/
export interface HiddenPost {
id: string;
title?: string | null;
category?: (string | null) | Category;
updatedAt: string;
createdAt: string;
}
/**
* This interface was referenced by `Config`'s JSON-Schema
* via the `definition` "singular".
@@ -305,6 +322,10 @@ export interface PayloadLockedDocument {
relationTo: 'categories';
value: string | Category;
} | null)
| ({
relationTo: 'hidden-posts';
value: string | HiddenPost;
} | null)
| ({
relationTo: 'uploads';
value: string | Upload;
@@ -389,7 +410,6 @@ export interface PayloadMigration {
*/
export interface PostsSelect<T extends boolean = true> {
title?: T;
conditionalField?: T;
isFiltered?: T;
restrictedField?: T;
upload?: T;
@@ -414,6 +434,7 @@ export interface CategoriesSelect<T extends boolean = true> {
relatedPosts?: T;
hasManyPosts?: T;
hasManyPostsLocalized?: T;
hiddenPosts?: T;
group?:
| T
| {
@@ -425,6 +446,16 @@ export interface CategoriesSelect<T extends boolean = true> {
updatedAt?: T;
createdAt?: T;
}
/**
* This interface was referenced by `Config`'s JSON-Schema
* via the `definition` "hidden-posts_select".
*/
export interface HiddenPostsSelect<T extends boolean = true> {
title?: T;
category?: T;
updatedAt?: T;
createdAt?: T;
}
/**
* This interface was referenced by `Config`'s JSON-Schema
* via the `definition` "uploads_select".

View File

@@ -6,7 +6,13 @@ import { fileURLToPath } from 'url'
import { devUser } from '../credentials.js'
import { seedDB } from '../helpers/seed.js'
import { categoriesSlug, collectionSlugs, postsSlug, uploadsSlug } from './shared.js'
import {
categoriesSlug,
collectionSlugs,
hiddenPostsSlug,
postsSlug,
uploadsSlug,
} from './shared.js'
const filename = fileURLToPath(import.meta.url)
const dirname = path.dirname(filename)
@@ -28,6 +34,14 @@ export const seed = async (_payload) => {
},
})
await _payload.create({
collection: hiddenPostsSlug,
data: {
category: category.id,
title: 'Test Post 1',
},
})
await _payload.create({
collection: postsSlug,
data: {

View File

@@ -1,7 +1,11 @@
export const categoriesSlug = 'categories'
export const categories2Slug = 'categories-2'
export const postsSlug = 'posts'
export const hiddenPostsSlug = 'hidden-posts'
export const uploadsSlug = 'uploads'
export const localizedPostsSlug = 'localized-posts'