refactor(ui): moves bulk edit controls (#11332)
Bulk edit controls are currently displayed within the search bar of the list view. This doesn't make sense from a UX perspective, as the current selection is displayed somewhere else entirely. These controls also take up a lot of visual real estate which is beginning to get overused especially after the introduction of "list menu items" in #11230, and the potential introduction of "saved filters" controls in #11330. Now, they are rendered contextually _alongside_ the selection count. To make room for these new controls, they are displayed in plain text and the entity labels have been removed from the selection count.
This commit is contained in:
@@ -7,5 +7,21 @@
|
|||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
|
|
||||||
|
&__toggle {
|
||||||
|
font-size: inherit;
|
||||||
|
line-height: inherit;
|
||||||
|
display: inline-flex;
|
||||||
|
background: transparent;
|
||||||
|
color: var(--theme-elevation-800);
|
||||||
|
white-space: nowrap;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
border: 0;
|
||||||
|
padding: 0;
|
||||||
|
align-items: center;
|
||||||
|
cursor: pointer;
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,7 +16,6 @@ import { useTranslation } from '../../providers/Translation/index.js'
|
|||||||
import { requests } from '../../utilities/api.js'
|
import { requests } from '../../utilities/api.js'
|
||||||
import { mergeListSearchAndWhere } from '../../utilities/mergeListSearchAndWhere.js'
|
import { mergeListSearchAndWhere } from '../../utilities/mergeListSearchAndWhere.js'
|
||||||
import { ConfirmationModal } from '../ConfirmationModal/index.js'
|
import { ConfirmationModal } from '../ConfirmationModal/index.js'
|
||||||
import { Pill } from '../Pill/index.js'
|
|
||||||
import './index.scss'
|
import './index.scss'
|
||||||
|
|
||||||
const baseClass = 'delete-documents'
|
const baseClass = 'delete-documents'
|
||||||
@@ -140,14 +139,15 @@ export const DeleteMany: React.FC<Props> = (props) => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<React.Fragment>
|
<React.Fragment>
|
||||||
<Pill
|
<button
|
||||||
className={`${baseClass}__toggle`}
|
className={`${baseClass}__toggle`}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
openModal(modalSlug)
|
openModal(modalSlug)
|
||||||
}}
|
}}
|
||||||
|
type="button"
|
||||||
>
|
>
|
||||||
{t('general:delete')}
|
{t('general:delete')}
|
||||||
</Pill>
|
</button>
|
||||||
<ConfirmationModal
|
<ConfirmationModal
|
||||||
body={t('general:aboutToDeleteCount', {
|
body={t('general:aboutToDeleteCount', {
|
||||||
count,
|
count,
|
||||||
|
|||||||
@@ -3,33 +3,19 @@
|
|||||||
@layer payload-default {
|
@layer payload-default {
|
||||||
.edit-many {
|
.edit-many {
|
||||||
&__toggle {
|
&__toggle {
|
||||||
font-size: 1rem;
|
font-size: inherit;
|
||||||
line-height: base(1.2);
|
line-height: inherit;
|
||||||
display: inline-flex;
|
display: inline-flex;
|
||||||
background: var(--theme-elevation-150);
|
background: transparent;
|
||||||
color: var(--theme-elevation-800);
|
color: var(--theme-elevation-800);
|
||||||
border-radius: $style-radius-s;
|
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
text-overflow: ellipsis;
|
text-overflow: ellipsis;
|
||||||
border: 0;
|
border: 0;
|
||||||
padding: 0 base(0.4);
|
padding: 0;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
text-decoration: none;
|
text-decoration: underline;
|
||||||
|
|
||||||
&:active,
|
|
||||||
&:focus {
|
|
||||||
outline: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
background: var(--theme-elevation-100);
|
|
||||||
}
|
|
||||||
|
|
||||||
&:active {
|
|
||||||
background: var(--theme-elevation-100);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
&__form {
|
&__form {
|
||||||
|
|||||||
@@ -1,15 +1,16 @@
|
|||||||
'use client'
|
'use client'
|
||||||
import type { ClientCollectionConfig, FieldWithPathClient } from 'payload'
|
import type { ClientCollectionConfig, FieldWithPathClient } from 'payload'
|
||||||
|
|
||||||
|
import { useModal } from '@faceless-ui/modal'
|
||||||
import React, { useState } from 'react'
|
import React, { useState } from 'react'
|
||||||
|
|
||||||
import { useAuth } from '../../providers/Auth/index.js'
|
import { useAuth } from '../../providers/Auth/index.js'
|
||||||
import { EditDepthProvider } from '../../providers/EditDepth/index.js'
|
import { EditDepthProvider } from '../../providers/EditDepth/index.js'
|
||||||
import { SelectAllStatus, useSelection } from '../../providers/Selection/index.js'
|
import { SelectAllStatus, useSelection } from '../../providers/Selection/index.js'
|
||||||
import { useTranslation } from '../../providers/Translation/index.js'
|
import { useTranslation } from '../../providers/Translation/index.js'
|
||||||
import './index.scss'
|
import { Drawer } from '../Drawer/index.js'
|
||||||
import { Drawer, DrawerToggler } from '../Drawer/index.js'
|
|
||||||
import { EditManyDrawerContent } from './DrawerContent.js'
|
import { EditManyDrawerContent } from './DrawerContent.js'
|
||||||
|
import './index.scss'
|
||||||
|
|
||||||
export const baseClass = 'edit-many'
|
export const baseClass = 'edit-many'
|
||||||
|
|
||||||
@@ -23,6 +24,7 @@ export const EditMany: React.FC<EditManyProps> = (props) => {
|
|||||||
} = props
|
} = props
|
||||||
|
|
||||||
const { permissions } = useAuth()
|
const { permissions } = useAuth()
|
||||||
|
const { openModal } = useModal()
|
||||||
|
|
||||||
const { selectAll } = useSelection()
|
const { selectAll } = useSelection()
|
||||||
const { t } = useTranslation()
|
const { t } = useTranslation()
|
||||||
@@ -39,16 +41,17 @@ export const EditMany: React.FC<EditManyProps> = (props) => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={baseClass}>
|
<div className={baseClass}>
|
||||||
<DrawerToggler
|
<button
|
||||||
aria-label={t('general:edit')}
|
aria-label={t('general:edit')}
|
||||||
className={`${baseClass}__toggle`}
|
className={`${baseClass}__toggle`}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
|
openModal(drawerSlug)
|
||||||
setSelected([])
|
setSelected([])
|
||||||
}}
|
}}
|
||||||
slug={drawerSlug}
|
type="button"
|
||||||
>
|
>
|
||||||
{t('general:edit')}
|
{t('general:edit')}
|
||||||
</DrawerToggler>
|
</button>
|
||||||
<EditDepthProvider>
|
<EditDepthProvider>
|
||||||
<Drawer Header={null} slug={drawerSlug}>
|
<Drawer Header={null} slug={drawerSlug}>
|
||||||
<EditManyDrawerContent
|
<EditManyDrawerContent
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import type { ClientCollectionConfig, ResolvedFilterOptions, Where } from 'paylo
|
|||||||
|
|
||||||
import { useWindowInfo } from '@faceless-ui/window-info'
|
import { useWindowInfo } from '@faceless-ui/window-info'
|
||||||
import { getTranslation } from '@payloadcms/translations'
|
import { getTranslation } from '@payloadcms/translations'
|
||||||
import React, { Fragment, useEffect, useRef, useState } from 'react'
|
import React, { useEffect, useRef, useState } from 'react'
|
||||||
|
|
||||||
import { Popup, PopupList } from '../../elements/Popup/index.js'
|
import { Popup, PopupList } from '../../elements/Popup/index.js'
|
||||||
import { useUseTitleField } from '../../hooks/useUseAsTitle.js'
|
import { useUseTitleField } from '../../hooks/useUseAsTitle.js'
|
||||||
@@ -14,12 +14,8 @@ import { useListQuery } from '../../providers/ListQuery/index.js'
|
|||||||
import { useTranslation } from '../../providers/Translation/index.js'
|
import { useTranslation } from '../../providers/Translation/index.js'
|
||||||
import { AnimateHeight } from '../AnimateHeight/index.js'
|
import { AnimateHeight } from '../AnimateHeight/index.js'
|
||||||
import { ColumnSelector } from '../ColumnSelector/index.js'
|
import { ColumnSelector } from '../ColumnSelector/index.js'
|
||||||
import { DeleteMany } from '../DeleteMany/index.js'
|
|
||||||
import { EditMany } from '../EditMany/index.js'
|
|
||||||
import { Pill } from '../Pill/index.js'
|
import { Pill } from '../Pill/index.js'
|
||||||
import { PublishMany } from '../PublishMany/index.js'
|
|
||||||
import { SearchFilter } from '../SearchFilter/index.js'
|
import { SearchFilter } from '../SearchFilter/index.js'
|
||||||
import { UnpublishMany } from '../UnpublishMany/index.js'
|
|
||||||
import { WhereBuilder } from '../WhereBuilder/index.js'
|
import { WhereBuilder } from '../WhereBuilder/index.js'
|
||||||
import validateWhereQuery from '../WhereBuilder/validateWhereQuery.js'
|
import validateWhereQuery from '../WhereBuilder/validateWhereQuery.js'
|
||||||
import { getTextFieldsToBeSearched } from './getTextFieldsToBeSearched.js'
|
import { getTextFieldsToBeSearched } from './getTextFieldsToBeSearched.js'
|
||||||
@@ -31,7 +27,15 @@ export type ListControlsProps = {
|
|||||||
readonly beforeActions?: React.ReactNode[]
|
readonly beforeActions?: React.ReactNode[]
|
||||||
readonly collectionConfig: ClientCollectionConfig
|
readonly collectionConfig: ClientCollectionConfig
|
||||||
readonly collectionSlug: string
|
readonly collectionSlug: string
|
||||||
|
/**
|
||||||
|
* @deprecated
|
||||||
|
* These are now handled by the `ListSelection` component
|
||||||
|
*/
|
||||||
readonly disableBulkDelete?: boolean
|
readonly disableBulkDelete?: boolean
|
||||||
|
/**
|
||||||
|
* @deprecated
|
||||||
|
* These are now handled by the `ListSelection` component
|
||||||
|
*/
|
||||||
readonly disableBulkEdit?: boolean
|
readonly disableBulkEdit?: boolean
|
||||||
readonly enableColumns?: boolean
|
readonly enableColumns?: boolean
|
||||||
readonly enableSort?: boolean
|
readonly enableSort?: boolean
|
||||||
@@ -53,8 +57,6 @@ export const ListControls: React.FC<ListControlsProps> = (props) => {
|
|||||||
beforeActions,
|
beforeActions,
|
||||||
collectionConfig,
|
collectionConfig,
|
||||||
collectionSlug,
|
collectionSlug,
|
||||||
disableBulkDelete,
|
|
||||||
disableBulkEdit,
|
|
||||||
enableColumns = true,
|
enableColumns = true,
|
||||||
enableSort = false,
|
enableSort = false,
|
||||||
listMenuItems,
|
listMenuItems,
|
||||||
@@ -148,19 +150,7 @@ export const ListControls: React.FC<ListControlsProps> = (props) => {
|
|||||||
/>
|
/>
|
||||||
<div className={`${baseClass}__buttons`}>
|
<div className={`${baseClass}__buttons`}>
|
||||||
<div className={`${baseClass}__buttons-wrap`}>
|
<div className={`${baseClass}__buttons-wrap`}>
|
||||||
{!smallBreak && (
|
{!smallBreak && <React.Fragment>{beforeActions && beforeActions}</React.Fragment>}
|
||||||
<React.Fragment>
|
|
||||||
{beforeActions && beforeActions}
|
|
||||||
{!disableBulkEdit && (
|
|
||||||
<Fragment>
|
|
||||||
<EditMany collection={collectionConfig} />
|
|
||||||
<PublishMany collection={collectionConfig} />
|
|
||||||
<UnpublishMany collection={collectionConfig} />
|
|
||||||
</Fragment>
|
|
||||||
)}
|
|
||||||
{!disableBulkDelete && <DeleteMany collection={collectionConfig} />}
|
|
||||||
</React.Fragment>
|
|
||||||
)}
|
|
||||||
{enableColumns && (
|
{enableColumns && (
|
||||||
<Pill
|
<Pill
|
||||||
aria-controls={`${baseClass}-columns`}
|
aria-controls={`${baseClass}-columns`}
|
||||||
|
|||||||
@@ -1,17 +1,31 @@
|
|||||||
'use client'
|
'use client'
|
||||||
|
import type { ClientCollectionConfig } from 'payload'
|
||||||
|
|
||||||
import React, { Fragment } from 'react'
|
import React, { Fragment } from 'react'
|
||||||
|
|
||||||
import { SelectAllStatus, useSelection } from '../../providers/Selection/index.js'
|
import { SelectAllStatus, useSelection } from '../../providers/Selection/index.js'
|
||||||
import { useTranslation } from '../../providers/Translation/index.js'
|
import { useTranslation } from '../../providers/Translation/index.js'
|
||||||
|
import { DeleteMany } from '../DeleteMany/index.js'
|
||||||
|
import { EditMany } from '../EditMany/index.js'
|
||||||
|
import { PublishMany } from '../PublishMany/index.js'
|
||||||
|
import { UnpublishMany } from '../UnpublishMany/index.js'
|
||||||
import './index.scss'
|
import './index.scss'
|
||||||
|
|
||||||
const baseClass = 'list-selection'
|
const baseClass = 'list-selection'
|
||||||
|
|
||||||
export type ListSelectionProps = {
|
export type ListSelectionProps = {
|
||||||
|
collectionConfig?: ClientCollectionConfig
|
||||||
|
disableBulkDelete?: boolean
|
||||||
|
disableBulkEdit?: boolean
|
||||||
label: string
|
label: string
|
||||||
}
|
}
|
||||||
|
|
||||||
export const ListSelection: React.FC<ListSelectionProps> = ({ label }) => {
|
export const ListSelection: React.FC<ListSelectionProps> = ({
|
||||||
|
collectionConfig,
|
||||||
|
disableBulkDelete,
|
||||||
|
disableBulkEdit,
|
||||||
|
label,
|
||||||
|
}) => {
|
||||||
const { count, selectAll, toggleAll, totalDocs } = useSelection()
|
const { count, selectAll, toggleAll, totalDocs } = useSelection()
|
||||||
const { t } = useTranslation()
|
const { t } = useTranslation()
|
||||||
|
|
||||||
@@ -21,21 +35,27 @@ export const ListSelection: React.FC<ListSelectionProps> = ({ label }) => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={baseClass}>
|
<div className={baseClass}>
|
||||||
<span>{t('general:selectedCount', { count, label })}</span>
|
<span>{t('general:selectedCount', { count, label: '' })}</span>
|
||||||
{selectAll !== SelectAllStatus.AllAvailable && count < totalDocs && (
|
{selectAll !== SelectAllStatus.AllAvailable && count < totalDocs && (
|
||||||
|
<button
|
||||||
|
aria-label={t('general:selectAll', { count, label })}
|
||||||
|
className={`${baseClass}__button`}
|
||||||
|
id="select-all-across-pages"
|
||||||
|
onClick={() => toggleAll(true)}
|
||||||
|
type="button"
|
||||||
|
>
|
||||||
|
{t('general:selectAll', { count: totalDocs, label: '' })}
|
||||||
|
</button>
|
||||||
|
)}
|
||||||
|
{!disableBulkEdit && !disableBulkDelete && <span>—</span>}
|
||||||
|
{!disableBulkEdit && (
|
||||||
<Fragment>
|
<Fragment>
|
||||||
<span>—</span>
|
<EditMany collection={collectionConfig} />
|
||||||
<button
|
<PublishMany collection={collectionConfig} />
|
||||||
aria-label={t('general:selectAll', { count, label })}
|
<UnpublishMany collection={collectionConfig} />
|
||||||
className={`${baseClass}__button`}
|
|
||||||
id="select-all-across-pages"
|
|
||||||
onClick={() => toggleAll(true)}
|
|
||||||
type="button"
|
|
||||||
>
|
|
||||||
{t('general:selectAll', { count: totalDocs, label })}
|
|
||||||
</button>
|
|
||||||
</Fragment>
|
</Fragment>
|
||||||
)}
|
)}
|
||||||
|
{!disableBulkDelete && <DeleteMany collection={collectionConfig} />}
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
21
packages/ui/src/elements/PublishMany/index.scss
Normal file
21
packages/ui/src/elements/PublishMany/index.scss
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
@import '../../scss/styles.scss';
|
||||||
|
|
||||||
|
@layer payload-default {
|
||||||
|
.publish-many {
|
||||||
|
&__toggle {
|
||||||
|
font-size: inherit;
|
||||||
|
line-height: inherit;
|
||||||
|
display: inline-flex;
|
||||||
|
background: transparent;
|
||||||
|
color: var(--theme-elevation-800);
|
||||||
|
white-space: nowrap;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
border: 0;
|
||||||
|
padding: 0;
|
||||||
|
align-items: center;
|
||||||
|
cursor: pointer;
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -16,7 +16,7 @@ import { useTranslation } from '../../providers/Translation/index.js'
|
|||||||
import { requests } from '../../utilities/api.js'
|
import { requests } from '../../utilities/api.js'
|
||||||
import { parseSearchParams } from '../../utilities/parseSearchParams.js'
|
import { parseSearchParams } from '../../utilities/parseSearchParams.js'
|
||||||
import { ConfirmationModal } from '../ConfirmationModal/index.js'
|
import { ConfirmationModal } from '../ConfirmationModal/index.js'
|
||||||
import { Pill } from '../Pill/index.js'
|
import './index.scss'
|
||||||
|
|
||||||
export type PublishManyProps = {
|
export type PublishManyProps = {
|
||||||
collection: ClientCollectionConfig
|
collection: ClientCollectionConfig
|
||||||
@@ -133,14 +133,15 @@ export const PublishMany: React.FC<PublishManyProps> = (props) => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<React.Fragment>
|
<React.Fragment>
|
||||||
<Pill
|
<button
|
||||||
className={`${baseClass}__toggle`}
|
className={`${baseClass}__toggle`}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
openModal(modalSlug)
|
openModal(modalSlug)
|
||||||
}}
|
}}
|
||||||
|
type="button"
|
||||||
>
|
>
|
||||||
{t('version:publish')}
|
{t('version:publish')}
|
||||||
</Pill>
|
</button>
|
||||||
<ConfirmationModal
|
<ConfirmationModal
|
||||||
body={t('version:aboutToPublishSelection', { label: getTranslation(plural, i18n) })}
|
body={t('version:aboutToPublishSelection', { label: getTranslation(plural, i18n) })}
|
||||||
cancelLabel={t('general:cancel')}
|
cancelLabel={t('general:cancel')}
|
||||||
|
|||||||
21
packages/ui/src/elements/UnpublishMany/index.scss
Normal file
21
packages/ui/src/elements/UnpublishMany/index.scss
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
@import '../../scss/styles.scss';
|
||||||
|
|
||||||
|
@layer payload-default {
|
||||||
|
.unpublish-many {
|
||||||
|
&__toggle {
|
||||||
|
font-size: inherit;
|
||||||
|
line-height: inherit;
|
||||||
|
display: inline-flex;
|
||||||
|
background: transparent;
|
||||||
|
color: var(--theme-elevation-800);
|
||||||
|
white-space: nowrap;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
border: 0;
|
||||||
|
padding: 0;
|
||||||
|
align-items: center;
|
||||||
|
cursor: pointer;
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -16,7 +16,7 @@ import { useTranslation } from '../../providers/Translation/index.js'
|
|||||||
import { requests } from '../../utilities/api.js'
|
import { requests } from '../../utilities/api.js'
|
||||||
import { parseSearchParams } from '../../utilities/parseSearchParams.js'
|
import { parseSearchParams } from '../../utilities/parseSearchParams.js'
|
||||||
import { ConfirmationModal } from '../ConfirmationModal/index.js'
|
import { ConfirmationModal } from '../ConfirmationModal/index.js'
|
||||||
import { Pill } from '../Pill/index.js'
|
import './index.scss'
|
||||||
|
|
||||||
export type UnpublishManyProps = {
|
export type UnpublishManyProps = {
|
||||||
collection: ClientCollectionConfig
|
collection: ClientCollectionConfig
|
||||||
@@ -130,14 +130,15 @@ export const UnpublishMany: React.FC<UnpublishManyProps> = (props) => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<React.Fragment>
|
<React.Fragment>
|
||||||
<Pill
|
<button
|
||||||
className={`${baseClass}__toggle`}
|
className={`${baseClass}__toggle`}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
toggleModal(modalSlug)
|
toggleModal(modalSlug)
|
||||||
}}
|
}}
|
||||||
|
type="button"
|
||||||
>
|
>
|
||||||
{t('version:unpublish')}
|
{t('version:unpublish')}
|
||||||
</Pill>
|
</button>
|
||||||
<ConfirmationModal
|
<ConfirmationModal
|
||||||
body={t('version:aboutToUnpublishSelection', { label: getTranslation(plural, i18n) })}
|
body={t('version:aboutToUnpublishSelection', { label: getTranslation(plural, i18n) })}
|
||||||
confirmingLabel={t('version:unpublishing')}
|
confirmingLabel={t('version:unpublishing')}
|
||||||
|
|||||||
@@ -22,6 +22,8 @@ export type ListHeaderProps = {
|
|||||||
className?: string
|
className?: string
|
||||||
collectionConfig: ClientCollectionConfig
|
collectionConfig: ClientCollectionConfig
|
||||||
Description?: React.ReactNode
|
Description?: React.ReactNode
|
||||||
|
disableBulkDelete?: boolean
|
||||||
|
disableBulkEdit?: boolean
|
||||||
hasCreatePermission: boolean
|
hasCreatePermission: boolean
|
||||||
i18n: I18nClient
|
i18n: I18nClient
|
||||||
isBulkUploadEnabled: boolean
|
isBulkUploadEnabled: boolean
|
||||||
@@ -35,6 +37,8 @@ const DefaultListHeader: React.FC<ListHeaderProps> = ({
|
|||||||
className,
|
className,
|
||||||
collectionConfig,
|
collectionConfig,
|
||||||
Description,
|
Description,
|
||||||
|
disableBulkDelete,
|
||||||
|
disableBulkEdit,
|
||||||
hasCreatePermission,
|
hasCreatePermission,
|
||||||
i18n,
|
i18n,
|
||||||
isBulkUploadEnabled,
|
isBulkUploadEnabled,
|
||||||
@@ -72,7 +76,12 @@ const DefaultListHeader: React.FC<ListHeaderProps> = ({
|
|||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
{!smallBreak && (
|
{!smallBreak && (
|
||||||
<ListSelection label={getTranslation(collectionConfig?.labels?.plural, i18n)} />
|
<ListSelection
|
||||||
|
collectionConfig={collectionConfig}
|
||||||
|
disableBulkDelete={disableBulkDelete}
|
||||||
|
disableBulkEdit={disableBulkEdit}
|
||||||
|
label={getTranslation(collectionConfig?.labels?.plural, i18n)}
|
||||||
|
/>
|
||||||
)}
|
)}
|
||||||
{Description}
|
{Description}
|
||||||
</header>
|
</header>
|
||||||
|
|||||||
@@ -9,8 +9,6 @@ import React, { Fragment, useEffect, useState } from 'react'
|
|||||||
|
|
||||||
import { useBulkUpload } from '../../elements/BulkUpload/index.js'
|
import { useBulkUpload } from '../../elements/BulkUpload/index.js'
|
||||||
import { Button } from '../../elements/Button/index.js'
|
import { Button } from '../../elements/Button/index.js'
|
||||||
import { DeleteMany } from '../../elements/DeleteMany/index.js'
|
|
||||||
import { EditMany } from '../../elements/EditMany/index.js'
|
|
||||||
import { Gutter } from '../../elements/Gutter/index.js'
|
import { Gutter } from '../../elements/Gutter/index.js'
|
||||||
import { ListControls } from '../../elements/ListControls/index.js'
|
import { ListControls } from '../../elements/ListControls/index.js'
|
||||||
import { useListDrawerContext } from '../../elements/ListDrawer/Provider.js'
|
import { useListDrawerContext } from '../../elements/ListDrawer/Provider.js'
|
||||||
@@ -18,13 +16,11 @@ import { ListSelection } from '../../elements/ListSelection/index.js'
|
|||||||
import { useModal } from '../../elements/Modal/index.js'
|
import { useModal } from '../../elements/Modal/index.js'
|
||||||
import { Pagination } from '../../elements/Pagination/index.js'
|
import { Pagination } from '../../elements/Pagination/index.js'
|
||||||
import { PerPage } from '../../elements/PerPage/index.js'
|
import { PerPage } from '../../elements/PerPage/index.js'
|
||||||
import { PublishMany } from '../../elements/PublishMany/index.js'
|
|
||||||
import { RenderCustomComponent } from '../../elements/RenderCustomComponent/index.js'
|
import { RenderCustomComponent } from '../../elements/RenderCustomComponent/index.js'
|
||||||
import { SelectMany } from '../../elements/SelectMany/index.js'
|
import { SelectMany } from '../../elements/SelectMany/index.js'
|
||||||
import { useStepNav } from '../../elements/StepNav/index.js'
|
import { useStepNav } from '../../elements/StepNav/index.js'
|
||||||
import { RelationshipProvider } from '../../elements/Table/RelationshipProvider/index.js'
|
import { RelationshipProvider } from '../../elements/Table/RelationshipProvider/index.js'
|
||||||
import { TableColumnsProvider } from '../../elements/TableColumns/index.js'
|
import { TableColumnsProvider } from '../../elements/TableColumns/index.js'
|
||||||
import { UnpublishMany } from '../../elements/UnpublishMany/index.js'
|
|
||||||
import { ViewDescription } from '../../elements/ViewDescription/index.js'
|
import { ViewDescription } from '../../elements/ViewDescription/index.js'
|
||||||
import { useAuth } from '../../providers/Auth/index.js'
|
import { useAuth } from '../../providers/Auth/index.js'
|
||||||
import { useConfig } from '../../providers/Config/index.js'
|
import { useConfig } from '../../providers/Config/index.js'
|
||||||
@@ -185,6 +181,8 @@ export function DefaultListView(props: ListViewClientProps) {
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
|
disableBulkDelete={disableBulkDelete}
|
||||||
|
disableBulkEdit={disableBulkEdit}
|
||||||
hasCreatePermission={hasCreatePermission}
|
hasCreatePermission={hasCreatePermission}
|
||||||
i18n={i18n}
|
i18n={i18n}
|
||||||
isBulkUploadEnabled={isBulkUploadEnabled && !upload.hideFileInputOnCreate}
|
isBulkUploadEnabled={isBulkUploadEnabled && !upload.hideFileInputOnCreate}
|
||||||
@@ -203,8 +201,6 @@ export function DefaultListView(props: ListViewClientProps) {
|
|||||||
}
|
}
|
||||||
collectionConfig={collectionConfig}
|
collectionConfig={collectionConfig}
|
||||||
collectionSlug={collectionSlug}
|
collectionSlug={collectionSlug}
|
||||||
disableBulkDelete={disableBulkDelete}
|
|
||||||
disableBulkEdit={disableBulkEdit}
|
|
||||||
listMenuItems={listMenuItems}
|
listMenuItems={listMenuItems}
|
||||||
renderedFilters={renderedFilters}
|
renderedFilters={renderedFilters}
|
||||||
resolvedFilterOptions={resolvedFilterOptions}
|
resolvedFilterOptions={resolvedFilterOptions}
|
||||||
@@ -267,6 +263,9 @@ export function DefaultListView(props: ListViewClientProps) {
|
|||||||
{smallBreak && (
|
{smallBreak && (
|
||||||
<div className={`${baseClass}__list-selection`}>
|
<div className={`${baseClass}__list-selection`}>
|
||||||
<ListSelection
|
<ListSelection
|
||||||
|
collectionConfig={collectionConfig}
|
||||||
|
disableBulkDelete={disableBulkDelete}
|
||||||
|
disableBulkEdit={disableBulkEdit}
|
||||||
label={getTranslation(collectionConfig.labels.plural, i18n)}
|
label={getTranslation(collectionConfig.labels.plural, i18n)}
|
||||||
/>
|
/>
|
||||||
<div className={`${baseClass}__list-selection-actions`}>
|
<div className={`${baseClass}__list-selection-actions`}>
|
||||||
@@ -278,14 +277,6 @@ export function DefaultListView(props: ListViewClientProps) {
|
|||||||
]
|
]
|
||||||
: [<SelectMany key="select-many" onClick={onBulkSelect} />]
|
: [<SelectMany key="select-many" onClick={onBulkSelect} />]
|
||||||
: beforeActions}
|
: beforeActions}
|
||||||
{!disableBulkEdit && (
|
|
||||||
<Fragment>
|
|
||||||
<EditMany collection={collectionConfig} />
|
|
||||||
<PublishMany collection={collectionConfig} />
|
|
||||||
<UnpublishMany collection={collectionConfig} />
|
|
||||||
</Fragment>
|
|
||||||
)}
|
|
||||||
{!disableBulkDelete && <DeleteMany collection={collectionConfig} />}
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ import {
|
|||||||
openNav,
|
openNav,
|
||||||
saveDocAndAssert,
|
saveDocAndAssert,
|
||||||
saveDocHotkeyAndAssert,
|
saveDocHotkeyAndAssert,
|
||||||
|
// throttleTest,
|
||||||
} from '../../../helpers.js'
|
} from '../../../helpers.js'
|
||||||
import { AdminUrlUtil } from '../../../helpers/adminUrlUtil.js'
|
import { AdminUrlUtil } from '../../../helpers/adminUrlUtil.js'
|
||||||
import { initPayloadE2ENoConfig } from '../../../helpers/initPayloadE2ENoConfig.js'
|
import { initPayloadE2ENoConfig } from '../../../helpers/initPayloadE2ENoConfig.js'
|
||||||
@@ -51,7 +52,6 @@ let payload: PayloadTestSDK<Config>
|
|||||||
import { navigateToDoc } from 'helpers/e2e/navigateToDoc.js'
|
import { navigateToDoc } from 'helpers/e2e/navigateToDoc.js'
|
||||||
import { openDocControls } from 'helpers/e2e/openDocControls.js'
|
import { openDocControls } from 'helpers/e2e/openDocControls.js'
|
||||||
import path from 'path'
|
import path from 'path'
|
||||||
import { wait } from 'payload/shared'
|
|
||||||
import { fileURLToPath } from 'url'
|
import { fileURLToPath } from 'url'
|
||||||
|
|
||||||
import type { PayloadTestSDK } from '../../../helpers/sdk/index.js'
|
import type { PayloadTestSDK } from '../../../helpers/sdk/index.js'
|
||||||
@@ -101,6 +101,12 @@ describe('General', () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
|
// await throttleTest({
|
||||||
|
// page,
|
||||||
|
// context,
|
||||||
|
// delay: 'Fast 4G',
|
||||||
|
// })
|
||||||
|
|
||||||
await reInitializeDB({
|
await reInitializeDB({
|
||||||
serverURL,
|
serverURL,
|
||||||
snapshotKey: 'adminTests',
|
snapshotKey: 'adminTests',
|
||||||
@@ -735,6 +741,7 @@ describe('General', () => {
|
|||||||
|
|
||||||
await page.goto(postsUrl.list)
|
await page.goto(postsUrl.list)
|
||||||
await page.locator('#search-filter-input').fill('Post')
|
await page.locator('#search-filter-input').fill('Post')
|
||||||
|
await page.waitForURL(/search=Post/)
|
||||||
await expect(page.locator('.table table > tbody > tr')).toHaveCount(5)
|
await expect(page.locator('.table table > tbody > tr')).toHaveCount(5)
|
||||||
await page.locator('input#select-all').check()
|
await page.locator('input#select-all').check()
|
||||||
await page.locator('button#select-all-across-pages').click()
|
await page.locator('button#select-all-across-pages').click()
|
||||||
@@ -860,9 +867,12 @@ describe('General', () => {
|
|||||||
|
|
||||||
await page.goto(postsUrl.list)
|
await page.goto(postsUrl.list)
|
||||||
await page.locator('#search-filter-input').fill('Post')
|
await page.locator('#search-filter-input').fill('Post')
|
||||||
|
await page.waitForURL(/search=Post/)
|
||||||
await expect(page.locator('.table table > tbody > tr')).toHaveCount(5)
|
await expect(page.locator('.table table > tbody > tr')).toHaveCount(5)
|
||||||
|
|
||||||
await page.locator('input#select-all').check()
|
await page.locator('input#select-all').check()
|
||||||
await page.locator('button#select-all-across-pages').click()
|
await page.locator('button#select-all-across-pages').click()
|
||||||
|
|
||||||
await page.locator('.edit-many__toggle').click()
|
await page.locator('.edit-many__toggle').click()
|
||||||
await page.locator('.field-select .rs__control').click()
|
await page.locator('.field-select .rs__control').click()
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user