chore: improves edit view types (#3427)

This commit is contained in:
Jacob Fletcher
2023-10-03 15:41:15 -04:00
committed by GitHub
parent fdbb61fc43
commit cbc1f3b3f1
22 changed files with 709 additions and 746 deletions

View File

@@ -2,6 +2,7 @@ import React, { useCallback } from 'react'
import { useTranslation } from 'react-i18next'
import type { Translation } from '../../../../translations/type'
import type { CollectionEditViewProps } from '../types'
import { DocumentControls } from '../../elements/DocumentControls'
import { DocumentHeader } from '../../elements/DocumentHeader'
@@ -19,134 +20,127 @@ import { OperationContext } from '../../utilities/OperationProvider'
import Auth from '../collections/Edit/Auth'
import { ToggleTheme } from './ToggleTheme'
import './index.scss'
import { EditViewProps } from '../types'
const baseClass = 'account'
const DefaultAccount: React.FC<EditViewProps> = (props) => {
if ('collection' in props) {
const {
action,
apiURL,
collection,
data,
hasSavePermission,
initialState,
isLoading,
onSave: onSaveFromProps,
permissions,
} = props
const DefaultAccount: React.FC<CollectionEditViewProps> = (props) => {
const {
action,
apiURL,
collection,
data,
hasSavePermission,
initialState,
isLoading,
onSave: onSaveFromProps,
permissions,
} = props
const { auth, fields } = collection
const { auth, fields } = collection
const { refreshCookieAsync } = useAuth()
const { i18n, t } = useTranslation('authentication')
const { refreshCookieAsync } = useAuth()
const { i18n, t } = useTranslation('authentication')
const languageOptions = Object.entries(i18n.options.resources).map(([language, resource]) => ({
label: (resource as Translation).general.thisLanguage,
value: language,
}))
const languageOptions = Object.entries(i18n.options.resources).map(([language, resource]) => ({
label: (resource as Translation).general.thisLanguage,
value: language,
}))
const onSave = useCallback(async () => {
await refreshCookieAsync()
if (typeof onSaveFromProps === 'function') {
onSaveFromProps({})
}
}, [onSaveFromProps, refreshCookieAsync])
const onSave = useCallback(async () => {
await refreshCookieAsync()
if (typeof onSaveFromProps === 'function') {
onSaveFromProps({})
}
}, [onSaveFromProps, refreshCookieAsync])
const classes = [baseClass].filter(Boolean).join(' ')
const classes = [baseClass].filter(Boolean).join(' ')
return (
<React.Fragment>
<LoadingOverlayToggle name="account" show={isLoading} type="withoutNav" />
{!isLoading && (
<div className={classes}>
<OperationContext.Provider value="update">
<Form
action={action}
className={`${baseClass}__form`}
disabled={!hasSavePermission}
initialState={initialState}
method="patch"
onSuccess={onSave}
>
<DocumentHeader apiURL={apiURL} collection={collection} data={data} />
<DocumentControls
apiURL={apiURL}
collection={collection}
data={data}
hasSavePermission={hasSavePermission}
permissions={permissions}
isAccountView
return (
<React.Fragment>
<LoadingOverlayToggle name="account" show={isLoading} type="withoutNav" />
{!isLoading && (
<div className={classes}>
<OperationContext.Provider value="update">
<Form
action={action}
className={`${baseClass}__form`}
disabled={!hasSavePermission}
initialState={initialState}
method="patch"
onSuccess={onSave}
>
<DocumentHeader apiURL={apiURL} collection={collection} data={data} />
<DocumentControls
apiURL={apiURL}
collection={collection}
data={data}
hasSavePermission={hasSavePermission}
isAccountView
permissions={permissions}
/>
<div className={`${baseClass}__main`}>
<Meta
description={t('accountOfCurrentUser')}
keywords={t('account')}
title={t('account')}
/>
<div className={`${baseClass}__main`}>
<Meta
description={t('accountOfCurrentUser')}
keywords={t('account')}
title={t('account')}
/>
{!(collection.versions?.drafts && collection.versions?.drafts?.autosave) && (
<LeaveWithoutSaving />
)}
<div className={`${baseClass}__edit`}>
<Gutter className={`${baseClass}__header`}>
<Auth
collection={collection}
email={data?.email}
operation="update"
readOnly={!hasSavePermission}
useAPIKey={auth.useAPIKey}
className={`${baseClass}__auth`}
{!(collection.versions?.drafts && collection.versions?.drafts?.autosave) && (
<LeaveWithoutSaving />
)}
<div className={`${baseClass}__edit`}>
<Gutter className={`${baseClass}__header`}>
<Auth
className={`${baseClass}__auth`}
collection={collection}
email={data?.email}
operation="update"
readOnly={!hasSavePermission}
useAPIKey={auth.useAPIKey}
/>
<RenderFields
fieldSchema={fields}
fieldTypes={fieldTypes}
filter={(field) => field?.admin?.position !== 'sidebar'}
permissions={permissions.fields}
readOnly={!hasSavePermission}
/>
</Gutter>
<Gutter className={`${baseClass}__payload-settings`}>
<h3>{t('general:payloadSettings')}</h3>
<div className={`${baseClass}__language`}>
<Label htmlFor="language-select" label={t('general:language')} />
<ReactSelect
inputId="language-select"
onChange={({ value }) => i18n.changeLanguage(value)}
options={languageOptions}
value={languageOptions.find((language) => language.value === i18n.language)}
/>
</div>
<ToggleTheme />
</Gutter>
</div>
</div>
<div className={`${baseClass}__sidebar-wrap`}>
<div className={`${baseClass}__sidebar`}>
<div className={`${baseClass}__sidebar-sticky-wrap`}>
<div className={`${baseClass}__sidebar-fields`}>
<RenderFields
fieldSchema={fields}
fieldTypes={fieldTypes}
filter={(field) => field?.admin?.position !== 'sidebar'}
filter={(field) => field?.admin?.position === 'sidebar'}
permissions={permissions.fields}
readOnly={!hasSavePermission}
/>
</Gutter>
<Gutter className={`${baseClass}__payload-settings`}>
<h3>{t('general:payloadSettings')}</h3>
<div className={`${baseClass}__language`}>
<Label htmlFor="language-select" label={t('general:language')} />
<ReactSelect
inputId="language-select"
onChange={({ value }) => i18n.changeLanguage(value)}
options={languageOptions}
value={languageOptions.find(
(language) => language.value === i18n.language,
)}
/>
</div>
<ToggleTheme />
</Gutter>
</div>
</div>
<div className={`${baseClass}__sidebar-wrap`}>
<div className={`${baseClass}__sidebar`}>
<div className={`${baseClass}__sidebar-sticky-wrap`}>
<div className={`${baseClass}__sidebar-fields`}>
<RenderFields
fieldSchema={fields}
fieldTypes={fieldTypes}
filter={(field) => field?.admin?.position === 'sidebar'}
permissions={permissions.fields}
readOnly={!hasSavePermission}
/>
</div>
</div>
</div>
</div>
</Form>
</OperationContext.Provider>
</div>
)}
</React.Fragment>
)
}
return null
</div>
</Form>
</OperationContext.Provider>
</div>
)}
</React.Fragment>
)
}
export default DefaultAccount

View File

@@ -1,6 +1,8 @@
import React from 'react'
import { useTranslation } from 'react-i18next'
import type { GlobalEditViewProps } from '../types'
import { getTranslation } from '../../../../utilities/getTranslation'
import { DocumentHeader } from '../../elements/DocumentHeader'
import { FormLoadingOverlayToggle } from '../../elements/Loading'
@@ -9,67 +11,62 @@ import { OperationContext } from '../../utilities/OperationProvider'
import { GlobalRoutes } from './Routes'
import { CustomGlobalComponent } from './Routes/CustomComponent'
import './index.scss'
import { EditViewProps } from '../types'
const baseClass = 'global-edit'
const DefaultGlobalView: React.FC<
EditViewProps & {
GlobalEditViewProps & {
disableRoutes?: boolean
}
> = (props) => {
if ('global' in props) {
const {
action,
apiURL,
data,
disableRoutes,
global,
initialState,
isLoading,
onSave,
permissions,
} = props
const { i18n } = useTranslation('general')
const { i18n } = useTranslation('general')
const {
action,
apiURL,
data,
disableRoutes,
global,
initialState,
isLoading,
onSave,
permissions,
} = props
const { label } = global
const { label } = global
const hasSavePermission = permissions?.update?.permission
const hasSavePermission = permissions?.update?.permission
return (
<main className={baseClass}>
<OperationContext.Provider value="update">
<Form
action={action}
className={`${baseClass}__form`}
disabled={!hasSavePermission}
initialState={initialState}
method="post"
onSuccess={onSave}
>
<FormLoadingOverlayToggle
action="update"
loadingSuffix={getTranslation(label, i18n)}
name={`global-edit--${typeof label === 'string' ? label : label?.en}`}
/>
{!isLoading && (
<React.Fragment>
<DocumentHeader apiURL={apiURL} data={data} global={global} />
{disableRoutes ? (
<CustomGlobalComponent view="Default" {...props} />
) : (
<GlobalRoutes {...props} />
)}
</React.Fragment>
)}
</Form>
</OperationContext.Provider>
</main>
)
}
return null
return (
<main className={baseClass}>
<OperationContext.Provider value="update">
<Form
action={action}
className={`${baseClass}__form`}
disabled={!hasSavePermission}
initialState={initialState}
method="post"
onSuccess={onSave}
>
<FormLoadingOverlayToggle
action="update"
loadingSuffix={getTranslation(label, i18n)}
name={`global-edit--${typeof label === 'string' ? label : label?.en}`}
/>
{!isLoading && (
<React.Fragment>
<DocumentHeader apiURL={apiURL} data={data} global={global} />
{disableRoutes ? (
<CustomGlobalComponent view="Default" {...props} />
) : (
<GlobalRoutes {...props} />
)}
</React.Fragment>
)}
</Form>
</OperationContext.Provider>
</main>
)
}
export default DefaultGlobalView

View File

@@ -1,6 +1,8 @@
import React from 'react'
import { useTranslation } from 'react-i18next'
import type { GlobalEditViewProps } from '../../types'
import { getTranslation } from '../../../../../utilities/getTranslation'
import { DocumentControls } from '../../../elements/DocumentControls'
import { Gutter } from '../../../elements/Gutter'
@@ -10,100 +12,96 @@ import { filterFields } from '../../../forms/RenderFields/filterFields'
import { fieldTypes } from '../../../forms/field-types'
import LeaveWithoutSaving from '../../../modals/LeaveWithoutSaving'
import Meta from '../../../utilities/Meta'
import { SetStepNav } from '../../collections/Edit/SetStepNav'
import './index.scss'
import { EditViewProps } from '../../types'
const baseClass = 'global-default-edit'
export const DefaultGlobalEdit: React.FC<EditViewProps> = (props) => {
if ('global' in props) {
const { apiURL, data, global, permissions } = props
export const DefaultGlobalEdit: React.FC<GlobalEditViewProps> = (props) => {
const { i18n } = useTranslation('general')
const { i18n } = useTranslation('general')
const { apiURL, data, global, permissions } = props
const { admin: { description } = {}, fields, label } = global
const { admin: { description } = {}, fields, label } = global
const hasSavePermission = permissions?.update?.permission
const hasSavePermission = permissions?.update?.permission
const sidebarFields = filterFields({
fieldSchema: fields,
fieldTypes,
filter: (field) => field?.admin?.position === 'sidebar',
permissions: permissions.fields,
readOnly: !hasSavePermission,
})
const sidebarFields = filterFields({
fieldSchema: fields,
fieldTypes,
filter: (field) => field?.admin?.position === 'sidebar',
permissions: permissions.fields,
readOnly: !hasSavePermission,
})
const hasSidebar = sidebarFields && sidebarFields.length > 0
const hasSidebar = sidebarFields && sidebarFields.length > 0
return (
<React.Fragment>
{/* <SetStepNav collection={collection} id={id} isEditing={isEditing} /> */}
<DocumentControls
apiURL={apiURL}
data={data}
global={global}
hasSavePermission={hasSavePermission}
isEditing
permissions={permissions}
/>
<div
className={[
baseClass,
hasSidebar ? `${baseClass}--has-sidebar` : `${baseClass}--no-sidebar`,
]
.filter(Boolean)
.join(' ')}
>
<div className={`${baseClass}__main`}>
<Meta
description={getTranslation(label, i18n)}
keywords={`${getTranslation(label, i18n)}, Payload, CMS`}
title={getTranslation(label, i18n)}
return (
<React.Fragment>
<SetStepNav global={global} />
<DocumentControls
apiURL={apiURL}
data={data}
global={global}
hasSavePermission={hasSavePermission}
isEditing
permissions={permissions}
/>
<div
className={[
baseClass,
hasSidebar ? `${baseClass}--has-sidebar` : `${baseClass}--no-sidebar`,
]
.filter(Boolean)
.join(' ')}
>
<div className={`${baseClass}__main`}>
<Meta
description={getTranslation(label, i18n)}
keywords={`${getTranslation(label, i18n)}, Payload, CMS`}
title={getTranslation(label, i18n)}
/>
{!(global.versions?.drafts && global.versions?.drafts?.autosave) && (
<LeaveWithoutSaving />
)}
<Gutter className={`${baseClass}__edit`}>
<header className={`${baseClass}__header`}>
{description && (
<div className={`${baseClass}__sub-header`}>
<ViewDescription description={description} />
</div>
)}
</header>
<RenderFields
fieldSchema={fields}
fieldTypes={fieldTypes}
filter={(field) =>
!field.admin.position ||
(field.admin.position && field.admin.position !== 'sidebar')
}
permissions={permissions.fields}
readOnly={!hasSavePermission}
/>
{!(global.versions?.drafts && global.versions?.drafts?.autosave) && (
<LeaveWithoutSaving />
)}
<Gutter className={`${baseClass}__edit`}>
<header className={`${baseClass}__header`}>
{description && (
<div className={`${baseClass}__sub-header`}>
<ViewDescription description={description} />
</div>
)}
</header>
<RenderFields
fieldSchema={fields}
fieldTypes={fieldTypes}
filter={(field) =>
!field.admin.position ||
(field.admin.position && field.admin.position !== 'sidebar')
}
permissions={permissions.fields}
readOnly={!hasSavePermission}
/>
</Gutter>
</div>
{hasSidebar && (
<div className={`${baseClass}__sidebar-wrap`}>
<div className={`${baseClass}__sidebar`}>
<div className={`${baseClass}__sidebar-sticky-wrap`}>
<div className={`${baseClass}__sidebar-fields`}>
<RenderFields
fieldSchema={fields}
fieldTypes={fieldTypes}
filter={(field) => field.admin.position === 'sidebar'}
permissions={permissions.fields}
readOnly={!hasSavePermission}
/>
</div>
</Gutter>
</div>
{hasSidebar && (
<div className={`${baseClass}__sidebar-wrap`}>
<div className={`${baseClass}__sidebar`}>
<div className={`${baseClass}__sidebar-sticky-wrap`}>
<div className={`${baseClass}__sidebar-fields`}>
<RenderFields
fieldSchema={fields}
fieldTypes={fieldTypes}
filter={(field) => field.admin.position === 'sidebar'}
permissions={permissions.fields}
readOnly={!hasSavePermission}
/>
</div>
</div>
</div>
)}
</div>
</React.Fragment>
)
}
return null
</div>
)}
</div>
</React.Fragment>
)
}

View File

@@ -1,9 +1,10 @@
import React from 'react'
import type { GlobalEditViewProps } from '../../types'
import VersionView from '../../Version/Version'
import VersionsView from '../../Versions'
import { DefaultGlobalEdit } from '../Default/index'
import { EditViewProps } from '../../types'
export type globalViewType =
| 'API'
@@ -27,37 +28,33 @@ export const defaultGlobalViews: {
}
export const CustomGlobalComponent = (
args: EditViewProps & {
args: GlobalEditViewProps & {
view: globalViewType
},
) => {
if ('global' in args) {
const { global, view } = args
const { global, view } = args
const { admin: { components: { views: { Edit } = {} } = {} } = {} } = global
const { admin: { components: { views: { Edit } = {} } = {} } = {} } = global
// Overriding components may come from multiple places in the config
// Need to cascade through the hierarchy to find the correct component to render
// For example, the Edit view:
// 1. Edit?.Default
// 2. Edit?.Default?.Component
// TODO: Remove the `@ts-ignore` when a Typescript wizard arrives
// For some reason `Component` does not exist on type `Edit[view]` no matter how narrow the type is
const Component =
typeof Edit === 'object' && typeof Edit[view] === 'function'
? Edit[view]
: typeof Edit === 'object' &&
typeof Edit?.[view] === 'object' &&
// @ts-ignore
typeof Edit[view].Component === 'function'
? // @ts-ignore
Edit[view].Component
: defaultGlobalViews[view]
// Overriding components may come from multiple places in the config
// Need to cascade through the hierarchy to find the correct component to render
// For example, the Edit view:
// 1. Edit?.Default
// 2. Edit?.Default?.Component
// TODO: Remove the `@ts-ignore` when a Typescript wizard arrives
// For some reason `Component` does not exist on type `Edit[view]` no matter how narrow the type is
const Component =
typeof Edit === 'object' && typeof Edit[view] === 'function'
? Edit[view]
: typeof Edit === 'object' &&
typeof Edit?.[view] === 'object' &&
// @ts-ignore
typeof Edit[view].Component === 'function'
? // @ts-ignore
Edit[view].Component
: defaultGlobalViews[view]
if (Component) {
return <Component {...args} />
}
if (Component) {
return <Component {...args} />
}
return null
}

View File

@@ -2,74 +2,71 @@ import { lazy } from 'react'
import React from 'react'
import { Route, Switch, useRouteMatch } from 'react-router-dom'
import type { GlobalEditViewProps } from '../../types'
import { useAuth } from '../../../utilities/Auth'
import { useConfig } from '../../../utilities/Config'
import NotFound from '../../NotFound'
import { CustomGlobalComponent } from './CustomComponent'
import { globalCustomRoutes } from './custom'
import { EditViewProps } from '../../types'
// @ts-expect-error Just TypeScript being broken // TODO: Open TypeScript issue
const Unauthorized = lazy(() => import('../../Unauthorized'))
export const GlobalRoutes: React.FC<EditViewProps> = (props) => {
if ('global' in props) {
const { global, permissions } = props
export const GlobalRoutes: React.FC<GlobalEditViewProps> = (props) => {
const { global, permissions } = props
const match = useRouteMatch()
const match = useRouteMatch()
const {
routes: { admin: adminRoute },
} = useConfig()
const {
routes: { admin: adminRoute },
} = useConfig()
const { user } = useAuth()
const { user } = useAuth()
return (
<Switch>
<Route
exact
key={`${global.slug}-versions`}
path={`${adminRoute}/globals/${global.slug}/versions`}
>
{permissions?.readVersions?.permission ? (
<CustomGlobalComponent view="Versions" {...props} />
) : (
<Unauthorized />
)}
</Route>
<Route
exact
key={`${global.slug}-view-version`}
path={`${adminRoute}/globals/${global.slug}/versions/:versionID`}
>
{permissions?.readVersions?.permission ? (
<CustomGlobalComponent view="Version" {...props} />
) : (
<Unauthorized />
)}
</Route>
<Route
exact
key={`${global.slug}-live-preview`}
path={`${adminRoute}/globals/${global.slug}/preview`}
>
<CustomGlobalComponent view="LivePreview" {...props} />
</Route>
{globalCustomRoutes({
global,
match,
permissions,
user,
})}
<Route exact key={`${global.slug}-view`} path={`${adminRoute}/globals/${global.slug}`}>
<CustomGlobalComponent view="Default" {...props} />
</Route>
<Route path={`${match.url}*`}>
<NotFound marginTop="large" />
</Route>
</Switch>
)
}
return null
return (
<Switch>
<Route
exact
key={`${global.slug}-versions`}
path={`${adminRoute}/globals/${global.slug}/versions`}
>
{permissions?.readVersions?.permission ? (
<CustomGlobalComponent view="Versions" {...props} />
) : (
<Unauthorized />
)}
</Route>
<Route
exact
key={`${global.slug}-view-version`}
path={`${adminRoute}/globals/${global.slug}/versions/:versionID`}
>
{permissions?.readVersions?.permission ? (
<CustomGlobalComponent view="Version" {...props} />
) : (
<Unauthorized />
)}
</Route>
<Route
exact
key={`${global.slug}-live-preview`}
path={`${adminRoute}/globals/${global.slug}/preview`}
>
<CustomGlobalComponent view="LivePreview" {...props} />
</Route>
{globalCustomRoutes({
global,
match,
permissions,
user,
})}
<Route exact key={`${global.slug}-view`} path={`${adminRoute}/globals/${global.slug}`}>
<CustomGlobalComponent view="Default" {...props} />
</Route>
<Route path={`${match.url}*`}>
<NotFound marginTop="large" />
</Route>
</Switch>
)
}

View File

@@ -3,27 +3,25 @@ import { useTranslation } from 'react-i18next'
import { useLocation } from 'react-router-dom'
import type { Fields } from '../../forms/Form/types'
import type { GlobalEditViewProps } from '../types'
import type { IndexProps } from './types'
import usePayloadAPI from '../../../hooks/usePayloadAPI'
import { useStepNav } from '../../elements/StepNav'
import buildStateFromSchema from '../../forms/Form/buildStateFromSchema'
import { useAuth } from '../../utilities/Auth'
import { useConfig } from '../../utilities/Config'
import { useDocumentInfo } from '../../utilities/DocumentInfo'
import { EditDepthContext } from '../../utilities/EditDepth'
import { useLocale } from '../../utilities/Locale'
import { usePreferences } from '../../utilities/Preferences'
import RenderCustomComponent from '../../utilities/RenderCustomComponent'
import DefaultGlobalView from './Default'
import { EditDepthContext } from '../../utilities/EditDepth'
import { EditViewProps } from '../types'
const GlobalView: React.FC<IndexProps> = (props) => {
const { global } = props
const { state: locationState } = useLocation<{ data?: Record<string, unknown> }>()
const { code: locale } = useLocale()
const { setStepNav } = useStepNav()
const { permissions, user } = useAuth()
const [initialState, setInitialState] = useState<Fields>()
const [updatedAt, setUpdatedAt] = useState<string>()
@@ -37,12 +35,7 @@ const GlobalView: React.FC<IndexProps> = (props) => {
serverURL,
} = useConfig()
const {
admin: { components: { views: { Edit: Edit } = {} } = {} } = {},
fields,
label,
slug,
} = global
const { admin: { components: { views: { Edit: Edit } = {} } = {} } = {}, fields, slug } = global
const onSave = useCallback(
async (json) => {
@@ -71,16 +64,6 @@ const GlobalView: React.FC<IndexProps> = (props) => {
const dataToRender = locationState?.data || data
useEffect(() => {
const nav = [
{
label,
},
]
setStepNav(nav)
}, [setStepNav, label])
useEffect(() => {
const awaitInitialState = async () => {
const preferences = await getDocPreferences()
@@ -102,7 +85,7 @@ const GlobalView: React.FC<IndexProps> = (props) => {
const isLoading = !initialState || !docPermissions || isLoadingData
const componentProps: EditViewProps = {
const componentProps: GlobalEditViewProps = {
action: `${serverURL}${api}/globals/${slug}?locale=${locale}&fallback-locale=null`,
apiURL: `${serverURL}${api}/globals/${slug}?locale=${locale}${
global.versions?.drafts ? '&draft=true' : ''

View File

@@ -12,6 +12,7 @@ import { filterFields } from '../../forms/RenderFields/filterFields'
import { fieldTypes } from '../../forms/field-types'
import LeaveWithoutSaving from '../../modals/LeaveWithoutSaving'
import Meta from '../../utilities/Meta'
import { SetStepNav } from '../collections/Edit/SetStepNav'
import { LivePreview } from './Preview'
import './index.scss'
import { usePopupWindow } from './usePopupWindow'
@@ -71,6 +72,7 @@ export const LivePreviewView: React.FC<EditViewProps> = (props) => {
return (
<Fragment>
<SetStepNav collection={collection} global={global} id={id} isEditing={isEditing} />
<DocumentControls
apiURL={apiURL}
collection={collection}

View File

@@ -85,7 +85,7 @@ const VersionView: React.FC<Props> = ({ collection, global }) => {
? originalDocFetchURL
: `${compareBaseURL}/${compareValue.value}`
const [{ data: doc, isError, isLoading: isLoadingData }] = usePayloadAPI(versionFetchURL, {
const [{ data: doc, isError }] = usePayloadAPI(versionFetchURL, {
initialParams: { depth: 1, locale: '*' },
})
const [{ data: publishedDoc }] = usePayloadAPI(originalDocFetchURL, {

View File

@@ -1,6 +1,8 @@
import React, { useCallback } from 'react'
import { useTranslation } from 'react-i18next'
import type { CollectionEditViewProps } from '../../types'
import { getTranslation } from '../../../../../utilities/getTranslation'
import { DocumentHeader } from '../../../elements/DocumentHeader'
import { FormLoadingOverlayToggle } from '../../../elements/Loading'
@@ -9,104 +11,99 @@ import { useAuth } from '../../../utilities/Auth'
import { OperationContext } from '../../../utilities/OperationProvider'
import { CollectionRoutes } from './Routes'
import { CustomCollectionComponent } from './Routes/CustomComponent'
import { EditViewProps } from '../../types'
import './index.scss'
const baseClass = 'collection-edit'
const DefaultEditView: React.FC<
EditViewProps & {
disableRoutes?: boolean
CollectionEditViewProps & {
customHeader?: React.ReactNode
disableRoutes?: boolean
}
> = (props) => {
const { i18n } = useTranslation('general')
const { refreshCookieAsync, user } = useAuth()
if ('collection' in props) {
const {
id,
action,
apiURL,
collection,
customHeader,
data,
disableRoutes,
hasSavePermission,
internalState,
isEditing,
isLoading,
onSave: onSaveFromProps,
} = props
const {
id,
action,
apiURL,
collection,
customHeader,
data,
disableRoutes,
hasSavePermission,
internalState,
isEditing,
isLoading,
onSave: onSaveFromProps,
} = props
const { auth } = collection
const { auth } = collection
const classes = [baseClass, isEditing && `${baseClass}--is-editing`].filter(Boolean).join(' ')
const classes = [baseClass, isEditing && `${baseClass}--is-editing`].filter(Boolean).join(' ')
const onSave = useCallback(
async (json) => {
if (auth && id === user.id) {
await refreshCookieAsync()
}
const onSave = useCallback(
async (json) => {
if (auth && id === user.id) {
await refreshCookieAsync()
}
if (typeof onSaveFromProps === 'function') {
onSaveFromProps({
...json,
operation: id ? 'update' : 'create',
})
}
},
[id, onSaveFromProps, auth, user, refreshCookieAsync],
)
if (typeof onSaveFromProps === 'function') {
onSaveFromProps({
...json,
operation: id ? 'update' : 'create',
})
}
},
[id, onSaveFromProps, auth, user, refreshCookieAsync],
)
const operation = isEditing ? 'update' : 'create'
const operation = isEditing ? 'update' : 'create'
return (
<main className={classes}>
<OperationContext.Provider value={operation}>
<Form
action={action}
className={`${baseClass}__form`}
disabled={!hasSavePermission}
initialState={internalState}
method={id ? 'patch' : 'post'}
onSuccess={onSave}
>
<FormLoadingOverlayToggle
action={isLoading ? 'loading' : operation}
formIsLoading={isLoading}
loadingSuffix={getTranslation(collection.labels.singular, i18n)}
name={`collection-edit--${
typeof collection?.labels?.singular === 'string'
? collection.labels.singular
: 'document'
}`}
type="withoutNav"
/>
{!isLoading && (
<React.Fragment>
<DocumentHeader
apiURL={apiURL}
collection={collection}
customHeader={customHeader}
data={data}
id={id}
isEditing={isEditing}
/>
{disableRoutes ? (
<CustomCollectionComponent view="Default" {...props} />
) : (
<CollectionRoutes {...props} />
)}
</React.Fragment>
)}
</Form>
</OperationContext.Provider>
</main>
)
}
return null
return (
<main className={classes}>
<OperationContext.Provider value={operation}>
<Form
action={action}
className={`${baseClass}__form`}
disabled={!hasSavePermission}
initialState={internalState}
method={id ? 'patch' : 'post'}
onSuccess={onSave}
>
<FormLoadingOverlayToggle
action={isLoading ? 'loading' : operation}
formIsLoading={isLoading}
loadingSuffix={getTranslation(collection.labels.singular, i18n)}
name={`collection-edit--${
typeof collection?.labels?.singular === 'string'
? collection.labels.singular
: 'document'
}`}
type="withoutNav"
/>
{!isLoading && (
<React.Fragment>
<DocumentHeader
apiURL={apiURL}
collection={collection}
customHeader={customHeader}
data={data}
id={id}
isEditing={isEditing}
/>
{disableRoutes ? (
<CustomCollectionComponent view="Default" {...props} />
) : (
<CollectionRoutes {...props} />
)}
</React.Fragment>
)}
</Form>
</OperationContext.Provider>
</main>
)
}
export default DefaultEditView

View File

@@ -1,6 +1,8 @@
import React, { Fragment } from 'react'
import { useTranslation } from 'react-i18next'
import type { CollectionEditViewProps } from '../../../types'
import { getTranslation } from '../../../../../../utilities/getTranslation'
import { DocumentControls } from '../../../../elements/DocumentControls'
import { Gutter } from '../../../../elements/Gutter'
@@ -13,115 +15,110 @@ import Auth from '../Auth'
import { SetStepNav } from '../SetStepNav'
import Upload from '../Upload'
import './index.scss'
import { EditViewProps } from '../../../types'
const baseClass = 'collection-default-edit'
export const DefaultCollectionEdit: React.FC<EditViewProps> = (props) => {
if ('collection' in props) {
const { i18n, t } = useTranslation('general')
export const DefaultCollectionEdit: React.FC<CollectionEditViewProps> = (props) => {
const { i18n, t } = useTranslation('general')
const {
id,
apiURL,
collection,
data,
disableActions,
disableLeaveWithoutSaving,
hasSavePermission,
internalState,
isEditing,
permissions,
} = props
const {
id,
apiURL,
collection,
data,
disableActions,
disableLeaveWithoutSaving,
hasSavePermission,
internalState,
isEditing,
permissions,
} = props
const { auth, fields, upload } = collection
const { auth, fields, upload } = collection
const operation = isEditing ? 'update' : 'create'
const operation = isEditing ? 'update' : 'create'
const sidebarFields = filterFields({
fieldSchema: fields,
fieldTypes,
filter: (field) => field?.admin?.position === 'sidebar',
permissions: permissions.fields,
readOnly: !hasSavePermission,
})
const sidebarFields = filterFields({
fieldSchema: fields,
fieldTypes,
filter: (field) => field?.admin?.position === 'sidebar',
permissions: permissions.fields,
readOnly: !hasSavePermission,
})
const hasSidebar = sidebarFields && sidebarFields.length > 0
const hasSidebar = sidebarFields && sidebarFields.length > 0
return (
<Fragment>
<SetStepNav collection={collection} id={id} isEditing={isEditing} />
<DocumentControls
apiURL={apiURL}
collection={collection}
data={data}
disableActions={disableActions}
hasSavePermission={hasSavePermission}
id={id}
isEditing={isEditing}
permissions={permissions}
/>
<div
className={[
baseClass,
hasSidebar ? `${baseClass}--has-sidebar` : `${baseClass}--no-sidebar`,
]
.filter(Boolean)
.join(' ')}
>
<div className={`${baseClass}__main`}>
<Meta
description={`${isEditing ? t('editing') : t('creating')} - ${getTranslation(
collection.labels.singular,
i18n,
)}`}
keywords={`${getTranslation(collection.labels.singular, i18n)}, Payload, CMS`}
title={`${isEditing ? t('editing') : t('creating')} - ${getTranslation(
collection.labels.singular,
i18n,
)}`}
/>
{!(collection.versions?.drafts && collection.versions?.drafts?.autosave) &&
!disableLeaveWithoutSaving && <LeaveWithoutSaving />}
<Gutter className={`${baseClass}__edit`}>
{auth && (
<Auth
className={`${baseClass}__auth`}
collection={collection}
email={data?.email}
operation={operation}
readOnly={!hasSavePermission}
requirePassword={!isEditing}
useAPIKey={auth.useAPIKey}
verify={auth.verify}
/>
)}
{upload && (
<Upload collection={collection} data={data} internalState={internalState} />
)}
<RenderFields
fieldSchema={fields}
fieldTypes={fieldTypes}
filter={(field) => !field?.admin?.position || field?.admin?.position !== 'sidebar'}
permissions={permissions.fields}
return (
<Fragment>
<SetStepNav collection={collection} id={id} isEditing={isEditing} />
<DocumentControls
apiURL={apiURL}
collection={collection}
data={data}
disableActions={disableActions}
hasSavePermission={hasSavePermission}
id={id}
isEditing={isEditing}
permissions={permissions}
/>
<div
className={[
baseClass,
hasSidebar ? `${baseClass}--has-sidebar` : `${baseClass}--no-sidebar`,
]
.filter(Boolean)
.join(' ')}
>
<div className={`${baseClass}__main`}>
<Meta
description={`${isEditing ? t('editing') : t('creating')} - ${getTranslation(
collection.labels.singular,
i18n,
)}`}
keywords={`${getTranslation(collection.labels.singular, i18n)}, Payload, CMS`}
title={`${isEditing ? t('editing') : t('creating')} - ${getTranslation(
collection.labels.singular,
i18n,
)}`}
/>
{!(collection.versions?.drafts && collection.versions?.drafts?.autosave) &&
!disableLeaveWithoutSaving && <LeaveWithoutSaving />}
<Gutter className={`${baseClass}__edit`}>
{auth && (
<Auth
className={`${baseClass}__auth`}
collection={collection}
email={data?.email}
operation={operation}
readOnly={!hasSavePermission}
className={`${baseClass}__fields`}
requirePassword={!isEditing}
useAPIKey={auth.useAPIKey}
verify={auth.verify}
/>
</Gutter>
</div>
{hasSidebar && (
<div className={`${baseClass}__sidebar-wrap`}>
<div className={`${baseClass}__sidebar`}>
<div className={`${baseClass}__sidebar-sticky-wrap`}>
<div className={`${baseClass}__sidebar-fields`}>
<RenderFields fieldTypes={fieldTypes} fields={sidebarFields} />
</div>
)}
{upload && <Upload collection={collection} data={data} internalState={internalState} />}
<RenderFields
className={`${baseClass}__fields`}
fieldSchema={fields}
fieldTypes={fieldTypes}
filter={(field) => !field?.admin?.position || field?.admin?.position !== 'sidebar'}
permissions={permissions.fields}
readOnly={!hasSavePermission}
/>
</Gutter>
</div>
{hasSidebar && (
<div className={`${baseClass}__sidebar-wrap`}>
<div className={`${baseClass}__sidebar`}>
<div className={`${baseClass}__sidebar-sticky-wrap`}>
<div className={`${baseClass}__sidebar-fields`}>
<RenderFields fieldTypes={fieldTypes} fields={sidebarFields} />
</div>
</div>
</div>
)}
</div>
</Fragment>
)
}
</div>
)}
</div>
</Fragment>
)
}

View File

@@ -1,12 +1,12 @@
import React from 'react'
import type { EditViewProps } from '../../../types'
import type { CollectionEditViewProps } from '../../../types'
import { LivePreviewView } from '../../../LivePreview'
import { QueryInspector } from '../../../RestAPI'
import VersionView from '../../../Version/Version'
import VersionsView from '../../../Versions'
import { DefaultCollectionEdit } from '../Default/index'
import { LivePreviewView } from '../../../LivePreview'
export type collectionViewType =
| 'API'
@@ -30,37 +30,33 @@ export const defaultCollectionViews: {
}
export const CustomCollectionComponent = (
args: EditViewProps & {
args: CollectionEditViewProps & {
view: collectionViewType
},
) => {
if ('collection' in args) {
const { collection, view } = args
const { collection, view } = args
const { admin: { components: { views: { Edit } = {} } = {} } = {} } = collection
const { admin: { components: { views: { Edit } = {} } = {} } = {} } = collection
// Overriding components may come from multiple places in the config
// Need to cascade through the hierarchy to find the correct component to render
// For example, the Edit view:
// 1. Edit?.Default
// 2. Edit?.Default?.Component
// TODO: Remove the `@ts-ignore` when a Typescript wizard arrives
// For some reason `Component` does not exist on type `Edit[view]` no matter how narrow the type is
const Component =
typeof Edit === 'object' && typeof Edit[view] === 'function'
? Edit[view]
: typeof Edit === 'object' &&
typeof Edit?.[view] === 'object' &&
// @ts-ignore
typeof Edit[view].Component === 'function'
? // @ts-ignore
Edit[view].Component
: defaultCollectionViews[view]
// Overriding components may come from multiple places in the config
// Need to cascade through the hierarchy to find the correct component to render
// For example, the Edit view:
// 1. Edit?.Default
// 2. Edit?.Default?.Component
// TODO: Remove the `@ts-ignore` when a Typescript wizard arrives
// For some reason `Component` does not exist on type `Edit[view]` no matter how narrow the type is
const Component =
typeof Edit === 'object' && typeof Edit[view] === 'function'
? Edit[view]
: typeof Edit === 'object' &&
typeof Edit?.[view] === 'object' &&
// @ts-ignore
typeof Edit[view].Component === 'function'
? // @ts-ignore
Edit[view].Component
: defaultCollectionViews[view]
if (Component) {
return <Component {...args} />
}
if (Component) {
return <Component {...args} />
}
return null
}

View File

@@ -2,7 +2,7 @@ import { lazy } from 'react'
import React from 'react'
import { Route, Switch, useRouteMatch } from 'react-router-dom'
import type { EditViewProps } from '../../../types'
import type { CollectionEditViewProps } from '../../../types'
import { useAuth } from '../../../../utilities/Auth'
import { useConfig } from '../../../../utilities/Config'
@@ -13,77 +13,71 @@ import { collectionCustomRoutes } from './custom'
// @ts-expect-error Just TypeScript being broken // TODO: Open TypeScript issue
const Unauthorized = lazy(() => import('../../../Unauthorized'))
export const CollectionRoutes: React.FC<EditViewProps> = (props) => {
if ('collection' in props) {
const { collection, permissions } = props
export const CollectionRoutes: React.FC<CollectionEditViewProps> = (props) => {
const { collection, permissions } = props
const match = useRouteMatch()
const match = useRouteMatch()
const {
routes: { admin: adminRoute },
} = useConfig()
const {
routes: { admin: adminRoute },
} = useConfig()
const { user } = useAuth()
const { user } = useAuth()
return (
<Switch>
<Route
exact
key={`${collection.slug}-versions`}
path={`${adminRoute}/collections/${collection.slug}/:id/versions`}
>
{permissions?.readVersions?.permission ? (
<CustomCollectionComponent view="Versions" {...props} />
) : (
<Unauthorized />
)}
</Route>
<Route
exact
key={`${collection.slug}-api`}
path={`${adminRoute}/collections/${collection.slug}/:id/api`}
>
{permissions?.read ? (
<CustomCollectionComponent view="API" {...props} />
) : (
<Unauthorized />
)}
</Route>
<Route
exact
key={`${collection.slug}-view-version`}
path={`${adminRoute}/collections/${collection.slug}/:id/versions/:versionID`}
>
{permissions?.readVersions?.permission ? (
<CustomCollectionComponent view="Version" {...props} />
) : (
<Unauthorized />
)}
</Route>
<Route
exact
key={`${collection.slug}-live-preview`}
path={`${adminRoute}/collections/${collection.slug}/:id/preview`}
>
<CustomCollectionComponent view="LivePreview" {...props} />
</Route>
{collectionCustomRoutes({
collection,
match,
permissions,
user,
})}
<Route
exact
key={`${collection.slug}-view`}
path={`${adminRoute}/collections/${collection.slug}/:id`}
>
<CustomCollectionComponent view="Default" {...props} />
</Route>
<Route path={`${match.url}*`}>
<NotFound marginTop="large" />
</Route>
</Switch>
)
}
return (
<Switch>
<Route
exact
key={`${collection.slug}-versions`}
path={`${adminRoute}/collections/${collection.slug}/:id/versions`}
>
{permissions?.readVersions?.permission ? (
<CustomCollectionComponent view="Versions" {...props} />
) : (
<Unauthorized />
)}
</Route>
<Route
exact
key={`${collection.slug}-api`}
path={`${adminRoute}/collections/${collection.slug}/:id/api`}
>
{permissions?.read ? <CustomCollectionComponent view="API" {...props} /> : <Unauthorized />}
</Route>
<Route
exact
key={`${collection.slug}-view-version`}
path={`${adminRoute}/collections/${collection.slug}/:id/versions/:versionID`}
>
{permissions?.readVersions?.permission ? (
<CustomCollectionComponent view="Version" {...props} />
) : (
<Unauthorized />
)}
</Route>
<Route
exact
key={`${collection.slug}-live-preview`}
path={`${adminRoute}/collections/${collection.slug}/:id/preview`}
>
<CustomCollectionComponent view="LivePreview" {...props} />
</Route>
{collectionCustomRoutes({
collection,
match,
permissions,
user,
})}
<Route
exact
key={`${collection.slug}-view`}
path={`${adminRoute}/collections/${collection.slug}/:id`}
>
<CustomCollectionComponent view="Default" {...props} />
</Route>
<Route path={`${match.url}*`}>
<NotFound marginTop="large" />
</Route>
</Switch>
)
}

View File

@@ -2,6 +2,7 @@ import { useEffect } from 'react'
import { useTranslation } from 'react-i18next'
import type { SanitizedCollectionConfig } from '../../../../../collections/config/types'
import type { SanitizedGlobalConfig } from '../../../../../exports/types'
import type { StepNavItem } from '../../../elements/StepNav/types'
import { getTranslation } from '../../../../../utilities/getTranslation'
@@ -9,45 +10,96 @@ import useTitle from '../../../../hooks/useTitle'
import { useStepNav } from '../../../elements/StepNav'
import { useConfig } from '../../../utilities/Config'
export const SetStepNav: React.FC<{
collection: SanitizedCollectionConfig
id: string
isEditing: boolean
}> = ({ id, collection, isEditing }) => {
const {
admin: { useAsTitle },
labels: { plural: pluralLabel },
slug,
} = collection
export const SetStepNav: React.FC<
| {
collection: SanitizedCollectionConfig
id: string
isEditing: boolean
}
| {
global: SanitizedGlobalConfig
}
> = (props) => {
let collection: SanitizedCollectionConfig | undefined
let global: SanitizedGlobalConfig | undefined
let useAsTitle: string | undefined
let pluralLabel: SanitizedCollectionConfig['labels']['plural']
let slug: string
let isEditing = false
let id: string | undefined
// This only applies to collections
const title = useTitle(collection)
if ('collection' in props) {
const {
id: idFromProps,
collection: collectionFromProps,
isEditing: isEditingFromProps,
} = props
collection = collectionFromProps
useAsTitle = collection.admin.useAsTitle
pluralLabel = collection.labels.plural
slug = collection.slug
isEditing = isEditingFromProps
id = idFromProps
}
if ('global' in props) {
const { global: globalFromProps } = props
global = globalFromProps
slug = globalFromProps?.slug
}
const { setStepNav } = useStepNav()
const { i18n, t } = useTranslation('general')
const {
routes: { admin },
} = useConfig()
const title = useTitle(collection)
useEffect(() => {
const nav: StepNavItem[] = [
{
const nav: StepNavItem[] = []
if (collection) {
nav.push({
label: getTranslation(pluralLabel, i18n),
url: `${admin}/collections/${slug}`,
},
]
if (isEditing) {
nav.push({
label: useAsTitle && useAsTitle !== 'id' ? title || `[${t('untitled')}]` : id,
})
} else {
if (isEditing) {
nav.push({
label: useAsTitle && useAsTitle !== 'id' ? title || `[${t('untitled')}]` : id,
})
} else {
nav.push({
label: t('createNew'),
})
}
} else if (global) {
nav.push({
label: t('createNew'),
label: getTranslation(global.label, i18n),
url: `${admin}/globals/${slug}`,
})
}
setStepNav(nav)
}, [setStepNav, isEditing, pluralLabel, id, slug, useAsTitle, admin, t, i18n, title])
}, [
setStepNav,
isEditing,
pluralLabel,
id,
slug,
useAsTitle,
admin,
t,
i18n,
title,
global,
collection,
])
return null
}

View File

@@ -4,6 +4,7 @@ import { useHistory, useRouteMatch } from 'react-router-dom'
import type { CollectionPermission } from '../../../../../auth'
import type { Fields } from '../../../forms/Form/types'
import type { CollectionEditViewProps } from '../../types'
import type { IndexProps } from './types'
import usePayloadAPI from '../../../../hooks/usePayloadAPI'
@@ -17,7 +18,6 @@ import RenderCustomComponent from '../../../utilities/RenderCustomComponent'
import NotFound from '../../NotFound'
import DefaultEdit from './Default'
import formatFields from './formatFields'
import { EditViewProps } from '../../types'
const EditView: React.FC<IndexProps> = (props) => {
const { collection: incomingCollection, isEditing } = props
@@ -125,7 +125,7 @@ const EditView: React.FC<IndexProps> = (props) => {
const isLoading = !internalState || !docPermissions || isLoadingData
const componentProps: EditViewProps = {
const componentProps: CollectionEditViewProps = {
id,
action,
apiURL,

View File

@@ -5,24 +5,25 @@ import type {
SanitizedGlobalConfig,
} from '../../../exports/types'
export type EditViewProps = (
| {
collection: SanitizedCollectionConfig
disableActions?: boolean
disableLeaveWithoutSaving?: boolean
hasSavePermission: boolean
id: string
initialState?: Fields
internalState: Fields
isEditing: boolean
permissions: CollectionPermission
}
| {
global: SanitizedGlobalConfig
initialState: Fields
permissions: GlobalPermission
}
) & {
export type CollectionEditViewProps = BaseEditViewProps & {
collection: SanitizedCollectionConfig
disableActions?: boolean
disableLeaveWithoutSaving?: boolean
hasSavePermission: boolean
id: string
initialState?: Fields
internalState: Fields
isEditing: boolean
permissions: CollectionPermission
}
export type GlobalEditViewProps = BaseEditViewProps & {
global: SanitizedGlobalConfig
initialState: Fields
permissions: GlobalPermission
}
export type BaseEditViewProps = {
action: string
apiURL: string
canAccessAdmin: boolean
@@ -32,3 +33,5 @@ export type EditViewProps = (
updatedAt: string
user: User
}
export type EditViewProps = CollectionEditViewProps | GlobalEditViewProps

View File

@@ -52,11 +52,20 @@ export const formatUseAsTitle = (args: {
return title
}
const useTitle = (collection: SanitizedCollectionConfig): string => {
// Keep `collection` optional so that component do need to worry about conditionally rendering hooks
// This is so that components which take both `collection` and `global` props can use this hook
const useTitle = (collection?: SanitizedCollectionConfig): string => {
const { i18n } = useTranslation()
const field = useFormFields(([formFields]) => formFields[collection?.admin?.useAsTitle])
const field = useFormFields(([formFields]) => {
if (!collection) return
return formFields[collection?.admin?.useAsTitle]
})
const config = useConfig()
if (!collection) return ''
return formatUseAsTitle({ collection, config, field, i18n })
}

View File

@@ -13,7 +13,7 @@ import type { InlineConfig } from 'vite'
import type { DocumentTab } from '../admin/components/elements/DocumentHeader/Tabs/types'
import type { RichTextAdapter } from '../admin/components/forms/field-types/RichText/types'
import type { EditViewProps } from '../admin/components/views/types'
import type { CollectionEditViewProps, GlobalEditViewProps } from '../admin/components/views/types'
import type { User } from '../auth/types'
import type { PayloadBundler } from '../bundlers/types'
import type {
@@ -241,7 +241,7 @@ export type EditViewConfig = {
path: string
}
export type EditViewComponent = React.ComponentType<EditViewProps>
export type EditViewComponent = React.ComponentType<CollectionEditViewProps | GlobalEditViewProps>
export type EditView = EditViewComponent | EditViewConfig

View File

@@ -1,9 +1,10 @@
import React, { Fragment, useEffect } from 'react'
import { Redirect } from 'react-router-dom'
import type { EditViewComponent } from '../../../../../packages/payload/src/config/types'
import { useStepNav } from '../../../../../packages/payload/src/admin/components/elements/StepNav'
import { useConfig } from '../../../../../packages/payload/src/admin/components/utilities/Config'
import { EditViewComponent } from '../../../../../packages/payload/src/config/types'
const CustomDefaultView: EditViewComponent = ({
canAccessAdmin,

View File

@@ -1,9 +1,10 @@
import React, { Fragment, useEffect } from 'react'
import { Redirect } from 'react-router-dom'
import type { EditViewComponent } from '../../../../../packages/payload/src/config/types'
import { useStepNav } from '../../../../../packages/payload/src/admin/components/elements/StepNav'
import { useConfig } from '../../../../../packages/payload/src/admin/components/utilities/Config'
import { EditViewComponent } from '../../../../../packages/payload/src/config/types'
const CustomEditView: EditViewComponent = ({
canAccessAdmin,

View File

@@ -1,9 +1,10 @@
import React, { Fragment, useEffect } from 'react'
import { Redirect } from 'react-router-dom'
import type { EditViewComponent } from '../../../../../packages/payload/src/config/types'
import { useStepNav } from '../../../../../packages/payload/src/admin/components/elements/StepNav'
import { useConfig } from '../../../../../packages/payload/src/admin/components/utilities/Config'
import { EditViewComponent } from '../../../../../packages/payload/src/config/types'
const CustomVersionsView: EditViewComponent = ({
canAccessAdmin,

View File

@@ -19,7 +19,7 @@ export default buildConfigWithDefaults({
slug: 'users',
auth: true,
admin: {
useAsTitle: 'email',
useAsTitle: 'title',
},
fields: [],
},

View File

@@ -9,21 +9,11 @@
export interface Config {
collections: {
users: User
'hidden-collection': HiddenCollection
posts: Post
'group-one-collection-ones': GroupOneCollectionOne
'group-one-collection-twos': GroupOneCollectionTwo
'group-two-collection-ones': GroupTwoCollectionOne
'group-two-collection-twos': GroupTwoCollectionTwo
pages: Page
'payload-preferences': PayloadPreference
'payload-migrations': PayloadMigration
}
globals: {
'hidden-global': HiddenGlobal
global: Global
'group-globals-one': GroupGlobalsOne
'group-globals-two': GroupGlobalsTwo
}
globals: {}
}
export interface User {
id: string
@@ -38,52 +28,19 @@ export interface User {
lockUntil?: string
password?: string
}
export interface HiddenCollection {
export interface Page {
id: string
title?: string
updatedAt: string
createdAt: string
}
export interface Post {
id: string
title?: string
description?: string
number?: number
richText?: {
[k: string]: unknown
}[]
updatedAt: string
createdAt: string
}
export interface GroupOneCollectionOne {
id: string
title?: string
updatedAt: string
createdAt: string
}
export interface GroupOneCollectionTwo {
id: string
title?: string
updatedAt: string
createdAt: string
}
export interface GroupTwoCollectionOne {
id: string
title?: string
updatedAt: string
createdAt: string
}
export interface GroupTwoCollectionTwo {
id: string
title?: string
title: string
description: string
slug: string
updatedAt: string
createdAt: string
}
export interface PayloadPreference {
id: string
user: {
value: string | User
relationTo: 'users'
value: string | User
}
key?: string
value?:
@@ -114,27 +71,14 @@ export interface PayloadMigration {
updatedAt: string
createdAt: string
}
export interface HiddenGlobal {
id: string
title?: string
updatedAt?: string
createdAt?: string
}
export interface Global {
id: string
title?: string
updatedAt?: string
createdAt?: string
}
export interface GroupGlobalsOne {
id: string
title?: string
updatedAt?: string
createdAt?: string
}
export interface GroupGlobalsTwo {
id: string
title?: string
updatedAt?: string
createdAt?: string
declare module 'payload' {
export interface GeneratedTypes {
collections: {
users: User
pages: Page
'payload-preferences': PayloadPreference
'payload-migrations': PayloadMigration
}
}
}