feat: drag-and-drop columns (#2142)
This commit is contained in:
@@ -82,6 +82,8 @@ export default buildConfig({
|
||||
description: { en: 'Description en', es: 'Description es' },
|
||||
listSearchableFields: ['title', 'description', 'number'],
|
||||
group: { en: 'One', es: 'Una' },
|
||||
useAsTitle: 'title',
|
||||
defaultColumns: ['id', 'number', 'title', 'description'],
|
||||
},
|
||||
fields: [
|
||||
{
|
||||
@@ -100,6 +102,15 @@ export default buildConfig({
|
||||
name: 'number',
|
||||
type: 'number',
|
||||
},
|
||||
{
|
||||
name: 'richText',
|
||||
type: 'richText',
|
||||
admin: {
|
||||
elements: [
|
||||
'relationship',
|
||||
],
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
|
||||
@@ -152,13 +152,13 @@ describe('admin', () => {
|
||||
});
|
||||
|
||||
test('should delete existing', async () => {
|
||||
const { id } = await createPost();
|
||||
const { id, ...post } = await createPost();
|
||||
|
||||
await page.goto(url.edit(id));
|
||||
await page.locator('#action-delete').click();
|
||||
await page.locator('#confirm-delete').click();
|
||||
|
||||
await expect(page.locator(`text=Post en "${id}" successfully deleted.`)).toBeVisible();
|
||||
await expect(page.locator(`text=Post en "${post.title}" successfully deleted.`)).toBeVisible();
|
||||
expect(page.url()).toContain(url.list);
|
||||
});
|
||||
|
||||
@@ -231,28 +231,63 @@ describe('admin', () => {
|
||||
const columnCountLocator = 'table >> thead >> tr >> th';
|
||||
await createPost();
|
||||
await page.locator('.list-controls__toggle-columns').click();
|
||||
await wait(1000); // Wait for column toggle UI, should probably use waitForSelector
|
||||
await wait(500); // Wait for column toggle UI, should probably use waitForSelector
|
||||
|
||||
const numberOfColumns = await page.locator(columnCountLocator).count();
|
||||
const idButton = page.locator('.column-selector >> text=ID');
|
||||
await expect(await page.locator('table >> thead >> tr >> th:first-child')).toHaveText('ID');
|
||||
|
||||
const idButton = await page.locator('.column-selector >> text=ID');
|
||||
|
||||
// Remove ID column
|
||||
await idButton.click({ delay: 100 });
|
||||
await expect(page.locator(columnCountLocator)).toHaveCount(numberOfColumns - 1);
|
||||
await idButton.click();
|
||||
await wait(100);
|
||||
await expect(await page.locator(columnCountLocator)).toHaveCount(numberOfColumns - 1);
|
||||
await expect(await page.locator('table >> thead >> tr >> th:first-child')).toHaveText('Number');
|
||||
|
||||
// Add back ID column
|
||||
await idButton.click({ delay: 100 });
|
||||
await expect(page.locator(columnCountLocator)).toHaveCount(numberOfColumns);
|
||||
await idButton.click();
|
||||
await wait(100);
|
||||
await expect(await page.locator(columnCountLocator)).toHaveCount(numberOfColumns);
|
||||
await expect(await page.locator('table >> thead >> tr >> th:first-child')).toHaveText('ID');
|
||||
});
|
||||
|
||||
test('first cell is a link', async () => {
|
||||
const { id } = await createPost();
|
||||
const firstCell = await page.locator(`${tableRowLocator} td`).first().locator('a');
|
||||
await expect(firstCell).toHaveAttribute('href', `/admin/collections/posts/${id}`);
|
||||
|
||||
// open the column controls
|
||||
await page.locator('.list-controls__toggle-columns').click();
|
||||
await wait(500); // Wait for column toggle UI, should probably use waitForSelector (same as above)
|
||||
|
||||
// toggle off the ID column
|
||||
page.locator('.column-selector >> text=ID').click();
|
||||
await wait(200);
|
||||
|
||||
// recheck that the first cell is still a link
|
||||
await expect(firstCell).toHaveAttribute('href', `/admin/collections/posts/${id}`);
|
||||
});
|
||||
|
||||
test('filter rows', async () => {
|
||||
const { id } = await createPost({ title: 'post1' });
|
||||
await createPost({ title: 'post2' });
|
||||
|
||||
// open the column controls
|
||||
await page.locator('.list-controls__toggle-columns').click();
|
||||
await wait(500); // Wait for column toggle UI, should probably use waitForSelector (same as above)
|
||||
|
||||
// ensure the ID column is active
|
||||
const idButton = await page.locator('.column-selector >> text=ID');
|
||||
const buttonClasses = await idButton.getAttribute('class');
|
||||
if (buttonClasses && !buttonClasses.includes('column-selector__column--active')) {
|
||||
await idButton.click();
|
||||
await wait(200);
|
||||
}
|
||||
|
||||
await expect(page.locator(tableRowLocator)).toHaveCount(2);
|
||||
|
||||
await page.locator('.list-controls__toggle-where').click();
|
||||
await wait(1000); // Wait for column toggle UI, should probably use waitForSelector
|
||||
await wait(500); // Wait for column toggle UI, should probably use waitForSelector (same as above)
|
||||
|
||||
await page.locator('.where-builder__add-first-filter').click();
|
||||
|
||||
@@ -277,6 +312,58 @@ describe('admin', () => {
|
||||
await wait(1000);
|
||||
await expect(page.locator(tableRowLocator)).toHaveCount(2);
|
||||
});
|
||||
|
||||
test('drag and reorder columns', async () => {
|
||||
await createPost();
|
||||
|
||||
// open the column controls
|
||||
await page.locator('.list-controls__toggle-columns').click();
|
||||
await wait(500); // Wait for column toggle UI, should probably use waitForSelector (same as above)
|
||||
|
||||
const numberBoundingBox = await page.locator('.column-selector >> text=Number').boundingBox();
|
||||
const idBoundingBox = await page.locator('.column-selector >> text=ID').boundingBox();
|
||||
|
||||
if (!numberBoundingBox || !idBoundingBox) return;
|
||||
|
||||
// drag the "number" column to the left of the "ID" column
|
||||
await page.mouse.move(numberBoundingBox.x + 2, numberBoundingBox.y + 2, { steps: 10 });
|
||||
await page.mouse.down();
|
||||
await wait(200);
|
||||
await page.mouse.move(idBoundingBox.x - 2, idBoundingBox.y - 2, { steps: 10 });
|
||||
await page.mouse.up();
|
||||
|
||||
// wait for the new preferences to save and internal state to update and re-render
|
||||
await wait(400);
|
||||
|
||||
// ensure the "number" column is now first
|
||||
await expect(await page.locator('.list-controls .column-selector .column-selector__column').first()).toHaveText('Number');
|
||||
await expect(await page.locator('table >> thead >> tr >> th').first()).toHaveText('Number');
|
||||
|
||||
// reload to ensure the preferred order was stored in the database
|
||||
await page.reload();
|
||||
await expect(await page.locator('.list-controls .column-selector .column-selector__column').first()).toHaveText('Number');
|
||||
await expect(await page.locator('table >> thead >> tr >> th').first()).toHaveText('Number');
|
||||
});
|
||||
|
||||
test('reorder columns from drawer', async () => {
|
||||
await page.goto(url.create);
|
||||
|
||||
// Open the drawer
|
||||
await page.locator('.rich-text .list-drawer__toggler').click();
|
||||
const listDrawer = page.locator('[id^=list-drawer_1_]');
|
||||
await expect(listDrawer).toBeVisible();
|
||||
|
||||
await page.locator('[id^=list-drawer_1_] .list-drawer__select-collection.react-select').click();
|
||||
// select the "post en" collection
|
||||
await page.locator('[id^=list-drawer_1_] .list-drawer__select-collection.react-select .rs__option >> text="Post en"').click();
|
||||
|
||||
// open the column controls
|
||||
await page.locator('[id^=list-drawer_1_] .list-controls__toggle-columns').click();
|
||||
await wait(500); // Wait for column toggle UI, should probably use waitForSelector (same as above)
|
||||
|
||||
// ensure that the columns are in the correct order
|
||||
await expect(await page.locator('[id^=list-drawer_1_] .list-controls .column-selector .column-selector__column').first()).toHaveText('Number');
|
||||
});
|
||||
});
|
||||
|
||||
describe('pagination', () => {
|
||||
@@ -394,7 +481,7 @@ describe('admin', () => {
|
||||
});
|
||||
|
||||
async function createPost(overrides?: Partial<Post>): Promise<Post> {
|
||||
return payload.create<Post>({
|
||||
return payload.create({
|
||||
collection: slug,
|
||||
data: {
|
||||
title,
|
||||
@@ -405,7 +492,7 @@ async function createPost(overrides?: Partial<Post>): Promise<Post> {
|
||||
}
|
||||
|
||||
async function clearDocs(): Promise<void> {
|
||||
const allDocs = await payload.find<Post>({ collection: slug, limit: 100 });
|
||||
const allDocs = await payload.find({ collection: slug, limit: 100 });
|
||||
const ids = allDocs.docs.map((doc) => doc.id);
|
||||
await mapAsync(ids, async (id) => {
|
||||
await payload.delete({ collection: slug, id });
|
||||
|
||||
Reference in New Issue
Block a user