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 { useTranslation } from 'react-i18next'
|
||||||
|
|
||||||
import type { Translation } from '../../../../translations/type'
|
import type { Translation } from '../../../../translations/type'
|
||||||
|
import type { CollectionEditViewProps } from '../types'
|
||||||
|
|
||||||
import { DocumentControls } from '../../elements/DocumentControls'
|
import { DocumentControls } from '../../elements/DocumentControls'
|
||||||
import { DocumentHeader } from '../../elements/DocumentHeader'
|
import { DocumentHeader } from '../../elements/DocumentHeader'
|
||||||
@@ -19,134 +20,127 @@ import { OperationContext } from '../../utilities/OperationProvider'
|
|||||||
import Auth from '../collections/Edit/Auth'
|
import Auth from '../collections/Edit/Auth'
|
||||||
import { ToggleTheme } from './ToggleTheme'
|
import { ToggleTheme } from './ToggleTheme'
|
||||||
import './index.scss'
|
import './index.scss'
|
||||||
import { EditViewProps } from '../types'
|
|
||||||
|
|
||||||
const baseClass = 'account'
|
const baseClass = 'account'
|
||||||
|
|
||||||
const DefaultAccount: React.FC<EditViewProps> = (props) => {
|
const DefaultAccount: React.FC<CollectionEditViewProps> = (props) => {
|
||||||
if ('collection' in props) {
|
const {
|
||||||
const {
|
action,
|
||||||
action,
|
apiURL,
|
||||||
apiURL,
|
collection,
|
||||||
collection,
|
data,
|
||||||
data,
|
hasSavePermission,
|
||||||
hasSavePermission,
|
initialState,
|
||||||
initialState,
|
isLoading,
|
||||||
isLoading,
|
onSave: onSaveFromProps,
|
||||||
onSave: onSaveFromProps,
|
permissions,
|
||||||
permissions,
|
} = props
|
||||||
} = props
|
|
||||||
|
|
||||||
const { auth, fields } = collection
|
const { auth, fields } = collection
|
||||||
|
|
||||||
const { refreshCookieAsync } = useAuth()
|
const { refreshCookieAsync } = useAuth()
|
||||||
const { i18n, t } = useTranslation('authentication')
|
const { i18n, t } = useTranslation('authentication')
|
||||||
|
|
||||||
const languageOptions = Object.entries(i18n.options.resources).map(([language, resource]) => ({
|
const languageOptions = Object.entries(i18n.options.resources).map(([language, resource]) => ({
|
||||||
label: (resource as Translation).general.thisLanguage,
|
label: (resource as Translation).general.thisLanguage,
|
||||||
value: language,
|
value: language,
|
||||||
}))
|
}))
|
||||||
|
|
||||||
const onSave = useCallback(async () => {
|
const onSave = useCallback(async () => {
|
||||||
await refreshCookieAsync()
|
await refreshCookieAsync()
|
||||||
if (typeof onSaveFromProps === 'function') {
|
if (typeof onSaveFromProps === 'function') {
|
||||||
onSaveFromProps({})
|
onSaveFromProps({})
|
||||||
}
|
}
|
||||||
}, [onSaveFromProps, refreshCookieAsync])
|
}, [onSaveFromProps, refreshCookieAsync])
|
||||||
|
|
||||||
const classes = [baseClass].filter(Boolean).join(' ')
|
const classes = [baseClass].filter(Boolean).join(' ')
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<React.Fragment>
|
<React.Fragment>
|
||||||
<LoadingOverlayToggle name="account" show={isLoading} type="withoutNav" />
|
<LoadingOverlayToggle name="account" show={isLoading} type="withoutNav" />
|
||||||
{!isLoading && (
|
{!isLoading && (
|
||||||
<div className={classes}>
|
<div className={classes}>
|
||||||
<OperationContext.Provider value="update">
|
<OperationContext.Provider value="update">
|
||||||
<Form
|
<Form
|
||||||
action={action}
|
action={action}
|
||||||
className={`${baseClass}__form`}
|
className={`${baseClass}__form`}
|
||||||
disabled={!hasSavePermission}
|
disabled={!hasSavePermission}
|
||||||
initialState={initialState}
|
initialState={initialState}
|
||||||
method="patch"
|
method="patch"
|
||||||
onSuccess={onSave}
|
onSuccess={onSave}
|
||||||
>
|
>
|
||||||
<DocumentHeader apiURL={apiURL} collection={collection} data={data} />
|
<DocumentHeader apiURL={apiURL} collection={collection} data={data} />
|
||||||
<DocumentControls
|
<DocumentControls
|
||||||
apiURL={apiURL}
|
apiURL={apiURL}
|
||||||
collection={collection}
|
collection={collection}
|
||||||
data={data}
|
data={data}
|
||||||
hasSavePermission={hasSavePermission}
|
hasSavePermission={hasSavePermission}
|
||||||
permissions={permissions}
|
isAccountView
|
||||||
isAccountView
|
permissions={permissions}
|
||||||
|
/>
|
||||||
|
<div className={`${baseClass}__main`}>
|
||||||
|
<Meta
|
||||||
|
description={t('accountOfCurrentUser')}
|
||||||
|
keywords={t('account')}
|
||||||
|
title={t('account')}
|
||||||
/>
|
/>
|
||||||
<div className={`${baseClass}__main`}>
|
{!(collection.versions?.drafts && collection.versions?.drafts?.autosave) && (
|
||||||
<Meta
|
<LeaveWithoutSaving />
|
||||||
description={t('accountOfCurrentUser')}
|
)}
|
||||||
keywords={t('account')}
|
<div className={`${baseClass}__edit`}>
|
||||||
title={t('account')}
|
<Gutter className={`${baseClass}__header`}>
|
||||||
/>
|
<Auth
|
||||||
{!(collection.versions?.drafts && collection.versions?.drafts?.autosave) && (
|
className={`${baseClass}__auth`}
|
||||||
<LeaveWithoutSaving />
|
collection={collection}
|
||||||
)}
|
email={data?.email}
|
||||||
<div className={`${baseClass}__edit`}>
|
operation="update"
|
||||||
<Gutter className={`${baseClass}__header`}>
|
readOnly={!hasSavePermission}
|
||||||
<Auth
|
useAPIKey={auth.useAPIKey}
|
||||||
collection={collection}
|
/>
|
||||||
email={data?.email}
|
<RenderFields
|
||||||
operation="update"
|
fieldSchema={fields}
|
||||||
readOnly={!hasSavePermission}
|
fieldTypes={fieldTypes}
|
||||||
useAPIKey={auth.useAPIKey}
|
filter={(field) => field?.admin?.position !== 'sidebar'}
|
||||||
className={`${baseClass}__auth`}
|
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
|
<RenderFields
|
||||||
fieldSchema={fields}
|
fieldSchema={fields}
|
||||||
fieldTypes={fieldTypes}
|
fieldTypes={fieldTypes}
|
||||||
filter={(field) => field?.admin?.position !== 'sidebar'}
|
filter={(field) => field?.admin?.position === 'sidebar'}
|
||||||
permissions={permissions.fields}
|
permissions={permissions.fields}
|
||||||
readOnly={!hasSavePermission}
|
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>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</Form>
|
</div>
|
||||||
</OperationContext.Provider>
|
</Form>
|
||||||
</div>
|
</OperationContext.Provider>
|
||||||
)}
|
</div>
|
||||||
</React.Fragment>
|
)}
|
||||||
)
|
</React.Fragment>
|
||||||
}
|
)
|
||||||
|
|
||||||
return null
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export default DefaultAccount
|
export default DefaultAccount
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
import React from 'react'
|
import React from 'react'
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
|
|
||||||
|
import type { GlobalEditViewProps } from '../types'
|
||||||
|
|
||||||
import { getTranslation } from '../../../../utilities/getTranslation'
|
import { getTranslation } from '../../../../utilities/getTranslation'
|
||||||
import { DocumentHeader } from '../../elements/DocumentHeader'
|
import { DocumentHeader } from '../../elements/DocumentHeader'
|
||||||
import { FormLoadingOverlayToggle } from '../../elements/Loading'
|
import { FormLoadingOverlayToggle } from '../../elements/Loading'
|
||||||
@@ -9,67 +11,62 @@ import { OperationContext } from '../../utilities/OperationProvider'
|
|||||||
import { GlobalRoutes } from './Routes'
|
import { GlobalRoutes } from './Routes'
|
||||||
import { CustomGlobalComponent } from './Routes/CustomComponent'
|
import { CustomGlobalComponent } from './Routes/CustomComponent'
|
||||||
import './index.scss'
|
import './index.scss'
|
||||||
import { EditViewProps } from '../types'
|
|
||||||
|
|
||||||
const baseClass = 'global-edit'
|
const baseClass = 'global-edit'
|
||||||
|
|
||||||
const DefaultGlobalView: React.FC<
|
const DefaultGlobalView: React.FC<
|
||||||
EditViewProps & {
|
GlobalEditViewProps & {
|
||||||
disableRoutes?: boolean
|
disableRoutes?: boolean
|
||||||
}
|
}
|
||||||
> = (props) => {
|
> = (props) => {
|
||||||
if ('global' in props) {
|
const { i18n } = useTranslation('general')
|
||||||
const {
|
|
||||||
action,
|
|
||||||
apiURL,
|
|
||||||
data,
|
|
||||||
disableRoutes,
|
|
||||||
global,
|
|
||||||
initialState,
|
|
||||||
isLoading,
|
|
||||||
onSave,
|
|
||||||
permissions,
|
|
||||||
} = props
|
|
||||||
|
|
||||||
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 (
|
return (
|
||||||
<main className={baseClass}>
|
<main className={baseClass}>
|
||||||
<OperationContext.Provider value="update">
|
<OperationContext.Provider value="update">
|
||||||
<Form
|
<Form
|
||||||
action={action}
|
action={action}
|
||||||
className={`${baseClass}__form`}
|
className={`${baseClass}__form`}
|
||||||
disabled={!hasSavePermission}
|
disabled={!hasSavePermission}
|
||||||
initialState={initialState}
|
initialState={initialState}
|
||||||
method="post"
|
method="post"
|
||||||
onSuccess={onSave}
|
onSuccess={onSave}
|
||||||
>
|
>
|
||||||
<FormLoadingOverlayToggle
|
<FormLoadingOverlayToggle
|
||||||
action="update"
|
action="update"
|
||||||
loadingSuffix={getTranslation(label, i18n)}
|
loadingSuffix={getTranslation(label, i18n)}
|
||||||
name={`global-edit--${typeof label === 'string' ? label : label?.en}`}
|
name={`global-edit--${typeof label === 'string' ? label : label?.en}`}
|
||||||
/>
|
/>
|
||||||
{!isLoading && (
|
{!isLoading && (
|
||||||
<React.Fragment>
|
<React.Fragment>
|
||||||
<DocumentHeader apiURL={apiURL} data={data} global={global} />
|
<DocumentHeader apiURL={apiURL} data={data} global={global} />
|
||||||
{disableRoutes ? (
|
{disableRoutes ? (
|
||||||
<CustomGlobalComponent view="Default" {...props} />
|
<CustomGlobalComponent view="Default" {...props} />
|
||||||
) : (
|
) : (
|
||||||
<GlobalRoutes {...props} />
|
<GlobalRoutes {...props} />
|
||||||
)}
|
)}
|
||||||
</React.Fragment>
|
</React.Fragment>
|
||||||
)}
|
)}
|
||||||
</Form>
|
</Form>
|
||||||
</OperationContext.Provider>
|
</OperationContext.Provider>
|
||||||
</main>
|
</main>
|
||||||
)
|
)
|
||||||
}
|
|
||||||
|
|
||||||
return null
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export default DefaultGlobalView
|
export default DefaultGlobalView
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
import React from 'react'
|
import React from 'react'
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
|
|
||||||
|
import type { GlobalEditViewProps } from '../../types'
|
||||||
|
|
||||||
import { getTranslation } from '../../../../../utilities/getTranslation'
|
import { getTranslation } from '../../../../../utilities/getTranslation'
|
||||||
import { DocumentControls } from '../../../elements/DocumentControls'
|
import { DocumentControls } from '../../../elements/DocumentControls'
|
||||||
import { Gutter } from '../../../elements/Gutter'
|
import { Gutter } from '../../../elements/Gutter'
|
||||||
@@ -10,100 +12,96 @@ import { filterFields } from '../../../forms/RenderFields/filterFields'
|
|||||||
import { fieldTypes } from '../../../forms/field-types'
|
import { fieldTypes } from '../../../forms/field-types'
|
||||||
import LeaveWithoutSaving from '../../../modals/LeaveWithoutSaving'
|
import LeaveWithoutSaving from '../../../modals/LeaveWithoutSaving'
|
||||||
import Meta from '../../../utilities/Meta'
|
import Meta from '../../../utilities/Meta'
|
||||||
|
import { SetStepNav } from '../../collections/Edit/SetStepNav'
|
||||||
import './index.scss'
|
import './index.scss'
|
||||||
import { EditViewProps } from '../../types'
|
|
||||||
|
|
||||||
const baseClass = 'global-default-edit'
|
const baseClass = 'global-default-edit'
|
||||||
|
|
||||||
export const DefaultGlobalEdit: React.FC<EditViewProps> = (props) => {
|
export const DefaultGlobalEdit: React.FC<GlobalEditViewProps> = (props) => {
|
||||||
if ('global' in props) {
|
const { i18n } = useTranslation('general')
|
||||||
const { apiURL, data, global, permissions } = props
|
|
||||||
|
|
||||||
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({
|
const sidebarFields = filterFields({
|
||||||
fieldSchema: fields,
|
fieldSchema: fields,
|
||||||
fieldTypes,
|
fieldTypes,
|
||||||
filter: (field) => field?.admin?.position === 'sidebar',
|
filter: (field) => field?.admin?.position === 'sidebar',
|
||||||
permissions: permissions.fields,
|
permissions: permissions.fields,
|
||||||
readOnly: !hasSavePermission,
|
readOnly: !hasSavePermission,
|
||||||
})
|
})
|
||||||
|
|
||||||
const hasSidebar = sidebarFields && sidebarFields.length > 0
|
const hasSidebar = sidebarFields && sidebarFields.length > 0
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<React.Fragment>
|
<React.Fragment>
|
||||||
{/* <SetStepNav collection={collection} id={id} isEditing={isEditing} /> */}
|
<SetStepNav global={global} />
|
||||||
<DocumentControls
|
<DocumentControls
|
||||||
apiURL={apiURL}
|
apiURL={apiURL}
|
||||||
data={data}
|
data={data}
|
||||||
global={global}
|
global={global}
|
||||||
hasSavePermission={hasSavePermission}
|
hasSavePermission={hasSavePermission}
|
||||||
isEditing
|
isEditing
|
||||||
permissions={permissions}
|
permissions={permissions}
|
||||||
/>
|
/>
|
||||||
<div
|
<div
|
||||||
className={[
|
className={[
|
||||||
baseClass,
|
baseClass,
|
||||||
hasSidebar ? `${baseClass}--has-sidebar` : `${baseClass}--no-sidebar`,
|
hasSidebar ? `${baseClass}--has-sidebar` : `${baseClass}--no-sidebar`,
|
||||||
]
|
]
|
||||||
.filter(Boolean)
|
.filter(Boolean)
|
||||||
.join(' ')}
|
.join(' ')}
|
||||||
>
|
>
|
||||||
<div className={`${baseClass}__main`}>
|
<div className={`${baseClass}__main`}>
|
||||||
<Meta
|
<Meta
|
||||||
description={getTranslation(label, i18n)}
|
description={getTranslation(label, i18n)}
|
||||||
keywords={`${getTranslation(label, i18n)}, Payload, CMS`}
|
keywords={`${getTranslation(label, i18n)}, Payload, CMS`}
|
||||||
title={getTranslation(label, i18n)}
|
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) && (
|
</Gutter>
|
||||||
<LeaveWithoutSaving />
|
</div>
|
||||||
)}
|
{hasSidebar && (
|
||||||
<Gutter className={`${baseClass}__edit`}>
|
<div className={`${baseClass}__sidebar-wrap`}>
|
||||||
<header className={`${baseClass}__header`}>
|
<div className={`${baseClass}__sidebar`}>
|
||||||
{description && (
|
<div className={`${baseClass}__sidebar-sticky-wrap`}>
|
||||||
<div className={`${baseClass}__sub-header`}>
|
<div className={`${baseClass}__sidebar-fields`}>
|
||||||
<ViewDescription description={description} />
|
<RenderFields
|
||||||
</div>
|
fieldSchema={fields}
|
||||||
)}
|
fieldTypes={fieldTypes}
|
||||||
</header>
|
filter={(field) => field.admin.position === 'sidebar'}
|
||||||
<RenderFields
|
permissions={permissions.fields}
|
||||||
fieldSchema={fields}
|
readOnly={!hasSavePermission}
|
||||||
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>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)}
|
</div>
|
||||||
</div>
|
)}
|
||||||
</React.Fragment>
|
</div>
|
||||||
)
|
</React.Fragment>
|
||||||
}
|
)
|
||||||
|
|
||||||
return null
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,9 +1,10 @@
|
|||||||
import React from 'react'
|
import React from 'react'
|
||||||
|
|
||||||
|
import type { GlobalEditViewProps } from '../../types'
|
||||||
|
|
||||||
import VersionView from '../../Version/Version'
|
import VersionView from '../../Version/Version'
|
||||||
import VersionsView from '../../Versions'
|
import VersionsView from '../../Versions'
|
||||||
import { DefaultGlobalEdit } from '../Default/index'
|
import { DefaultGlobalEdit } from '../Default/index'
|
||||||
import { EditViewProps } from '../../types'
|
|
||||||
|
|
||||||
export type globalViewType =
|
export type globalViewType =
|
||||||
| 'API'
|
| 'API'
|
||||||
@@ -27,37 +28,33 @@ export const defaultGlobalViews: {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const CustomGlobalComponent = (
|
export const CustomGlobalComponent = (
|
||||||
args: EditViewProps & {
|
args: GlobalEditViewProps & {
|
||||||
view: globalViewType
|
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
|
// Overriding components may come from multiple places in the config
|
||||||
// Need to cascade through the hierarchy to find the correct component to render
|
// Need to cascade through the hierarchy to find the correct component to render
|
||||||
// For example, the Edit view:
|
// For example, the Edit view:
|
||||||
// 1. Edit?.Default
|
// 1. Edit?.Default
|
||||||
// 2. Edit?.Default?.Component
|
// 2. Edit?.Default?.Component
|
||||||
// TODO: Remove the `@ts-ignore` when a Typescript wizard arrives
|
// 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
|
// For some reason `Component` does not exist on type `Edit[view]` no matter how narrow the type is
|
||||||
const Component =
|
const Component =
|
||||||
typeof Edit === 'object' && typeof Edit[view] === 'function'
|
typeof Edit === 'object' && typeof Edit[view] === 'function'
|
||||||
? Edit[view]
|
? Edit[view]
|
||||||
: typeof Edit === 'object' &&
|
: typeof Edit === 'object' &&
|
||||||
typeof Edit?.[view] === 'object' &&
|
typeof Edit?.[view] === 'object' &&
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
typeof Edit[view].Component === 'function'
|
typeof Edit[view].Component === 'function'
|
||||||
? // @ts-ignore
|
? // @ts-ignore
|
||||||
Edit[view].Component
|
Edit[view].Component
|
||||||
: defaultGlobalViews[view]
|
: defaultGlobalViews[view]
|
||||||
|
|
||||||
if (Component) {
|
if (Component) {
|
||||||
return <Component {...args} />
|
return <Component {...args} />
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return null
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,74 +2,71 @@ import { lazy } from 'react'
|
|||||||
import React from 'react'
|
import React from 'react'
|
||||||
import { Route, Switch, useRouteMatch } from 'react-router-dom'
|
import { Route, Switch, useRouteMatch } from 'react-router-dom'
|
||||||
|
|
||||||
|
import type { GlobalEditViewProps } from '../../types'
|
||||||
|
|
||||||
import { useAuth } from '../../../utilities/Auth'
|
import { useAuth } from '../../../utilities/Auth'
|
||||||
import { useConfig } from '../../../utilities/Config'
|
import { useConfig } from '../../../utilities/Config'
|
||||||
import NotFound from '../../NotFound'
|
import NotFound from '../../NotFound'
|
||||||
import { CustomGlobalComponent } from './CustomComponent'
|
import { CustomGlobalComponent } from './CustomComponent'
|
||||||
import { globalCustomRoutes } from './custom'
|
import { globalCustomRoutes } from './custom'
|
||||||
import { EditViewProps } from '../../types'
|
|
||||||
|
|
||||||
// @ts-expect-error Just TypeScript being broken // TODO: Open TypeScript issue
|
// @ts-expect-error Just TypeScript being broken // TODO: Open TypeScript issue
|
||||||
const Unauthorized = lazy(() => import('../../Unauthorized'))
|
const Unauthorized = lazy(() => import('../../Unauthorized'))
|
||||||
|
|
||||||
export const GlobalRoutes: React.FC<EditViewProps> = (props) => {
|
export const GlobalRoutes: React.FC<GlobalEditViewProps> = (props) => {
|
||||||
if ('global' in props) {
|
const { global, permissions } = props
|
||||||
const { global, permissions } = props
|
|
||||||
|
|
||||||
const match = useRouteMatch()
|
const match = useRouteMatch()
|
||||||
|
|
||||||
const {
|
const {
|
||||||
routes: { admin: adminRoute },
|
routes: { admin: adminRoute },
|
||||||
} = useConfig()
|
} = useConfig()
|
||||||
|
|
||||||
const { user } = useAuth()
|
const { user } = useAuth()
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Switch>
|
<Switch>
|
||||||
<Route
|
<Route
|
||||||
exact
|
exact
|
||||||
key={`${global.slug}-versions`}
|
key={`${global.slug}-versions`}
|
||||||
path={`${adminRoute}/globals/${global.slug}/versions`}
|
path={`${adminRoute}/globals/${global.slug}/versions`}
|
||||||
>
|
>
|
||||||
{permissions?.readVersions?.permission ? (
|
{permissions?.readVersions?.permission ? (
|
||||||
<CustomGlobalComponent view="Versions" {...props} />
|
<CustomGlobalComponent view="Versions" {...props} />
|
||||||
) : (
|
) : (
|
||||||
<Unauthorized />
|
<Unauthorized />
|
||||||
)}
|
)}
|
||||||
</Route>
|
</Route>
|
||||||
<Route
|
<Route
|
||||||
exact
|
exact
|
||||||
key={`${global.slug}-view-version`}
|
key={`${global.slug}-view-version`}
|
||||||
path={`${adminRoute}/globals/${global.slug}/versions/:versionID`}
|
path={`${adminRoute}/globals/${global.slug}/versions/:versionID`}
|
||||||
>
|
>
|
||||||
{permissions?.readVersions?.permission ? (
|
{permissions?.readVersions?.permission ? (
|
||||||
<CustomGlobalComponent view="Version" {...props} />
|
<CustomGlobalComponent view="Version" {...props} />
|
||||||
) : (
|
) : (
|
||||||
<Unauthorized />
|
<Unauthorized />
|
||||||
)}
|
)}
|
||||||
</Route>
|
</Route>
|
||||||
<Route
|
<Route
|
||||||
exact
|
exact
|
||||||
key={`${global.slug}-live-preview`}
|
key={`${global.slug}-live-preview`}
|
||||||
path={`${adminRoute}/globals/${global.slug}/preview`}
|
path={`${adminRoute}/globals/${global.slug}/preview`}
|
||||||
>
|
>
|
||||||
<CustomGlobalComponent view="LivePreview" {...props} />
|
<CustomGlobalComponent view="LivePreview" {...props} />
|
||||||
</Route>
|
</Route>
|
||||||
{globalCustomRoutes({
|
{globalCustomRoutes({
|
||||||
global,
|
global,
|
||||||
match,
|
match,
|
||||||
permissions,
|
permissions,
|
||||||
user,
|
user,
|
||||||
})}
|
})}
|
||||||
<Route exact key={`${global.slug}-view`} path={`${adminRoute}/globals/${global.slug}`}>
|
<Route exact key={`${global.slug}-view`} path={`${adminRoute}/globals/${global.slug}`}>
|
||||||
<CustomGlobalComponent view="Default" {...props} />
|
<CustomGlobalComponent view="Default" {...props} />
|
||||||
</Route>
|
</Route>
|
||||||
<Route path={`${match.url}*`}>
|
<Route path={`${match.url}*`}>
|
||||||
<NotFound marginTop="large" />
|
<NotFound marginTop="large" />
|
||||||
</Route>
|
</Route>
|
||||||
</Switch>
|
</Switch>
|
||||||
)
|
)
|
||||||
}
|
|
||||||
|
|
||||||
return null
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,27 +3,25 @@ import { useTranslation } from 'react-i18next'
|
|||||||
import { useLocation } from 'react-router-dom'
|
import { useLocation } from 'react-router-dom'
|
||||||
|
|
||||||
import type { Fields } from '../../forms/Form/types'
|
import type { Fields } from '../../forms/Form/types'
|
||||||
|
import type { GlobalEditViewProps } from '../types'
|
||||||
import type { IndexProps } from './types'
|
import type { IndexProps } from './types'
|
||||||
|
|
||||||
import usePayloadAPI from '../../../hooks/usePayloadAPI'
|
import usePayloadAPI from '../../../hooks/usePayloadAPI'
|
||||||
import { useStepNav } from '../../elements/StepNav'
|
|
||||||
import buildStateFromSchema from '../../forms/Form/buildStateFromSchema'
|
import buildStateFromSchema from '../../forms/Form/buildStateFromSchema'
|
||||||
import { useAuth } from '../../utilities/Auth'
|
import { useAuth } from '../../utilities/Auth'
|
||||||
import { useConfig } from '../../utilities/Config'
|
import { useConfig } from '../../utilities/Config'
|
||||||
import { useDocumentInfo } from '../../utilities/DocumentInfo'
|
import { useDocumentInfo } from '../../utilities/DocumentInfo'
|
||||||
|
import { EditDepthContext } from '../../utilities/EditDepth'
|
||||||
import { useLocale } from '../../utilities/Locale'
|
import { useLocale } from '../../utilities/Locale'
|
||||||
import { usePreferences } from '../../utilities/Preferences'
|
import { usePreferences } from '../../utilities/Preferences'
|
||||||
import RenderCustomComponent from '../../utilities/RenderCustomComponent'
|
import RenderCustomComponent from '../../utilities/RenderCustomComponent'
|
||||||
import DefaultGlobalView from './Default'
|
import DefaultGlobalView from './Default'
|
||||||
import { EditDepthContext } from '../../utilities/EditDepth'
|
|
||||||
import { EditViewProps } from '../types'
|
|
||||||
|
|
||||||
const GlobalView: React.FC<IndexProps> = (props) => {
|
const GlobalView: React.FC<IndexProps> = (props) => {
|
||||||
const { global } = props
|
const { global } = props
|
||||||
|
|
||||||
const { state: locationState } = useLocation<{ data?: Record<string, unknown> }>()
|
const { state: locationState } = useLocation<{ data?: Record<string, unknown> }>()
|
||||||
const { code: locale } = useLocale()
|
const { code: locale } = useLocale()
|
||||||
const { setStepNav } = useStepNav()
|
|
||||||
const { permissions, user } = useAuth()
|
const { permissions, user } = useAuth()
|
||||||
const [initialState, setInitialState] = useState<Fields>()
|
const [initialState, setInitialState] = useState<Fields>()
|
||||||
const [updatedAt, setUpdatedAt] = useState<string>()
|
const [updatedAt, setUpdatedAt] = useState<string>()
|
||||||
@@ -37,12 +35,7 @@ const GlobalView: React.FC<IndexProps> = (props) => {
|
|||||||
serverURL,
|
serverURL,
|
||||||
} = useConfig()
|
} = useConfig()
|
||||||
|
|
||||||
const {
|
const { admin: { components: { views: { Edit: Edit } = {} } = {} } = {}, fields, slug } = global
|
||||||
admin: { components: { views: { Edit: Edit } = {} } = {} } = {},
|
|
||||||
fields,
|
|
||||||
label,
|
|
||||||
slug,
|
|
||||||
} = global
|
|
||||||
|
|
||||||
const onSave = useCallback(
|
const onSave = useCallback(
|
||||||
async (json) => {
|
async (json) => {
|
||||||
@@ -71,16 +64,6 @@ const GlobalView: React.FC<IndexProps> = (props) => {
|
|||||||
|
|
||||||
const dataToRender = locationState?.data || data
|
const dataToRender = locationState?.data || data
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
const nav = [
|
|
||||||
{
|
|
||||||
label,
|
|
||||||
},
|
|
||||||
]
|
|
||||||
|
|
||||||
setStepNav(nav)
|
|
||||||
}, [setStepNav, label])
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const awaitInitialState = async () => {
|
const awaitInitialState = async () => {
|
||||||
const preferences = await getDocPreferences()
|
const preferences = await getDocPreferences()
|
||||||
@@ -102,7 +85,7 @@ const GlobalView: React.FC<IndexProps> = (props) => {
|
|||||||
|
|
||||||
const isLoading = !initialState || !docPermissions || isLoadingData
|
const isLoading = !initialState || !docPermissions || isLoadingData
|
||||||
|
|
||||||
const componentProps: EditViewProps = {
|
const componentProps: GlobalEditViewProps = {
|
||||||
action: `${serverURL}${api}/globals/${slug}?locale=${locale}&fallback-locale=null`,
|
action: `${serverURL}${api}/globals/${slug}?locale=${locale}&fallback-locale=null`,
|
||||||
apiURL: `${serverURL}${api}/globals/${slug}?locale=${locale}${
|
apiURL: `${serverURL}${api}/globals/${slug}?locale=${locale}${
|
||||||
global.versions?.drafts ? '&draft=true' : ''
|
global.versions?.drafts ? '&draft=true' : ''
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ import { filterFields } from '../../forms/RenderFields/filterFields'
|
|||||||
import { fieldTypes } from '../../forms/field-types'
|
import { fieldTypes } from '../../forms/field-types'
|
||||||
import LeaveWithoutSaving from '../../modals/LeaveWithoutSaving'
|
import LeaveWithoutSaving from '../../modals/LeaveWithoutSaving'
|
||||||
import Meta from '../../utilities/Meta'
|
import Meta from '../../utilities/Meta'
|
||||||
|
import { SetStepNav } from '../collections/Edit/SetStepNav'
|
||||||
import { LivePreview } from './Preview'
|
import { LivePreview } from './Preview'
|
||||||
import './index.scss'
|
import './index.scss'
|
||||||
import { usePopupWindow } from './usePopupWindow'
|
import { usePopupWindow } from './usePopupWindow'
|
||||||
@@ -71,6 +72,7 @@ export const LivePreviewView: React.FC<EditViewProps> = (props) => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<Fragment>
|
<Fragment>
|
||||||
|
<SetStepNav collection={collection} global={global} id={id} isEditing={isEditing} />
|
||||||
<DocumentControls
|
<DocumentControls
|
||||||
apiURL={apiURL}
|
apiURL={apiURL}
|
||||||
collection={collection}
|
collection={collection}
|
||||||
|
|||||||
@@ -85,7 +85,7 @@ const VersionView: React.FC<Props> = ({ collection, global }) => {
|
|||||||
? originalDocFetchURL
|
? originalDocFetchURL
|
||||||
: `${compareBaseURL}/${compareValue.value}`
|
: `${compareBaseURL}/${compareValue.value}`
|
||||||
|
|
||||||
const [{ data: doc, isError, isLoading: isLoadingData }] = usePayloadAPI(versionFetchURL, {
|
const [{ data: doc, isError }] = usePayloadAPI(versionFetchURL, {
|
||||||
initialParams: { depth: 1, locale: '*' },
|
initialParams: { depth: 1, locale: '*' },
|
||||||
})
|
})
|
||||||
const [{ data: publishedDoc }] = usePayloadAPI(originalDocFetchURL, {
|
const [{ data: publishedDoc }] = usePayloadAPI(originalDocFetchURL, {
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
import React, { useCallback } from 'react'
|
import React, { useCallback } from 'react'
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
|
|
||||||
|
import type { CollectionEditViewProps } from '../../types'
|
||||||
|
|
||||||
import { getTranslation } from '../../../../../utilities/getTranslation'
|
import { getTranslation } from '../../../../../utilities/getTranslation'
|
||||||
import { DocumentHeader } from '../../../elements/DocumentHeader'
|
import { DocumentHeader } from '../../../elements/DocumentHeader'
|
||||||
import { FormLoadingOverlayToggle } from '../../../elements/Loading'
|
import { FormLoadingOverlayToggle } from '../../../elements/Loading'
|
||||||
@@ -9,104 +11,99 @@ import { useAuth } from '../../../utilities/Auth'
|
|||||||
import { OperationContext } from '../../../utilities/OperationProvider'
|
import { OperationContext } from '../../../utilities/OperationProvider'
|
||||||
import { CollectionRoutes } from './Routes'
|
import { CollectionRoutes } from './Routes'
|
||||||
import { CustomCollectionComponent } from './Routes/CustomComponent'
|
import { CustomCollectionComponent } from './Routes/CustomComponent'
|
||||||
import { EditViewProps } from '../../types'
|
|
||||||
import './index.scss'
|
import './index.scss'
|
||||||
|
|
||||||
const baseClass = 'collection-edit'
|
const baseClass = 'collection-edit'
|
||||||
|
|
||||||
const DefaultEditView: React.FC<
|
const DefaultEditView: React.FC<
|
||||||
EditViewProps & {
|
CollectionEditViewProps & {
|
||||||
disableRoutes?: boolean
|
|
||||||
customHeader?: React.ReactNode
|
customHeader?: React.ReactNode
|
||||||
|
disableRoutes?: boolean
|
||||||
}
|
}
|
||||||
> = (props) => {
|
> = (props) => {
|
||||||
const { i18n } = useTranslation('general')
|
const { i18n } = useTranslation('general')
|
||||||
const { refreshCookieAsync, user } = useAuth()
|
const { refreshCookieAsync, user } = useAuth()
|
||||||
|
|
||||||
if ('collection' in props) {
|
const {
|
||||||
const {
|
id,
|
||||||
id,
|
action,
|
||||||
action,
|
apiURL,
|
||||||
apiURL,
|
collection,
|
||||||
collection,
|
customHeader,
|
||||||
customHeader,
|
data,
|
||||||
data,
|
disableRoutes,
|
||||||
disableRoutes,
|
hasSavePermission,
|
||||||
hasSavePermission,
|
internalState,
|
||||||
internalState,
|
isEditing,
|
||||||
isEditing,
|
isLoading,
|
||||||
isLoading,
|
onSave: onSaveFromProps,
|
||||||
onSave: onSaveFromProps,
|
} = props
|
||||||
} = 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(
|
const onSave = useCallback(
|
||||||
async (json) => {
|
async (json) => {
|
||||||
if (auth && id === user.id) {
|
if (auth && id === user.id) {
|
||||||
await refreshCookieAsync()
|
await refreshCookieAsync()
|
||||||
}
|
}
|
||||||
|
|
||||||
if (typeof onSaveFromProps === 'function') {
|
if (typeof onSaveFromProps === 'function') {
|
||||||
onSaveFromProps({
|
onSaveFromProps({
|
||||||
...json,
|
...json,
|
||||||
operation: id ? 'update' : 'create',
|
operation: id ? 'update' : 'create',
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
[id, onSaveFromProps, auth, user, refreshCookieAsync],
|
[id, onSaveFromProps, auth, user, refreshCookieAsync],
|
||||||
)
|
)
|
||||||
|
|
||||||
const operation = isEditing ? 'update' : 'create'
|
const operation = isEditing ? 'update' : 'create'
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<main className={classes}>
|
<main className={classes}>
|
||||||
<OperationContext.Provider value={operation}>
|
<OperationContext.Provider value={operation}>
|
||||||
<Form
|
<Form
|
||||||
action={action}
|
action={action}
|
||||||
className={`${baseClass}__form`}
|
className={`${baseClass}__form`}
|
||||||
disabled={!hasSavePermission}
|
disabled={!hasSavePermission}
|
||||||
initialState={internalState}
|
initialState={internalState}
|
||||||
method={id ? 'patch' : 'post'}
|
method={id ? 'patch' : 'post'}
|
||||||
onSuccess={onSave}
|
onSuccess={onSave}
|
||||||
>
|
>
|
||||||
<FormLoadingOverlayToggle
|
<FormLoadingOverlayToggle
|
||||||
action={isLoading ? 'loading' : operation}
|
action={isLoading ? 'loading' : operation}
|
||||||
formIsLoading={isLoading}
|
formIsLoading={isLoading}
|
||||||
loadingSuffix={getTranslation(collection.labels.singular, i18n)}
|
loadingSuffix={getTranslation(collection.labels.singular, i18n)}
|
||||||
name={`collection-edit--${
|
name={`collection-edit--${
|
||||||
typeof collection?.labels?.singular === 'string'
|
typeof collection?.labels?.singular === 'string'
|
||||||
? collection.labels.singular
|
? collection.labels.singular
|
||||||
: 'document'
|
: 'document'
|
||||||
}`}
|
}`}
|
||||||
type="withoutNav"
|
type="withoutNav"
|
||||||
/>
|
/>
|
||||||
{!isLoading && (
|
{!isLoading && (
|
||||||
<React.Fragment>
|
<React.Fragment>
|
||||||
<DocumentHeader
|
<DocumentHeader
|
||||||
apiURL={apiURL}
|
apiURL={apiURL}
|
||||||
collection={collection}
|
collection={collection}
|
||||||
customHeader={customHeader}
|
customHeader={customHeader}
|
||||||
data={data}
|
data={data}
|
||||||
id={id}
|
id={id}
|
||||||
isEditing={isEditing}
|
isEditing={isEditing}
|
||||||
/>
|
/>
|
||||||
{disableRoutes ? (
|
{disableRoutes ? (
|
||||||
<CustomCollectionComponent view="Default" {...props} />
|
<CustomCollectionComponent view="Default" {...props} />
|
||||||
) : (
|
) : (
|
||||||
<CollectionRoutes {...props} />
|
<CollectionRoutes {...props} />
|
||||||
)}
|
)}
|
||||||
</React.Fragment>
|
</React.Fragment>
|
||||||
)}
|
)}
|
||||||
</Form>
|
</Form>
|
||||||
</OperationContext.Provider>
|
</OperationContext.Provider>
|
||||||
</main>
|
</main>
|
||||||
)
|
)
|
||||||
}
|
|
||||||
|
|
||||||
return null
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export default DefaultEditView
|
export default DefaultEditView
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
import React, { Fragment } from 'react'
|
import React, { Fragment } from 'react'
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
|
|
||||||
|
import type { CollectionEditViewProps } from '../../../types'
|
||||||
|
|
||||||
import { getTranslation } from '../../../../../../utilities/getTranslation'
|
import { getTranslation } from '../../../../../../utilities/getTranslation'
|
||||||
import { DocumentControls } from '../../../../elements/DocumentControls'
|
import { DocumentControls } from '../../../../elements/DocumentControls'
|
||||||
import { Gutter } from '../../../../elements/Gutter'
|
import { Gutter } from '../../../../elements/Gutter'
|
||||||
@@ -13,115 +15,110 @@ import Auth from '../Auth'
|
|||||||
import { SetStepNav } from '../SetStepNav'
|
import { SetStepNav } from '../SetStepNav'
|
||||||
import Upload from '../Upload'
|
import Upload from '../Upload'
|
||||||
import './index.scss'
|
import './index.scss'
|
||||||
import { EditViewProps } from '../../../types'
|
|
||||||
|
|
||||||
const baseClass = 'collection-default-edit'
|
const baseClass = 'collection-default-edit'
|
||||||
|
|
||||||
export const DefaultCollectionEdit: React.FC<EditViewProps> = (props) => {
|
export const DefaultCollectionEdit: React.FC<CollectionEditViewProps> = (props) => {
|
||||||
if ('collection' in props) {
|
const { i18n, t } = useTranslation('general')
|
||||||
const { i18n, t } = useTranslation('general')
|
|
||||||
|
|
||||||
const {
|
const {
|
||||||
id,
|
id,
|
||||||
apiURL,
|
apiURL,
|
||||||
collection,
|
collection,
|
||||||
data,
|
data,
|
||||||
disableActions,
|
disableActions,
|
||||||
disableLeaveWithoutSaving,
|
disableLeaveWithoutSaving,
|
||||||
hasSavePermission,
|
hasSavePermission,
|
||||||
internalState,
|
internalState,
|
||||||
isEditing,
|
isEditing,
|
||||||
permissions,
|
permissions,
|
||||||
} = props
|
} = props
|
||||||
|
|
||||||
const { auth, fields, upload } = collection
|
const { auth, fields, upload } = collection
|
||||||
|
|
||||||
const operation = isEditing ? 'update' : 'create'
|
const operation = isEditing ? 'update' : 'create'
|
||||||
|
|
||||||
const sidebarFields = filterFields({
|
const sidebarFields = filterFields({
|
||||||
fieldSchema: fields,
|
fieldSchema: fields,
|
||||||
fieldTypes,
|
fieldTypes,
|
||||||
filter: (field) => field?.admin?.position === 'sidebar',
|
filter: (field) => field?.admin?.position === 'sidebar',
|
||||||
permissions: permissions.fields,
|
permissions: permissions.fields,
|
||||||
readOnly: !hasSavePermission,
|
readOnly: !hasSavePermission,
|
||||||
})
|
})
|
||||||
|
|
||||||
const hasSidebar = sidebarFields && sidebarFields.length > 0
|
const hasSidebar = sidebarFields && sidebarFields.length > 0
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Fragment>
|
<Fragment>
|
||||||
<SetStepNav collection={collection} id={id} isEditing={isEditing} />
|
<SetStepNav collection={collection} id={id} isEditing={isEditing} />
|
||||||
<DocumentControls
|
<DocumentControls
|
||||||
apiURL={apiURL}
|
apiURL={apiURL}
|
||||||
collection={collection}
|
collection={collection}
|
||||||
data={data}
|
data={data}
|
||||||
disableActions={disableActions}
|
disableActions={disableActions}
|
||||||
hasSavePermission={hasSavePermission}
|
hasSavePermission={hasSavePermission}
|
||||||
id={id}
|
id={id}
|
||||||
isEditing={isEditing}
|
isEditing={isEditing}
|
||||||
permissions={permissions}
|
permissions={permissions}
|
||||||
/>
|
/>
|
||||||
<div
|
<div
|
||||||
className={[
|
className={[
|
||||||
baseClass,
|
baseClass,
|
||||||
hasSidebar ? `${baseClass}--has-sidebar` : `${baseClass}--no-sidebar`,
|
hasSidebar ? `${baseClass}--has-sidebar` : `${baseClass}--no-sidebar`,
|
||||||
]
|
]
|
||||||
.filter(Boolean)
|
.filter(Boolean)
|
||||||
.join(' ')}
|
.join(' ')}
|
||||||
>
|
>
|
||||||
<div className={`${baseClass}__main`}>
|
<div className={`${baseClass}__main`}>
|
||||||
<Meta
|
<Meta
|
||||||
description={`${isEditing ? t('editing') : t('creating')} - ${getTranslation(
|
description={`${isEditing ? t('editing') : t('creating')} - ${getTranslation(
|
||||||
collection.labels.singular,
|
collection.labels.singular,
|
||||||
i18n,
|
i18n,
|
||||||
)}`}
|
)}`}
|
||||||
keywords={`${getTranslation(collection.labels.singular, i18n)}, Payload, CMS`}
|
keywords={`${getTranslation(collection.labels.singular, i18n)}, Payload, CMS`}
|
||||||
title={`${isEditing ? t('editing') : t('creating')} - ${getTranslation(
|
title={`${isEditing ? t('editing') : t('creating')} - ${getTranslation(
|
||||||
collection.labels.singular,
|
collection.labels.singular,
|
||||||
i18n,
|
i18n,
|
||||||
)}`}
|
)}`}
|
||||||
/>
|
/>
|
||||||
{!(collection.versions?.drafts && collection.versions?.drafts?.autosave) &&
|
{!(collection.versions?.drafts && collection.versions?.drafts?.autosave) &&
|
||||||
!disableLeaveWithoutSaving && <LeaveWithoutSaving />}
|
!disableLeaveWithoutSaving && <LeaveWithoutSaving />}
|
||||||
<Gutter className={`${baseClass}__edit`}>
|
<Gutter className={`${baseClass}__edit`}>
|
||||||
{auth && (
|
{auth && (
|
||||||
<Auth
|
<Auth
|
||||||
className={`${baseClass}__auth`}
|
className={`${baseClass}__auth`}
|
||||||
collection={collection}
|
collection={collection}
|
||||||
email={data?.email}
|
email={data?.email}
|
||||||
operation={operation}
|
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}
|
|
||||||
readOnly={!hasSavePermission}
|
readOnly={!hasSavePermission}
|
||||||
className={`${baseClass}__fields`}
|
requirePassword={!isEditing}
|
||||||
|
useAPIKey={auth.useAPIKey}
|
||||||
|
verify={auth.verify}
|
||||||
/>
|
/>
|
||||||
</Gutter>
|
)}
|
||||||
</div>
|
{upload && <Upload collection={collection} data={data} internalState={internalState} />}
|
||||||
{hasSidebar && (
|
<RenderFields
|
||||||
<div className={`${baseClass}__sidebar-wrap`}>
|
className={`${baseClass}__fields`}
|
||||||
<div className={`${baseClass}__sidebar`}>
|
fieldSchema={fields}
|
||||||
<div className={`${baseClass}__sidebar-sticky-wrap`}>
|
fieldTypes={fieldTypes}
|
||||||
<div className={`${baseClass}__sidebar-fields`}>
|
filter={(field) => !field?.admin?.position || field?.admin?.position !== 'sidebar'}
|
||||||
<RenderFields fieldTypes={fieldTypes} fields={sidebarFields} />
|
permissions={permissions.fields}
|
||||||
</div>
|
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>
|
||||||
</div>
|
</div>
|
||||||
)}
|
</div>
|
||||||
</div>
|
)}
|
||||||
</Fragment>
|
</div>
|
||||||
)
|
</Fragment>
|
||||||
}
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
import React from 'react'
|
import React from 'react'
|
||||||
|
|
||||||
import type { EditViewProps } from '../../../types'
|
import type { CollectionEditViewProps } from '../../../types'
|
||||||
|
|
||||||
|
import { LivePreviewView } from '../../../LivePreview'
|
||||||
import { QueryInspector } from '../../../RestAPI'
|
import { QueryInspector } from '../../../RestAPI'
|
||||||
import VersionView from '../../../Version/Version'
|
import VersionView from '../../../Version/Version'
|
||||||
import VersionsView from '../../../Versions'
|
import VersionsView from '../../../Versions'
|
||||||
import { DefaultCollectionEdit } from '../Default/index'
|
import { DefaultCollectionEdit } from '../Default/index'
|
||||||
import { LivePreviewView } from '../../../LivePreview'
|
|
||||||
|
|
||||||
export type collectionViewType =
|
export type collectionViewType =
|
||||||
| 'API'
|
| 'API'
|
||||||
@@ -30,37 +30,33 @@ export const defaultCollectionViews: {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const CustomCollectionComponent = (
|
export const CustomCollectionComponent = (
|
||||||
args: EditViewProps & {
|
args: CollectionEditViewProps & {
|
||||||
view: collectionViewType
|
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
|
// Overriding components may come from multiple places in the config
|
||||||
// Need to cascade through the hierarchy to find the correct component to render
|
// Need to cascade through the hierarchy to find the correct component to render
|
||||||
// For example, the Edit view:
|
// For example, the Edit view:
|
||||||
// 1. Edit?.Default
|
// 1. Edit?.Default
|
||||||
// 2. Edit?.Default?.Component
|
// 2. Edit?.Default?.Component
|
||||||
// TODO: Remove the `@ts-ignore` when a Typescript wizard arrives
|
// 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
|
// For some reason `Component` does not exist on type `Edit[view]` no matter how narrow the type is
|
||||||
const Component =
|
const Component =
|
||||||
typeof Edit === 'object' && typeof Edit[view] === 'function'
|
typeof Edit === 'object' && typeof Edit[view] === 'function'
|
||||||
? Edit[view]
|
? Edit[view]
|
||||||
: typeof Edit === 'object' &&
|
: typeof Edit === 'object' &&
|
||||||
typeof Edit?.[view] === 'object' &&
|
typeof Edit?.[view] === 'object' &&
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
typeof Edit[view].Component === 'function'
|
typeof Edit[view].Component === 'function'
|
||||||
? // @ts-ignore
|
? // @ts-ignore
|
||||||
Edit[view].Component
|
Edit[view].Component
|
||||||
: defaultCollectionViews[view]
|
: defaultCollectionViews[view]
|
||||||
|
|
||||||
if (Component) {
|
if (Component) {
|
||||||
return <Component {...args} />
|
return <Component {...args} />
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return null
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import { lazy } from 'react'
|
|||||||
import React from 'react'
|
import React from 'react'
|
||||||
import { Route, Switch, useRouteMatch } from 'react-router-dom'
|
import { Route, Switch, useRouteMatch } from 'react-router-dom'
|
||||||
|
|
||||||
import type { EditViewProps } from '../../../types'
|
import type { CollectionEditViewProps } from '../../../types'
|
||||||
|
|
||||||
import { useAuth } from '../../../../utilities/Auth'
|
import { useAuth } from '../../../../utilities/Auth'
|
||||||
import { useConfig } from '../../../../utilities/Config'
|
import { useConfig } from '../../../../utilities/Config'
|
||||||
@@ -13,77 +13,71 @@ import { collectionCustomRoutes } from './custom'
|
|||||||
// @ts-expect-error Just TypeScript being broken // TODO: Open TypeScript issue
|
// @ts-expect-error Just TypeScript being broken // TODO: Open TypeScript issue
|
||||||
const Unauthorized = lazy(() => import('../../../Unauthorized'))
|
const Unauthorized = lazy(() => import('../../../Unauthorized'))
|
||||||
|
|
||||||
export const CollectionRoutes: React.FC<EditViewProps> = (props) => {
|
export const CollectionRoutes: React.FC<CollectionEditViewProps> = (props) => {
|
||||||
if ('collection' in props) {
|
const { collection, permissions } = props
|
||||||
const { collection, permissions } = props
|
|
||||||
|
|
||||||
const match = useRouteMatch()
|
const match = useRouteMatch()
|
||||||
|
|
||||||
const {
|
const {
|
||||||
routes: { admin: adminRoute },
|
routes: { admin: adminRoute },
|
||||||
} = useConfig()
|
} = useConfig()
|
||||||
|
|
||||||
const { user } = useAuth()
|
const { user } = useAuth()
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Switch>
|
<Switch>
|
||||||
<Route
|
<Route
|
||||||
exact
|
exact
|
||||||
key={`${collection.slug}-versions`}
|
key={`${collection.slug}-versions`}
|
||||||
path={`${adminRoute}/collections/${collection.slug}/:id/versions`}
|
path={`${adminRoute}/collections/${collection.slug}/:id/versions`}
|
||||||
>
|
>
|
||||||
{permissions?.readVersions?.permission ? (
|
{permissions?.readVersions?.permission ? (
|
||||||
<CustomCollectionComponent view="Versions" {...props} />
|
<CustomCollectionComponent view="Versions" {...props} />
|
||||||
) : (
|
) : (
|
||||||
<Unauthorized />
|
<Unauthorized />
|
||||||
)}
|
)}
|
||||||
</Route>
|
</Route>
|
||||||
<Route
|
<Route
|
||||||
exact
|
exact
|
||||||
key={`${collection.slug}-api`}
|
key={`${collection.slug}-api`}
|
||||||
path={`${adminRoute}/collections/${collection.slug}/:id/api`}
|
path={`${adminRoute}/collections/${collection.slug}/:id/api`}
|
||||||
>
|
>
|
||||||
{permissions?.read ? (
|
{permissions?.read ? <CustomCollectionComponent view="API" {...props} /> : <Unauthorized />}
|
||||||
<CustomCollectionComponent view="API" {...props} />
|
</Route>
|
||||||
) : (
|
<Route
|
||||||
<Unauthorized />
|
exact
|
||||||
)}
|
key={`${collection.slug}-view-version`}
|
||||||
</Route>
|
path={`${adminRoute}/collections/${collection.slug}/:id/versions/:versionID`}
|
||||||
<Route
|
>
|
||||||
exact
|
{permissions?.readVersions?.permission ? (
|
||||||
key={`${collection.slug}-view-version`}
|
<CustomCollectionComponent view="Version" {...props} />
|
||||||
path={`${adminRoute}/collections/${collection.slug}/:id/versions/:versionID`}
|
) : (
|
||||||
>
|
<Unauthorized />
|
||||||
{permissions?.readVersions?.permission ? (
|
)}
|
||||||
<CustomCollectionComponent view="Version" {...props} />
|
</Route>
|
||||||
) : (
|
<Route
|
||||||
<Unauthorized />
|
exact
|
||||||
)}
|
key={`${collection.slug}-live-preview`}
|
||||||
</Route>
|
path={`${adminRoute}/collections/${collection.slug}/:id/preview`}
|
||||||
<Route
|
>
|
||||||
exact
|
<CustomCollectionComponent view="LivePreview" {...props} />
|
||||||
key={`${collection.slug}-live-preview`}
|
</Route>
|
||||||
path={`${adminRoute}/collections/${collection.slug}/:id/preview`}
|
{collectionCustomRoutes({
|
||||||
>
|
collection,
|
||||||
<CustomCollectionComponent view="LivePreview" {...props} />
|
match,
|
||||||
</Route>
|
permissions,
|
||||||
{collectionCustomRoutes({
|
user,
|
||||||
collection,
|
})}
|
||||||
match,
|
<Route
|
||||||
permissions,
|
exact
|
||||||
user,
|
key={`${collection.slug}-view`}
|
||||||
})}
|
path={`${adminRoute}/collections/${collection.slug}/:id`}
|
||||||
<Route
|
>
|
||||||
exact
|
<CustomCollectionComponent view="Default" {...props} />
|
||||||
key={`${collection.slug}-view`}
|
</Route>
|
||||||
path={`${adminRoute}/collections/${collection.slug}/:id`}
|
<Route path={`${match.url}*`}>
|
||||||
>
|
<NotFound marginTop="large" />
|
||||||
<CustomCollectionComponent view="Default" {...props} />
|
</Route>
|
||||||
</Route>
|
</Switch>
|
||||||
<Route path={`${match.url}*`}>
|
)
|
||||||
<NotFound marginTop="large" />
|
|
||||||
</Route>
|
|
||||||
</Switch>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import { useEffect } from 'react'
|
|||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
|
|
||||||
import type { SanitizedCollectionConfig } from '../../../../../collections/config/types'
|
import type { SanitizedCollectionConfig } from '../../../../../collections/config/types'
|
||||||
|
import type { SanitizedGlobalConfig } from '../../../../../exports/types'
|
||||||
import type { StepNavItem } from '../../../elements/StepNav/types'
|
import type { StepNavItem } from '../../../elements/StepNav/types'
|
||||||
|
|
||||||
import { getTranslation } from '../../../../../utilities/getTranslation'
|
import { getTranslation } from '../../../../../utilities/getTranslation'
|
||||||
@@ -9,45 +10,96 @@ import useTitle from '../../../../hooks/useTitle'
|
|||||||
import { useStepNav } from '../../../elements/StepNav'
|
import { useStepNav } from '../../../elements/StepNav'
|
||||||
import { useConfig } from '../../../utilities/Config'
|
import { useConfig } from '../../../utilities/Config'
|
||||||
|
|
||||||
export const SetStepNav: React.FC<{
|
export const SetStepNav: React.FC<
|
||||||
collection: SanitizedCollectionConfig
|
| {
|
||||||
id: string
|
collection: SanitizedCollectionConfig
|
||||||
isEditing: boolean
|
id: string
|
||||||
}> = ({ id, collection, isEditing }) => {
|
isEditing: boolean
|
||||||
const {
|
}
|
||||||
admin: { useAsTitle },
|
| {
|
||||||
labels: { plural: pluralLabel },
|
global: SanitizedGlobalConfig
|
||||||
slug,
|
}
|
||||||
} = collection
|
> = (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 { setStepNav } = useStepNav()
|
||||||
|
|
||||||
const { i18n, t } = useTranslation('general')
|
const { i18n, t } = useTranslation('general')
|
||||||
|
|
||||||
const {
|
const {
|
||||||
routes: { admin },
|
routes: { admin },
|
||||||
} = useConfig()
|
} = useConfig()
|
||||||
|
|
||||||
const title = useTitle(collection)
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const nav: StepNavItem[] = [
|
const nav: StepNavItem[] = []
|
||||||
{
|
|
||||||
|
if (collection) {
|
||||||
|
nav.push({
|
||||||
label: getTranslation(pluralLabel, i18n),
|
label: getTranslation(pluralLabel, i18n),
|
||||||
url: `${admin}/collections/${slug}`,
|
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({
|
nav.push({
|
||||||
label: t('createNew'),
|
label: getTranslation(global.label, i18n),
|
||||||
|
url: `${admin}/globals/${slug}`,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
setStepNav(nav)
|
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
|
return null
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import { useHistory, useRouteMatch } from 'react-router-dom'
|
|||||||
|
|
||||||
import type { CollectionPermission } from '../../../../../auth'
|
import type { CollectionPermission } from '../../../../../auth'
|
||||||
import type { Fields } from '../../../forms/Form/types'
|
import type { Fields } from '../../../forms/Form/types'
|
||||||
|
import type { CollectionEditViewProps } from '../../types'
|
||||||
import type { IndexProps } from './types'
|
import type { IndexProps } from './types'
|
||||||
|
|
||||||
import usePayloadAPI from '../../../../hooks/usePayloadAPI'
|
import usePayloadAPI from '../../../../hooks/usePayloadAPI'
|
||||||
@@ -17,7 +18,6 @@ import RenderCustomComponent from '../../../utilities/RenderCustomComponent'
|
|||||||
import NotFound from '../../NotFound'
|
import NotFound from '../../NotFound'
|
||||||
import DefaultEdit from './Default'
|
import DefaultEdit from './Default'
|
||||||
import formatFields from './formatFields'
|
import formatFields from './formatFields'
|
||||||
import { EditViewProps } from '../../types'
|
|
||||||
|
|
||||||
const EditView: React.FC<IndexProps> = (props) => {
|
const EditView: React.FC<IndexProps> = (props) => {
|
||||||
const { collection: incomingCollection, isEditing } = props
|
const { collection: incomingCollection, isEditing } = props
|
||||||
@@ -125,7 +125,7 @@ const EditView: React.FC<IndexProps> = (props) => {
|
|||||||
|
|
||||||
const isLoading = !internalState || !docPermissions || isLoadingData
|
const isLoading = !internalState || !docPermissions || isLoadingData
|
||||||
|
|
||||||
const componentProps: EditViewProps = {
|
const componentProps: CollectionEditViewProps = {
|
||||||
id,
|
id,
|
||||||
action,
|
action,
|
||||||
apiURL,
|
apiURL,
|
||||||
|
|||||||
@@ -5,24 +5,25 @@ import type {
|
|||||||
SanitizedGlobalConfig,
|
SanitizedGlobalConfig,
|
||||||
} from '../../../exports/types'
|
} from '../../../exports/types'
|
||||||
|
|
||||||
export type EditViewProps = (
|
export type CollectionEditViewProps = BaseEditViewProps & {
|
||||||
| {
|
collection: SanitizedCollectionConfig
|
||||||
collection: SanitizedCollectionConfig
|
disableActions?: boolean
|
||||||
disableActions?: boolean
|
disableLeaveWithoutSaving?: boolean
|
||||||
disableLeaveWithoutSaving?: boolean
|
hasSavePermission: boolean
|
||||||
hasSavePermission: boolean
|
id: string
|
||||||
id: string
|
initialState?: Fields
|
||||||
initialState?: Fields
|
internalState: Fields
|
||||||
internalState: Fields
|
isEditing: boolean
|
||||||
isEditing: boolean
|
permissions: CollectionPermission
|
||||||
permissions: CollectionPermission
|
}
|
||||||
}
|
|
||||||
| {
|
export type GlobalEditViewProps = BaseEditViewProps & {
|
||||||
global: SanitizedGlobalConfig
|
global: SanitizedGlobalConfig
|
||||||
initialState: Fields
|
initialState: Fields
|
||||||
permissions: GlobalPermission
|
permissions: GlobalPermission
|
||||||
}
|
}
|
||||||
) & {
|
|
||||||
|
export type BaseEditViewProps = {
|
||||||
action: string
|
action: string
|
||||||
apiURL: string
|
apiURL: string
|
||||||
canAccessAdmin: boolean
|
canAccessAdmin: boolean
|
||||||
@@ -32,3 +33,5 @@ export type EditViewProps = (
|
|||||||
updatedAt: string
|
updatedAt: string
|
||||||
user: User
|
user: User
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type EditViewProps = CollectionEditViewProps | GlobalEditViewProps
|
||||||
|
|||||||
@@ -52,11 +52,20 @@ export const formatUseAsTitle = (args: {
|
|||||||
return title
|
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 { 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()
|
const config = useConfig()
|
||||||
|
|
||||||
|
if (!collection) return ''
|
||||||
|
|
||||||
return formatUseAsTitle({ collection, config, field, i18n })
|
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 { DocumentTab } from '../admin/components/elements/DocumentHeader/Tabs/types'
|
||||||
import type { RichTextAdapter } from '../admin/components/forms/field-types/RichText/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 { User } from '../auth/types'
|
||||||
import type { PayloadBundler } from '../bundlers/types'
|
import type { PayloadBundler } from '../bundlers/types'
|
||||||
import type {
|
import type {
|
||||||
@@ -241,7 +241,7 @@ export type EditViewConfig = {
|
|||||||
path: string
|
path: string
|
||||||
}
|
}
|
||||||
|
|
||||||
export type EditViewComponent = React.ComponentType<EditViewProps>
|
export type EditViewComponent = React.ComponentType<CollectionEditViewProps | GlobalEditViewProps>
|
||||||
|
|
||||||
export type EditView = EditViewComponent | EditViewConfig
|
export type EditView = EditViewComponent | EditViewConfig
|
||||||
|
|
||||||
|
|||||||
@@ -1,9 +1,10 @@
|
|||||||
import React, { Fragment, useEffect } from 'react'
|
import React, { Fragment, useEffect } from 'react'
|
||||||
import { Redirect } from 'react-router-dom'
|
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 { useStepNav } from '../../../../../packages/payload/src/admin/components/elements/StepNav'
|
||||||
import { useConfig } from '../../../../../packages/payload/src/admin/components/utilities/Config'
|
import { useConfig } from '../../../../../packages/payload/src/admin/components/utilities/Config'
|
||||||
import { EditViewComponent } from '../../../../../packages/payload/src/config/types'
|
|
||||||
|
|
||||||
const CustomDefaultView: EditViewComponent = ({
|
const CustomDefaultView: EditViewComponent = ({
|
||||||
canAccessAdmin,
|
canAccessAdmin,
|
||||||
|
|||||||
@@ -1,9 +1,10 @@
|
|||||||
import React, { Fragment, useEffect } from 'react'
|
import React, { Fragment, useEffect } from 'react'
|
||||||
import { Redirect } from 'react-router-dom'
|
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 { useStepNav } from '../../../../../packages/payload/src/admin/components/elements/StepNav'
|
||||||
import { useConfig } from '../../../../../packages/payload/src/admin/components/utilities/Config'
|
import { useConfig } from '../../../../../packages/payload/src/admin/components/utilities/Config'
|
||||||
import { EditViewComponent } from '../../../../../packages/payload/src/config/types'
|
|
||||||
|
|
||||||
const CustomEditView: EditViewComponent = ({
|
const CustomEditView: EditViewComponent = ({
|
||||||
canAccessAdmin,
|
canAccessAdmin,
|
||||||
|
|||||||
@@ -1,9 +1,10 @@
|
|||||||
import React, { Fragment, useEffect } from 'react'
|
import React, { Fragment, useEffect } from 'react'
|
||||||
import { Redirect } from 'react-router-dom'
|
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 { useStepNav } from '../../../../../packages/payload/src/admin/components/elements/StepNav'
|
||||||
import { useConfig } from '../../../../../packages/payload/src/admin/components/utilities/Config'
|
import { useConfig } from '../../../../../packages/payload/src/admin/components/utilities/Config'
|
||||||
import { EditViewComponent } from '../../../../../packages/payload/src/config/types'
|
|
||||||
|
|
||||||
const CustomVersionsView: EditViewComponent = ({
|
const CustomVersionsView: EditViewComponent = ({
|
||||||
canAccessAdmin,
|
canAccessAdmin,
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ export default buildConfigWithDefaults({
|
|||||||
slug: 'users',
|
slug: 'users',
|
||||||
auth: true,
|
auth: true,
|
||||||
admin: {
|
admin: {
|
||||||
useAsTitle: 'email',
|
useAsTitle: 'title',
|
||||||
},
|
},
|
||||||
fields: [],
|
fields: [],
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -9,21 +9,11 @@
|
|||||||
export interface Config {
|
export interface Config {
|
||||||
collections: {
|
collections: {
|
||||||
users: User
|
users: User
|
||||||
'hidden-collection': HiddenCollection
|
pages: Page
|
||||||
posts: Post
|
|
||||||
'group-one-collection-ones': GroupOneCollectionOne
|
|
||||||
'group-one-collection-twos': GroupOneCollectionTwo
|
|
||||||
'group-two-collection-ones': GroupTwoCollectionOne
|
|
||||||
'group-two-collection-twos': GroupTwoCollectionTwo
|
|
||||||
'payload-preferences': PayloadPreference
|
'payload-preferences': PayloadPreference
|
||||||
'payload-migrations': PayloadMigration
|
'payload-migrations': PayloadMigration
|
||||||
}
|
}
|
||||||
globals: {
|
globals: {}
|
||||||
'hidden-global': HiddenGlobal
|
|
||||||
global: Global
|
|
||||||
'group-globals-one': GroupGlobalsOne
|
|
||||||
'group-globals-two': GroupGlobalsTwo
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
export interface User {
|
export interface User {
|
||||||
id: string
|
id: string
|
||||||
@@ -38,52 +28,19 @@ export interface User {
|
|||||||
lockUntil?: string
|
lockUntil?: string
|
||||||
password?: string
|
password?: string
|
||||||
}
|
}
|
||||||
export interface HiddenCollection {
|
export interface Page {
|
||||||
id: string
|
id: string
|
||||||
title?: string
|
title: string
|
||||||
updatedAt: string
|
description: string
|
||||||
createdAt: string
|
slug: 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
|
|
||||||
updatedAt: string
|
updatedAt: string
|
||||||
createdAt: string
|
createdAt: string
|
||||||
}
|
}
|
||||||
export interface PayloadPreference {
|
export interface PayloadPreference {
|
||||||
id: string
|
id: string
|
||||||
user: {
|
user: {
|
||||||
value: string | User
|
|
||||||
relationTo: 'users'
|
relationTo: 'users'
|
||||||
|
value: string | User
|
||||||
}
|
}
|
||||||
key?: string
|
key?: string
|
||||||
value?:
|
value?:
|
||||||
@@ -114,27 +71,14 @@ export interface PayloadMigration {
|
|||||||
updatedAt: string
|
updatedAt: string
|
||||||
createdAt: string
|
createdAt: string
|
||||||
}
|
}
|
||||||
export interface HiddenGlobal {
|
|
||||||
id: string
|
declare module 'payload' {
|
||||||
title?: string
|
export interface GeneratedTypes {
|
||||||
updatedAt?: string
|
collections: {
|
||||||
createdAt?: string
|
users: User
|
||||||
}
|
pages: Page
|
||||||
export interface Global {
|
'payload-preferences': PayloadPreference
|
||||||
id: string
|
'payload-migrations': PayloadMigration
|
||||||
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
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user