chore: improves edit view types (#3427)
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -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' : ''
|
||||
|
||||
@@ -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}
|
||||
|
||||
@@ -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, {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 })
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -19,7 +19,7 @@ export default buildConfigWithDefaults({
|
||||
slug: 'users',
|
||||
auth: true,
|
||||
admin: {
|
||||
useAsTitle: 'email',
|
||||
useAsTitle: 'title',
|
||||
},
|
||||
fields: [],
|
||||
},
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user