fix(ui): stacking drawers (#7397)
This commit is contained in:
@@ -25,7 +25,8 @@ $transTime: 200;
|
||||
transform: translateX(calc(var(--base) * 4));
|
||||
position: relative;
|
||||
z-index: 2;
|
||||
width: calc(100% - var(--gutter-h));
|
||||
// NOTE: width is controlled by js
|
||||
// width: calc(100% - var(--gutter-h));
|
||||
overflow: hidden;
|
||||
transition: all #{$transTime}ms linear;
|
||||
background-color: var(--theme-bg);
|
||||
|
||||
@@ -55,6 +55,7 @@ export const Drawer: React.FC<Props> = ({
|
||||
const { t } = useTranslation()
|
||||
const { closeModal, modalState } = useModal()
|
||||
const drawerDepth = useEditDepth()
|
||||
|
||||
const [isOpen, setIsOpen] = useState(false)
|
||||
const [animateIn, setAnimateIn] = useState(false)
|
||||
|
||||
@@ -91,7 +92,12 @@ export const Drawer: React.FC<Props> = ({
|
||||
onClick={() => closeModal(slug)}
|
||||
type="button"
|
||||
/>
|
||||
<div className={`${baseClass}__content`}>
|
||||
<div
|
||||
className={`${baseClass}__content`}
|
||||
style={{
|
||||
width: `calc(100% - (${drawerDepth} * var(--gutter-h))`,
|
||||
}}
|
||||
>
|
||||
<div className={`${baseClass}__blur-bg-content`} />
|
||||
<Gutter className={`${baseClass}__content-children`} left={gutter} right={gutter}>
|
||||
<EditDepthContext.Provider value={drawerDepth + 1}>
|
||||
|
||||
@@ -55,6 +55,7 @@ const description = 'Description'
|
||||
|
||||
let payload: PayloadTestSDK<Config>
|
||||
|
||||
import { navigateToDoc } from 'helpers/e2e/navigateToDoc.js'
|
||||
import path from 'path'
|
||||
import { fileURLToPath } from 'url'
|
||||
|
||||
@@ -813,6 +814,99 @@ describe('admin1', () => {
|
||||
})
|
||||
})
|
||||
|
||||
describe('i18n', () => {
|
||||
test('should allow changing language', async () => {
|
||||
await page.goto(postsUrl.account)
|
||||
|
||||
const field = page.locator('.payload-settings__language .react-select')
|
||||
|
||||
await field.click()
|
||||
const options = page.locator('.rs__option')
|
||||
await options.locator('text=Español').click()
|
||||
|
||||
await expect(page.locator('.step-nav a').first().locator('span')).toHaveAttribute(
|
||||
'title',
|
||||
'Tablero',
|
||||
)
|
||||
|
||||
await field.click()
|
||||
await options.locator('text=English').click()
|
||||
await field.click()
|
||||
await expect(page.locator('.form-submit .btn')).toContainText('Save')
|
||||
})
|
||||
|
||||
test('should allow custom translation', async () => {
|
||||
await page.goto(postsUrl.account)
|
||||
await expect(page.locator('.step-nav a').first().locator('span')).toHaveAttribute(
|
||||
'title',
|
||||
'Home',
|
||||
)
|
||||
})
|
||||
|
||||
test('should allow custom translation of locale labels', async () => {
|
||||
const selectOptionClass = '.localizer .popup-button-list__button'
|
||||
const localizerButton = page.locator('.localizer .popup-button')
|
||||
const localeListItem1 = page.locator(selectOptionClass).nth(0)
|
||||
|
||||
async function checkLocaleLabels(firstLabel: string, secondLabel: string) {
|
||||
await localizerButton.click()
|
||||
await expect(page.locator(selectOptionClass).first()).toContainText(firstLabel)
|
||||
await expect(page.locator(selectOptionClass).nth(1)).toContainText(secondLabel)
|
||||
}
|
||||
|
||||
await checkLocaleLabels('Spanish (es)', 'English (en)')
|
||||
|
||||
// Change locale to Spanish
|
||||
await localizerButton.click()
|
||||
await expect(localeListItem1).toContainText('Spanish (es)')
|
||||
await localeListItem1.click()
|
||||
|
||||
// Go to account page
|
||||
await page.goto(postsUrl.account)
|
||||
|
||||
const languageField = page.locator('.payload-settings__language .react-select')
|
||||
const options = page.locator('.rs__option')
|
||||
|
||||
// Change language to Spanish
|
||||
await languageField.click()
|
||||
await options.locator('text=Español').click()
|
||||
|
||||
await checkLocaleLabels('Español (es)', 'Inglés (en)')
|
||||
|
||||
// Change locale and language back to English
|
||||
await languageField.click()
|
||||
await options.locator('text=English').click()
|
||||
await localizerButton.click()
|
||||
await expect(localeListItem1).toContainText('Spanish (es)')
|
||||
})
|
||||
})
|
||||
|
||||
describe('drawers', () => {
|
||||
test('document drawers are visually stacking', async () => {
|
||||
await navigateToDoc(page, postsUrl)
|
||||
await page.locator('#field-title').fill(title)
|
||||
await saveDocAndAssert(page)
|
||||
await page
|
||||
.locator(
|
||||
'.field-type.relationship .relationship--single-value__drawer-toggler.doc-drawer__toggler',
|
||||
)
|
||||
.click()
|
||||
await wait(500)
|
||||
const drawer1Content = page.locator('[id^=doc-drawer_posts_1_] .drawer__content')
|
||||
await expect(drawer1Content).toBeVisible()
|
||||
const drawerLeft = await drawer1Content.boundingBox().then((box) => box.x)
|
||||
await drawer1Content
|
||||
.locator(
|
||||
'.field-type.relationship .relationship--single-value__drawer-toggler.doc-drawer__toggler',
|
||||
)
|
||||
.click()
|
||||
const drawer2Content = page.locator('[id^=doc-drawer_posts_2_] .drawer__content')
|
||||
await expect(drawer2Content).toBeVisible()
|
||||
const drawer2Left = await drawer2Content.boundingBox().then((box) => box.x)
|
||||
expect(drawer2Left > drawerLeft).toBe(true)
|
||||
})
|
||||
})
|
||||
|
||||
describe('CRUD', () => {
|
||||
test('should create', async () => {
|
||||
await page.goto(postsUrl.create)
|
||||
@@ -954,73 +1048,6 @@ describe('admin1', () => {
|
||||
await expect(idField).toHaveValue(customIdCollectionId)
|
||||
})
|
||||
})
|
||||
|
||||
describe('i18n', () => {
|
||||
test('should allow changing language', async () => {
|
||||
await page.goto(postsUrl.account)
|
||||
|
||||
const field = page.locator('.payload-settings__language .react-select')
|
||||
|
||||
await field.click()
|
||||
const options = page.locator('.rs__option')
|
||||
await options.locator('text=Español').click()
|
||||
|
||||
await expect(page.locator('.step-nav a').first().locator('span')).toHaveAttribute(
|
||||
'title',
|
||||
'Tablero',
|
||||
)
|
||||
|
||||
await field.click()
|
||||
await options.locator('text=English').click()
|
||||
await field.click()
|
||||
await expect(page.locator('.form-submit .btn')).toContainText('Save')
|
||||
})
|
||||
|
||||
test('should allow custom translation', async () => {
|
||||
await page.goto(postsUrl.account)
|
||||
await expect(page.locator('.step-nav a').first().locator('span')).toHaveAttribute(
|
||||
'title',
|
||||
'Home',
|
||||
)
|
||||
})
|
||||
|
||||
test('should allow custom translation of locale labels', async () => {
|
||||
const selectOptionClass = '.localizer .popup-button-list__button'
|
||||
const localizerButton = page.locator('.localizer .popup-button')
|
||||
const localeListItem1 = page.locator(selectOptionClass).nth(0)
|
||||
|
||||
async function checkLocaleLabels(firstLabel: string, secondLabel: string) {
|
||||
await localizerButton.click()
|
||||
await expect(page.locator(selectOptionClass).first()).toContainText(firstLabel)
|
||||
await expect(page.locator(selectOptionClass).nth(1)).toContainText(secondLabel)
|
||||
}
|
||||
|
||||
await checkLocaleLabels('Spanish (es)', 'English (en)')
|
||||
|
||||
// Change locale to Spanish
|
||||
await localizerButton.click()
|
||||
await expect(localeListItem1).toContainText('Spanish (es)')
|
||||
await localeListItem1.click()
|
||||
|
||||
// Go to account page
|
||||
await page.goto(postsUrl.account)
|
||||
|
||||
const languageField = page.locator('.payload-settings__language .react-select')
|
||||
const options = page.locator('.rs__option')
|
||||
|
||||
// Change language to Spanish
|
||||
await languageField.click()
|
||||
await options.locator('text=Español').click()
|
||||
|
||||
await checkLocaleLabels('Español (es)', 'Inglés (en)')
|
||||
|
||||
// Change locale and language back to English
|
||||
await languageField.click()
|
||||
await options.locator('text=English').click()
|
||||
await localizerButton.click()
|
||||
await expect(localeListItem1).toContainText('Spanish (es)')
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
async function createPost(overrides?: Partial<Post>): Promise<Post> {
|
||||
|
||||
@@ -40,18 +40,31 @@ export const seed = async (_payload) => {
|
||||
depth: 0,
|
||||
overrideAccess: true,
|
||||
}),
|
||||
...[...Array(11)].map(
|
||||
() => () =>
|
||||
_payload.create({
|
||||
collection: postsCollectionSlug,
|
||||
data: {
|
||||
description: 'Description',
|
||||
title: 'Title',
|
||||
...[...Array(11)].map(() => async () => {
|
||||
const postDoc = await _payload.create({
|
||||
collection: postsCollectionSlug,
|
||||
data: {
|
||||
description: 'Description',
|
||||
title: 'Title',
|
||||
},
|
||||
depth: 0,
|
||||
overrideAccess: true,
|
||||
})
|
||||
|
||||
return await _payload.update({
|
||||
collection: postsCollectionSlug,
|
||||
where: {
|
||||
id: {
|
||||
equals: postDoc.id,
|
||||
},
|
||||
depth: 0,
|
||||
overrideAccess: true,
|
||||
}),
|
||||
),
|
||||
},
|
||||
data: {
|
||||
relationship: postDoc.id,
|
||||
},
|
||||
depth: 0,
|
||||
overrideAccess: true,
|
||||
})
|
||||
}),
|
||||
() =>
|
||||
_payload.create({
|
||||
collection: customViews1CollectionSlug,
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import type { Page } from '@playwright/test'
|
||||
|
||||
import { expect, test } from '@playwright/test'
|
||||
import { navigateToDoc } from 'helpers/e2e/navigateToDoc.js'
|
||||
import path from 'path'
|
||||
import { wait } from 'payload/shared'
|
||||
import { fileURLToPath } from 'url'
|
||||
@@ -11,7 +12,6 @@ import type { Config } from '../../payload-types.js'
|
||||
import {
|
||||
ensureCompilationIsDone,
|
||||
initPageConsoleErrorCatch,
|
||||
navigateToListCellLink,
|
||||
saveDocAndAssert,
|
||||
switchTab,
|
||||
} from '../../../helpers.js'
|
||||
@@ -97,8 +97,7 @@ describe('Tabs', () => {
|
||||
test('should retain updated values within tabs while switching between tabs', async () => {
|
||||
const textInRowValue = 'new value'
|
||||
const jsonValue = '{ "new": "value"}'
|
||||
await page.goto(url.list)
|
||||
await navigateToListCellLink(page)
|
||||
await navigateToDoc(page, url)
|
||||
|
||||
// Go to Row tab, update the value
|
||||
await switchTab(page, '.tabs-field__tab-button:has-text("Tab with Row")')
|
||||
@@ -125,15 +124,13 @@ describe('Tabs', () => {
|
||||
})
|
||||
|
||||
test('should render array data within unnamed tabs', async () => {
|
||||
await page.goto(url.list)
|
||||
await navigateToListCellLink(page)
|
||||
await navigateToDoc(page, url)
|
||||
await switchTab(page, '.tabs-field__tab-button:has-text("Tab with Array")')
|
||||
await expect(page.locator('#field-array__0__text')).toHaveValue("Hello, I'm the first row")
|
||||
})
|
||||
|
||||
test('should render array data within named tabs', async () => {
|
||||
await page.goto(url.list)
|
||||
await navigateToListCellLink(page)
|
||||
await navigateToDoc(page, url)
|
||||
await switchTab(page, '.tabs-field__tab-button:nth-child(5)')
|
||||
await expect(page.locator('#field-tab__array__0__text')).toHaveValue(
|
||||
"Hello, I'm the first row, in a named tab",
|
||||
|
||||
@@ -270,13 +270,6 @@ export const findTableCell = (page: Page, fieldName: string, rowTitle?: string):
|
||||
return cell
|
||||
}
|
||||
|
||||
export async function navigateToListCellLink(page: Page, selector = '.cell-id') {
|
||||
const cellLink = page.locator(`${selector} a`).first()
|
||||
const linkURL = await cellLink.getAttribute('href')
|
||||
await cellLink.click()
|
||||
await page.waitForURL(`**${linkURL}`)
|
||||
}
|
||||
|
||||
export const findTableRow = (page: Page, title: string): Locator => {
|
||||
const row = page.locator(`tbody tr:has-text("${title}")`)
|
||||
expect(row).toBeTruthy()
|
||||
|
||||
10
test/helpers/e2e/navigateToDoc.ts
Normal file
10
test/helpers/e2e/navigateToDoc.ts
Normal file
@@ -0,0 +1,10 @@
|
||||
import type { Page } from '@playwright/test'
|
||||
import type { AdminUrlUtil } from 'helpers/adminUrlUtil.js'
|
||||
|
||||
import { navigateToListCellLink } from './navigateToFirstCellLink.js'
|
||||
|
||||
export const navigateToDoc = async (page: Page, urlUtil: AdminUrlUtil) => {
|
||||
await page.goto(urlUtil.list)
|
||||
await page.waitForURL(urlUtil.list)
|
||||
await navigateToListCellLink(page)
|
||||
}
|
||||
8
test/helpers/e2e/navigateToFirstCellLink.ts
Normal file
8
test/helpers/e2e/navigateToFirstCellLink.ts
Normal file
@@ -0,0 +1,8 @@
|
||||
import type { Page } from '@playwright/test'
|
||||
|
||||
export async function navigateToListCellLink(page: Page, selector = '.cell-id') {
|
||||
const cellLink = page.locator(`${selector} a`).first()
|
||||
const linkURL = await cellLink.getAttribute('href')
|
||||
await cellLink.click()
|
||||
await page.waitForURL(`**${linkURL}`)
|
||||
}
|
||||
@@ -11,13 +11,13 @@ import {
|
||||
saveDocAndAssert,
|
||||
} from '../helpers.js'
|
||||
import { AdminUrlUtil } from '../helpers/adminUrlUtil.js'
|
||||
import { navigateToDoc } from '../helpers/e2e/navigateToDoc.js'
|
||||
import { initPayloadE2ENoConfig } from '../helpers/initPayloadE2ENoConfig.js'
|
||||
import { POLL_TOPASS_TIMEOUT, TEST_TIMEOUT_LONG } from '../playwright.config.js'
|
||||
import {
|
||||
ensureDeviceIsCentered,
|
||||
ensureDeviceIsLeftAligned,
|
||||
goToCollectionLivePreview,
|
||||
goToDoc,
|
||||
goToGlobalLivePreview,
|
||||
selectLivePreviewBreakpoint,
|
||||
selectLivePreviewZoom,
|
||||
@@ -61,7 +61,7 @@ describe('Live Preview', () => {
|
||||
})
|
||||
|
||||
test('collection — has tab', async () => {
|
||||
await goToDoc(page, pagesURLUtil)
|
||||
await navigateToDoc(page, pagesURLUtil)
|
||||
|
||||
const livePreviewTab = page.locator('.doc-tab', {
|
||||
hasText: exactText('Live Preview'),
|
||||
|
||||
@@ -2,21 +2,16 @@ import type { Page } from '@playwright/test'
|
||||
|
||||
import { expect } from '@playwright/test'
|
||||
|
||||
import { exactText, navigateToListCellLink } from '../helpers.js'
|
||||
import { exactText } from '../helpers.js'
|
||||
import { AdminUrlUtil } from '../helpers/adminUrlUtil.js'
|
||||
import { navigateToDoc } from '../helpers/e2e/navigateToDoc.js'
|
||||
import { POLL_TOPASS_TIMEOUT } from '../playwright.config.js'
|
||||
|
||||
export const goToDoc = async (page: Page, urlUtil: AdminUrlUtil) => {
|
||||
await page.goto(urlUtil.list)
|
||||
await page.waitForURL(urlUtil.list)
|
||||
await navigateToListCellLink(page)
|
||||
}
|
||||
|
||||
export const goToCollectionLivePreview = async (
|
||||
page: Page,
|
||||
urlUtil: AdminUrlUtil,
|
||||
): Promise<void> => {
|
||||
await goToDoc(page, urlUtil)
|
||||
await navigateToDoc(page, urlUtil)
|
||||
await page.goto(`${page.url()}/preview`)
|
||||
await page.waitForURL(`**/preview`)
|
||||
}
|
||||
|
||||
@@ -37,7 +37,7 @@
|
||||
],
|
||||
"paths": {
|
||||
"@payload-config": [
|
||||
"./test/_community/config.ts"
|
||||
"./test/admin/config.ts"
|
||||
],
|
||||
"@payloadcms/live-preview": [
|
||||
"./packages/live-preview/src"
|
||||
|
||||
Reference in New Issue
Block a user