chore(next): ssr globals view (#4640)
This commit is contained in:
@@ -0,0 +1,11 @@
|
||||
/* THIS FILE WAS GENERATED AUTOMATICALLY BY PAYLOAD. */
|
||||
/* DO NOT MODIFY IT BECAUSE IT COULD BE REWRITTEN AT ANY TIME. */
|
||||
import { Global } from '@payloadcms/next/pages/Global'
|
||||
import config from 'payload-config'
|
||||
|
||||
export default ({ params, searchParams }) =>
|
||||
Global({
|
||||
globalSlug: params.global,
|
||||
searchParams,
|
||||
config,
|
||||
})
|
||||
10
packages/dev/src/collections/Users.ts
Normal file
10
packages/dev/src/collections/Users.ts
Normal file
@@ -0,0 +1,10 @@
|
||||
import { CollectionConfig } from 'payload/types'
|
||||
|
||||
export const Users: CollectionConfig = {
|
||||
slug: 'users',
|
||||
auth: true,
|
||||
admin: {
|
||||
useAsTitle: 'email',
|
||||
},
|
||||
fields: [],
|
||||
}
|
||||
11
packages/dev/src/globals/Settings.ts
Normal file
11
packages/dev/src/globals/Settings.ts
Normal file
@@ -0,0 +1,11 @@
|
||||
import { GlobalConfig } from 'payload/types'
|
||||
|
||||
export const Settings: GlobalConfig = {
|
||||
slug: 'settings',
|
||||
fields: [
|
||||
{
|
||||
name: 'title',
|
||||
type: 'text',
|
||||
},
|
||||
],
|
||||
}
|
||||
@@ -2,6 +2,8 @@ import { mongooseAdapter } from '@payloadcms/db-mongodb'
|
||||
// import { postgresAdapter } from '@payloadcms/db-postgres'
|
||||
// import { lexicalEditor } from '@payloadcms/richtext-lexical'
|
||||
import { buildConfig } from 'payload/config'
|
||||
import { Users } from './collections/Users'
|
||||
import { Settings } from './globals/Settings'
|
||||
|
||||
export default buildConfig({
|
||||
db: mongooseAdapter({
|
||||
@@ -14,6 +16,8 @@ export default buildConfig({
|
||||
// }),
|
||||
// editor: lexicalEditor({}),
|
||||
secret: process.env.PAYLOAD_SECRET,
|
||||
collections: [Users],
|
||||
globals: [Settings],
|
||||
// onInit: async (payload) => {
|
||||
// await payload.create({
|
||||
// collection: 'users',
|
||||
|
||||
@@ -41,6 +41,8 @@ export const Account = async ({
|
||||
const collectionConfig = config.collections.find((collection) => collection.slug === userSlug)
|
||||
|
||||
if (collectionConfig) {
|
||||
const { fields } = collectionConfig
|
||||
|
||||
let data: TypeWithID & Record<string, unknown>
|
||||
|
||||
try {
|
||||
@@ -54,7 +56,7 @@ export const Account = async ({
|
||||
return notFound()
|
||||
}
|
||||
|
||||
const fieldSchema = formatFields(collectionConfig, true)
|
||||
const fieldSchema = formatFields(fields, true)
|
||||
|
||||
let preferencesKey: string
|
||||
|
||||
@@ -79,7 +81,7 @@ export const Account = async ({
|
||||
|
||||
const state = await buildStateFromSchema({
|
||||
id: user?.id,
|
||||
config: collectionConfig,
|
||||
config,
|
||||
data: data || {},
|
||||
fieldSchema,
|
||||
locale,
|
||||
|
||||
@@ -4,7 +4,7 @@ import { initPage } from '../../utilities/initPage'
|
||||
import {
|
||||
EditDepthProvider,
|
||||
RenderCustomComponent,
|
||||
DefaultEdit,
|
||||
DefaultEditView,
|
||||
DefaultEditViewProps,
|
||||
findLocaleFromCode,
|
||||
fieldTypes,
|
||||
@@ -45,6 +45,7 @@ export const CollectionEdit = async ({
|
||||
if (collectionConfig) {
|
||||
const {
|
||||
admin: { components: { views: { Edit: CustomEdit } = {} } = {} },
|
||||
fields,
|
||||
} = collectionConfig
|
||||
|
||||
let data: TypeWithID & Record<string, unknown>
|
||||
@@ -67,7 +68,7 @@ export const CollectionEdit = async ({
|
||||
|
||||
const collectionPermissions = permissions?.collections?.[collectionSlug]
|
||||
|
||||
const fieldSchema = formatFields(collectionConfig, isEditing)
|
||||
const fieldSchema = formatFields(fields, isEditing)
|
||||
|
||||
let preferencesKey: string
|
||||
|
||||
@@ -92,7 +93,7 @@ export const CollectionEdit = async ({
|
||||
|
||||
const state = await buildStateFromSchema({
|
||||
id,
|
||||
config: collectionConfig,
|
||||
config,
|
||||
data: data || {},
|
||||
fieldSchema,
|
||||
locale,
|
||||
@@ -125,13 +126,12 @@ export const CollectionEdit = async ({
|
||||
hasSavePermission:
|
||||
(isEditing && collectionPermissions?.update?.permission) ||
|
||||
(!isEditing && collectionPermissions?.create?.permission),
|
||||
internalState: state,
|
||||
initialState: state,
|
||||
isEditing,
|
||||
permissions: collectionPermissions,
|
||||
updatedAt: data?.updatedAt.toString(),
|
||||
user,
|
||||
onSave: () => {},
|
||||
isLoading: false,
|
||||
}
|
||||
|
||||
return (
|
||||
@@ -141,7 +141,7 @@ export const CollectionEdit = async ({
|
||||
<FormQueryParamsProvider formQueryParams={formQueryParams}>
|
||||
<RenderCustomComponent
|
||||
CustomComponent={typeof CustomEdit === 'function' ? CustomEdit : undefined}
|
||||
DefaultComponent={DefaultEdit}
|
||||
DefaultComponent={DefaultEditView}
|
||||
componentProps={componentProps}
|
||||
/>
|
||||
</FormQueryParamsProvider>
|
||||
|
||||
153
packages/next/src/pages/Global/index.tsx
Normal file
153
packages/next/src/pages/Global/index.tsx
Normal file
@@ -0,0 +1,153 @@
|
||||
import { SanitizedConfig, TypeWithID } from 'payload/types'
|
||||
import React, { Fragment } from 'react'
|
||||
import { initPage } from '../../utilities/initPage'
|
||||
import {
|
||||
EditDepthProvider,
|
||||
RenderCustomComponent,
|
||||
DefaultGlobalViewProps,
|
||||
findLocaleFromCode,
|
||||
DefaultGlobalView,
|
||||
fieldTypes,
|
||||
buildStateFromSchema,
|
||||
formatFields,
|
||||
FormQueryParamsProvider,
|
||||
QueryParamTypes,
|
||||
HydrateClientUser,
|
||||
} from '@payloadcms/ui'
|
||||
import { notFound } from 'next/navigation'
|
||||
import { Metadata } from 'next'
|
||||
import { meta } from '../../utilities/meta'
|
||||
// import i18n from 'i18next'
|
||||
// import { getTranslation } from 'payload/utilities'
|
||||
|
||||
export const generateMetadata = async ({
|
||||
config,
|
||||
}: {
|
||||
config: Promise<SanitizedConfig>
|
||||
}): Promise<Metadata> =>
|
||||
meta({
|
||||
// title: getTranslation(label, i18n),
|
||||
// description: getTranslation(label, i18n),
|
||||
// keywords: `${getTranslation(label, i18n)}, Payload, CMS`,
|
||||
title: '',
|
||||
description: '',
|
||||
keywords: '',
|
||||
config,
|
||||
})
|
||||
|
||||
export const Global = async ({
|
||||
globalSlug,
|
||||
config: configPromise,
|
||||
searchParams,
|
||||
}: {
|
||||
globalSlug: string
|
||||
config: Promise<SanitizedConfig>
|
||||
searchParams: { [key: string]: string | string[] | undefined }
|
||||
}) => {
|
||||
const { config, payload, permissions, user } = await initPage(configPromise, true)
|
||||
|
||||
const {
|
||||
routes: { api },
|
||||
serverURL,
|
||||
localization,
|
||||
} = config
|
||||
|
||||
const globalConfig = config.globals.find((global) => global.slug === globalSlug)
|
||||
|
||||
if (globalConfig) {
|
||||
const {
|
||||
admin: { components: { views: { Edit: CustomEdit } = {} } = {} },
|
||||
fields,
|
||||
} = globalConfig
|
||||
|
||||
let data: TypeWithID & Record<string, unknown>
|
||||
|
||||
try {
|
||||
data = await payload.findGlobal({
|
||||
slug: globalSlug,
|
||||
depth: 0,
|
||||
user,
|
||||
})
|
||||
} catch (error) {}
|
||||
|
||||
const defaultLocale =
|
||||
localization && localization.defaultLocale ? localization.defaultLocale : 'en'
|
||||
|
||||
const localeCode = (searchParams?.locale as string) || defaultLocale
|
||||
|
||||
const locale = localization && findLocaleFromCode(localization, localeCode)
|
||||
|
||||
const globalPermission = permissions?.globals?.[globalSlug]
|
||||
|
||||
const fieldSchema = formatFields(fields, true)
|
||||
|
||||
const preferencesKey = `global-${globalSlug}`
|
||||
|
||||
const {
|
||||
docs: [preferences],
|
||||
} = await payload.find({
|
||||
collection: 'payload-preferences',
|
||||
depth: 0,
|
||||
pagination: false,
|
||||
user,
|
||||
limit: 1,
|
||||
where: {
|
||||
key: {
|
||||
equals: preferencesKey,
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
const state = await buildStateFromSchema({
|
||||
config,
|
||||
data: data || {},
|
||||
fieldSchema,
|
||||
locale,
|
||||
operation: 'update',
|
||||
preferences,
|
||||
// t,
|
||||
user,
|
||||
})
|
||||
|
||||
const formQueryParams: QueryParamTypes = {
|
||||
depth: 0,
|
||||
'fallback-locale': 'null',
|
||||
locale: '',
|
||||
uploadEdits: undefined,
|
||||
}
|
||||
|
||||
const componentProps: DefaultGlobalViewProps = {
|
||||
action: `${serverURL}${api}/globals/${globalSlug}?locale=${locale}&fallback-locale=null`,
|
||||
apiURL: `${serverURL}${api}/globals/${globalSlug}?locale=${locale}${
|
||||
global.versions?.drafts ? '&draft=true' : ''
|
||||
}`,
|
||||
canAccessAdmin: permissions?.canAccessAdmin,
|
||||
config,
|
||||
globalConfig,
|
||||
data,
|
||||
fieldTypes,
|
||||
initialState: state,
|
||||
permissions: globalPermission,
|
||||
updatedAt: data?.updatedAt?.toString(),
|
||||
user,
|
||||
onSave: () => {},
|
||||
}
|
||||
|
||||
return (
|
||||
<Fragment>
|
||||
<HydrateClientUser user={user} />
|
||||
<EditDepthProvider depth={1}>
|
||||
<FormQueryParamsProvider formQueryParams={formQueryParams}>
|
||||
<RenderCustomComponent
|
||||
CustomComponent={typeof CustomEdit === 'function' ? CustomEdit : undefined}
|
||||
DefaultComponent={DefaultGlobalView}
|
||||
componentProps={componentProps}
|
||||
/>
|
||||
</FormQueryParamsProvider>
|
||||
</EditDepthProvider>
|
||||
</Fragment>
|
||||
)
|
||||
}
|
||||
|
||||
return notFound()
|
||||
}
|
||||
@@ -1,11 +1,11 @@
|
||||
import React, { useEffect } from 'react'
|
||||
import React from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
|
||||
import Button from '../../elements/Button'
|
||||
import { Button } from '../../elements/Button'
|
||||
import { Gutter } from '../../elements/Gutter'
|
||||
import { useStepNav } from '../../elements/StepNav'
|
||||
import { useConfig } from '../../utilities/Config'
|
||||
import Meta from '../../utilities/Meta'
|
||||
import { useConfig } from '../../providers/Config'
|
||||
// import Meta from '../../utilities/Meta'
|
||||
import './index.scss'
|
||||
|
||||
const baseClass = 'not-found'
|
||||
@@ -21,15 +21,13 @@ const NotFound: React.FC<{
|
||||
routes: { admin },
|
||||
} = useConfig()
|
||||
|
||||
const { t } = useTranslation('general')
|
||||
|
||||
useEffect(() => {
|
||||
setStepNav([
|
||||
{
|
||||
label: t('notFound'),
|
||||
},
|
||||
])
|
||||
}, [setStepNav, t])
|
||||
// useEffect(() => {
|
||||
// setStepNav([
|
||||
// {
|
||||
// label: t('notFound'),
|
||||
// },
|
||||
// ])
|
||||
// }, [setStepNav, t])
|
||||
|
||||
return (
|
||||
<div
|
||||
@@ -37,16 +35,23 @@ const NotFound: React.FC<{
|
||||
.filter(Boolean)
|
||||
.join(' ')}
|
||||
>
|
||||
<Meta
|
||||
{/* <Meta
|
||||
description={t('pageNotFound')}
|
||||
keywords={`404 ${t('notFound')}`}
|
||||
title={t('notFound')}
|
||||
/>
|
||||
/> */}
|
||||
<Gutter className={`${baseClass}__wrap`}>
|
||||
<h1>{t('nothingFound')}</h1>
|
||||
<p>{t('sorryNotFound')}</p>
|
||||
<h1>
|
||||
Nothing Found
|
||||
{/* {t('nothingFound')} */}
|
||||
</h1>
|
||||
<p>
|
||||
Sorry, we couldn't find what you were looking for.
|
||||
{/* {t('sorryNotFound')} */}
|
||||
</p>
|
||||
<Button className={`${baseClass}__button`} el="link" to={`${admin}`}>
|
||||
{t('backToDashboard')}
|
||||
Back to Dashboard
|
||||
{/* {t('backToDashboard')} */}
|
||||
</Button>
|
||||
</Gutter>
|
||||
</div>
|
||||
@@ -1,96 +0,0 @@
|
||||
import React, { useEffect } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
|
||||
import type { FieldTypes } from '../../forms/field-types'
|
||||
import type { GlobalEditViewProps } from '../types'
|
||||
|
||||
import { getTranslation } from '../../../../utilities/getTranslation'
|
||||
import { DocumentHeader } from '../../elements/DocumentHeader'
|
||||
import { FormLoadingOverlayToggle } from '../../elements/Loading'
|
||||
import Form from '../../forms/Form'
|
||||
import { useActions } from '../../utilities/ActionsProvider'
|
||||
import { OperationContext } from '../../utilities/OperationProvider'
|
||||
import { SetStepNav } from '../collections/Edit/SetStepNav'
|
||||
import { GlobalRoutes } from './Routes'
|
||||
import { CustomGlobalComponent } from './Routes/CustomComponent'
|
||||
import './index.scss'
|
||||
|
||||
const baseClass = 'global-edit'
|
||||
|
||||
export type DefaultGlobalViewProps = GlobalEditViewProps & {
|
||||
disableRoutes?: boolean
|
||||
fieldTypes: FieldTypes
|
||||
}
|
||||
|
||||
const DefaultGlobalView: React.FC<DefaultGlobalViewProps> = (props) => {
|
||||
const { i18n } = useTranslation('general')
|
||||
|
||||
const {
|
||||
action,
|
||||
apiURL,
|
||||
data,
|
||||
disableRoutes,
|
||||
fieldTypes,
|
||||
global,
|
||||
initialState,
|
||||
isLoading,
|
||||
onSave,
|
||||
permissions,
|
||||
} = props
|
||||
|
||||
const { setViewActions } = useActions()
|
||||
|
||||
const { label } = global
|
||||
|
||||
const hasSavePermission = permissions?.update?.permission
|
||||
|
||||
useEffect(() => {
|
||||
const path = location.pathname
|
||||
|
||||
if (!path.endsWith(global.slug)) {
|
||||
return
|
||||
}
|
||||
|
||||
const editConfig = global?.admin?.components?.views?.Edit
|
||||
const defaultActions =
|
||||
editConfig && 'Default' in editConfig && 'actions' in editConfig.Default
|
||||
? editConfig.Default.actions
|
||||
: []
|
||||
|
||||
setViewActions(defaultActions)
|
||||
}, [global.slug, location.pathname, global?.admin?.components?.views?.Edit, setViewActions])
|
||||
|
||||
return (
|
||||
<main className={baseClass}>
|
||||
<OperationContext.Provider value="update">
|
||||
<SetStepNav global={global} />
|
||||
<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} fieldTypes={fieldTypes} />
|
||||
)}
|
||||
</React.Fragment>
|
||||
)}
|
||||
</Form>
|
||||
</OperationContext.Provider>
|
||||
</main>
|
||||
)
|
||||
}
|
||||
|
||||
export default DefaultGlobalView
|
||||
@@ -1,154 +0,0 @@
|
||||
import React, { useCallback, useEffect, useState } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { useLocation } from 'react-router-dom'
|
||||
|
||||
import type { Fields } from '../../forms/Form/types'
|
||||
import type { DefaultGlobalViewProps } from './Default'
|
||||
import type { IndexProps } from './types'
|
||||
|
||||
import usePayloadAPI from '../../../hooks/usePayloadAPI'
|
||||
import buildStateFromSchema from '../../forms/Form/buildStateFromSchema'
|
||||
import { fieldTypes } from '../../forms/field-types'
|
||||
import { useAuth } from '../../utilities/Auth'
|
||||
import { useConfig } from '../../utilities/Config'
|
||||
import { useDocumentEvents } from '../../utilities/DocumentEvents'
|
||||
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'
|
||||
|
||||
const GlobalView: React.FC<IndexProps> = (props) => {
|
||||
const { global } = props
|
||||
|
||||
const { state: locationState } = useLocation<{ data?: Record<string, unknown> }>()
|
||||
const { code: locale } = useLocale()
|
||||
const { permissions, user } = useAuth()
|
||||
const [initialState, setInitialState] = useState<Fields>()
|
||||
const [updatedAt, setUpdatedAt] = useState<string>()
|
||||
const { docPermissions, getDocPermissions, getDocPreferences, getVersions, preferencesKey } =
|
||||
useDocumentInfo()
|
||||
const { getPreference } = usePreferences()
|
||||
const { t } = useTranslation()
|
||||
const config = useConfig()
|
||||
|
||||
const {
|
||||
routes: { api },
|
||||
serverURL,
|
||||
} = useConfig()
|
||||
|
||||
const { reportUpdate } = useDocumentEvents()
|
||||
|
||||
const { admin: { components: { views: { Edit: Edit } = {} } = {} } = {}, fields, slug } = global
|
||||
|
||||
const onSave = useCallback(
|
||||
async (json) => {
|
||||
reportUpdate({
|
||||
entitySlug: global.slug,
|
||||
updatedAt: json?.result?.updatedAt || new Date().toISOString(),
|
||||
})
|
||||
|
||||
getVersions()
|
||||
getDocPermissions()
|
||||
setUpdatedAt(json?.result?.updatedAt)
|
||||
|
||||
const preferences = await getDocPreferences()
|
||||
|
||||
const state = await buildStateFromSchema({
|
||||
config,
|
||||
data: json.result,
|
||||
fieldSchema: fields,
|
||||
locale,
|
||||
operation: 'update',
|
||||
preferences,
|
||||
t,
|
||||
user,
|
||||
})
|
||||
setInitialState(state)
|
||||
},
|
||||
[
|
||||
getVersions,
|
||||
fields,
|
||||
user,
|
||||
locale,
|
||||
t,
|
||||
getDocPermissions,
|
||||
getDocPreferences,
|
||||
config,
|
||||
global,
|
||||
reportUpdate,
|
||||
],
|
||||
)
|
||||
|
||||
const [{ data, isLoading: isLoadingData }] = usePayloadAPI(`${serverURL}${api}/globals/${slug}`, {
|
||||
initialData: null,
|
||||
initialParams: { depth: 0, draft: 'true', 'fallback-locale': 'null' },
|
||||
})
|
||||
|
||||
const dataToRender = locationState?.data || data
|
||||
|
||||
useEffect(() => {
|
||||
const awaitInitialState = async () => {
|
||||
const preferences = await getDocPreferences()
|
||||
const state = await buildStateFromSchema({
|
||||
config,
|
||||
data: dataToRender,
|
||||
fieldSchema: fields,
|
||||
locale,
|
||||
operation: 'update',
|
||||
preferences,
|
||||
t,
|
||||
user,
|
||||
})
|
||||
|
||||
if (preferencesKey) {
|
||||
await getPreference(preferencesKey)
|
||||
}
|
||||
|
||||
setInitialState(state)
|
||||
}
|
||||
|
||||
if (dataToRender) awaitInitialState()
|
||||
}, [
|
||||
dataToRender,
|
||||
fields,
|
||||
user,
|
||||
locale,
|
||||
getPreference,
|
||||
preferencesKey,
|
||||
t,
|
||||
getDocPreferences,
|
||||
config,
|
||||
])
|
||||
|
||||
const isLoading = !initialState || !docPermissions || isLoadingData
|
||||
|
||||
const componentProps: DefaultGlobalViewProps = {
|
||||
action: `${serverURL}${api}/globals/${slug}?locale=${locale}&fallback-locale=null`,
|
||||
apiURL: `${serverURL}${api}/globals/${slug}?locale=${locale}${
|
||||
global.versions?.drafts ? '&draft=true' : ''
|
||||
}`,
|
||||
canAccessAdmin: permissions?.canAccessAdmin,
|
||||
data: dataToRender,
|
||||
fieldTypes,
|
||||
global,
|
||||
initialState,
|
||||
isLoading,
|
||||
onSave,
|
||||
permissions: docPermissions,
|
||||
updatedAt: updatedAt || dataToRender?.updatedAt,
|
||||
user,
|
||||
}
|
||||
|
||||
return (
|
||||
<EditDepthContext.Provider value={1}>
|
||||
<RenderCustomComponent
|
||||
CustomComponent={typeof Edit === 'function' ? Edit : undefined}
|
||||
DefaultComponent={DefaultGlobalView}
|
||||
componentProps={componentProps}
|
||||
/>
|
||||
</EditDepthContext.Provider>
|
||||
)
|
||||
}
|
||||
export default GlobalView
|
||||
@@ -1,5 +0,0 @@
|
||||
import type { SanitizedGlobalConfig } from '../../../../globals/config/types'
|
||||
|
||||
export type IndexProps = {
|
||||
global: SanitizedGlobalConfig
|
||||
}
|
||||
@@ -28,12 +28,12 @@ export const DocumentControls: React.FC<{
|
||||
apiURL: string
|
||||
data?: any
|
||||
disableActions?: boolean
|
||||
global?: SanitizedGlobalConfig
|
||||
globalConfig?: SanitizedGlobalConfig
|
||||
hasSavePermission?: boolean
|
||||
id?: string
|
||||
isAccountView?: boolean
|
||||
isEditing?: boolean
|
||||
permissions?: CollectionPermission | GlobalPermission | null
|
||||
permissions: CollectionPermission | GlobalPermission | null
|
||||
config: SanitizedConfig
|
||||
collectionConfig?: SanitizedCollectionConfig
|
||||
}> = (props) => {
|
||||
@@ -43,7 +43,7 @@ export const DocumentControls: React.FC<{
|
||||
collectionConfig,
|
||||
data,
|
||||
disableActions,
|
||||
global,
|
||||
globalConfig,
|
||||
hasSavePermission,
|
||||
isAccountView,
|
||||
isEditing,
|
||||
|
||||
@@ -22,7 +22,7 @@ import { useFormQueryParams } from '../../providers/FormQueryParams'
|
||||
import { useLocale } from '../../providers/Locale'
|
||||
import { RenderCustomComponent } from '../../elements/RenderCustomComponent'
|
||||
// import DefaultEdit from '../../views/collections/Edit/Default'
|
||||
import formatFields from '../../utilities/formatFields'
|
||||
import { formatFields } from '../../utilities/formatFields'
|
||||
import { Button } from '../Button'
|
||||
import IDLabel from '../IDLabel'
|
||||
|
||||
@@ -32,10 +32,13 @@ const Content: React.FC<DocumentDrawerProps> = ({
|
||||
drawerSlug,
|
||||
onSave,
|
||||
}) => {
|
||||
const config = useConfig()
|
||||
|
||||
const {
|
||||
routes: { api },
|
||||
serverURL,
|
||||
} = useConfig()
|
||||
} = config
|
||||
|
||||
const { closeModal, modalState, toggleModal } = useModal()
|
||||
const { code: locale } = useLocale()
|
||||
const { user } = useAuth()
|
||||
@@ -44,11 +47,11 @@ const Content: React.FC<DocumentDrawerProps> = ({
|
||||
const hasInitializedState = useRef(false)
|
||||
const [isOpen, setIsOpen] = useState(false)
|
||||
const [collectionConfig] = useRelatedCollections(collectionSlug)
|
||||
const config = useConfig()
|
||||
const { formQueryParams } = useFormQueryParams()
|
||||
const formattedQueryParams = queryString.stringify(formQueryParams)
|
||||
|
||||
const { admin: { components: { views: { Edit } = {} } = {} } = {} } = collectionConfig
|
||||
const { admin: { components: { views: { Edit } = {} } = {} } = {}, fields: fieldsFromConfig } =
|
||||
collectionConfig
|
||||
|
||||
const { id, docPermissions, getDocPreferences } = useDocumentInfo()
|
||||
|
||||
@@ -68,7 +71,7 @@ const Content: React.FC<DocumentDrawerProps> = ({
|
||||
? Edit.Default.Component
|
||||
: undefined
|
||||
|
||||
const [fields, setFields] = useState(() => formatFields(collectionConfig, true))
|
||||
const [fields, setFields] = useState(() => formatFields(fieldsFromConfig, true))
|
||||
|
||||
// no need to an additional requests when creating new documents
|
||||
const initialID = useRef(id)
|
||||
@@ -78,7 +81,7 @@ const Content: React.FC<DocumentDrawerProps> = ({
|
||||
)
|
||||
|
||||
useEffect(() => {
|
||||
setFields(formatFields(collectionConfig, true))
|
||||
setFields(formatFields(fields, true))
|
||||
}, [collectionSlug, collectionConfig])
|
||||
|
||||
useEffect(() => {
|
||||
|
||||
@@ -16,9 +16,9 @@ export const DocumentTab: React.FC<DocumentTabProps & DocumentTabConfig> = (prop
|
||||
const {
|
||||
id,
|
||||
apiURL,
|
||||
collection,
|
||||
collectionSlug,
|
||||
condition,
|
||||
global,
|
||||
globalSlug,
|
||||
href: tabHref,
|
||||
isActive: checkIsActive,
|
||||
label,
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import type { SanitizedCollectionConfig, SanitizedGlobalConfig } from 'payload/types'
|
||||
import type { EditViewConfig } from 'payload/config'
|
||||
|
||||
import { defaultGlobalViews } from '../../../views/Global/Routes/CustomComponent'
|
||||
import { defaultGlobalViews } from '../../../views/Global/RenderCustomView'
|
||||
import { defaultCollectionViews } from '../../../views/collections/Edit/Routes/CustomComponent'
|
||||
|
||||
export const getCustomViews = (args: {
|
||||
|
||||
@@ -2,30 +2,30 @@ import type { SanitizedCollectionConfig, SanitizedGlobalConfig } from 'payload/t
|
||||
import { EditViewConfig } from 'payload/config'
|
||||
|
||||
export const getViewConfig = (args: {
|
||||
collection: SanitizedCollectionConfig
|
||||
global: SanitizedGlobalConfig
|
||||
collectionConfig: SanitizedCollectionConfig
|
||||
globalConfig: SanitizedGlobalConfig
|
||||
name: string
|
||||
}): EditViewConfig => {
|
||||
const { name, collection, global } = args
|
||||
const { name, collectionConfig, globalConfig } = args
|
||||
|
||||
if (collection) {
|
||||
const collectionViewsConfig =
|
||||
typeof collection?.admin?.components?.views?.Edit === 'object' &&
|
||||
typeof collection?.admin?.components?.views?.Edit !== 'function'
|
||||
? collection?.admin?.components?.views?.Edit
|
||||
if (collectionConfig) {
|
||||
const collectionConfigViewsConfig =
|
||||
typeof collectionConfig?.admin?.components?.views?.Edit === 'object' &&
|
||||
typeof collectionConfig?.admin?.components?.views?.Edit !== 'function'
|
||||
? collectionConfig?.admin?.components?.views?.Edit
|
||||
: undefined
|
||||
|
||||
return collectionViewsConfig?.[name]
|
||||
return collectionConfigViewsConfig?.[name]
|
||||
}
|
||||
|
||||
if (global) {
|
||||
const globalViewsConfig =
|
||||
typeof global?.admin?.components?.views?.Edit === 'object' &&
|
||||
typeof global?.admin?.components?.views?.Edit !== 'function'
|
||||
? global?.admin?.components?.views?.Edit
|
||||
if (globalConfig) {
|
||||
const globalConfigViewsConfig =
|
||||
typeof globalConfig?.admin?.components?.views?.Edit === 'object' &&
|
||||
typeof globalConfig?.admin?.components?.views?.Edit !== 'function'
|
||||
? globalConfig?.admin?.components?.views?.Edit
|
||||
: undefined
|
||||
|
||||
return globalViewsConfig?.[name]
|
||||
return globalConfigViewsConfig?.[name]
|
||||
}
|
||||
|
||||
return null
|
||||
|
||||
@@ -11,11 +11,11 @@ import { tabs as defaultViews } from './tabs'
|
||||
const baseClass = 'doc-tabs'
|
||||
|
||||
export const DocumentTabs: React.FC<DocumentTabProps> = (props) => {
|
||||
const { collection, global, isEditing } = props
|
||||
const { collectionConfig, globalConfig, isEditing } = props
|
||||
// const customViews = getCustomViews({ collection, global })
|
||||
|
||||
// Don't show tabs when creating new documents
|
||||
if ((collection && isEditing) || global) {
|
||||
if ((collectionConfig && isEditing) || global) {
|
||||
return (
|
||||
<div className={baseClass}>
|
||||
<div className={`${baseClass}__tabs-container`}>
|
||||
@@ -31,19 +31,21 @@ export const DocumentTabs: React.FC<DocumentTabProps> = (props) => {
|
||||
return a.order - b.order
|
||||
})
|
||||
?.map(([name, Tab], index) => {
|
||||
const viewConfig = getViewConfig({ name, collection, global })
|
||||
const viewConfig = getViewConfig({ name, collectionConfig, globalConfig })
|
||||
const tabOverrides = viewConfig && 'Tab' in viewConfig ? viewConfig.Tab : undefined
|
||||
|
||||
return (
|
||||
<DocumentTab
|
||||
{...{
|
||||
// ...props,
|
||||
...(Tab || {}),
|
||||
...(tabOverrides || {}),
|
||||
}}
|
||||
key={`tab-${index}`}
|
||||
/>
|
||||
)
|
||||
return null
|
||||
|
||||
// return (
|
||||
// <DocumentTab
|
||||
// {...{
|
||||
// // ...props,
|
||||
// ...(Tab || {}),
|
||||
// ...(tabOverrides || {}),
|
||||
// }}
|
||||
// key={`tab-${index}`}
|
||||
// />
|
||||
// )
|
||||
})}
|
||||
{/* {customViews?.map((CustomView, index) => {
|
||||
if ('Tab' in CustomView) {
|
||||
|
||||
@@ -8,17 +8,17 @@ import type { ContextType } from '../../../providers/DocumentInfo/types'
|
||||
|
||||
export type DocumentTabProps = {
|
||||
apiURL?: string
|
||||
collection?: SanitizedCollectionConfig
|
||||
global?: SanitizedGlobalConfig
|
||||
collectionConfig?: SanitizedCollectionConfig
|
||||
globalConfig?: SanitizedGlobalConfig
|
||||
id: string
|
||||
isEditing?: boolean
|
||||
}
|
||||
|
||||
export type DocumentTabCondition = (args: {
|
||||
collection: SanitizedCollectionConfig
|
||||
collectionConfig: SanitizedCollectionConfig
|
||||
config: Config
|
||||
documentInfo: ContextType
|
||||
global: SanitizedGlobalConfig
|
||||
globalConfig: SanitizedGlobalConfig
|
||||
}) => boolean
|
||||
|
||||
// Everything is optional because we merge in the defaults
|
||||
|
||||
@@ -14,11 +14,11 @@ export const DocumentHeader: React.FC<{
|
||||
collectionConfig?: SanitizedCollectionConfig
|
||||
customHeader?: React.ReactNode
|
||||
data?: any
|
||||
global?: SanitizedGlobalConfig
|
||||
globalConfig?: SanitizedGlobalConfig
|
||||
id?: string
|
||||
isEditing?: boolean
|
||||
}> = (props) => {
|
||||
const { id, apiURL, collectionConfig, customHeader, data, global, isEditing } = props
|
||||
const { id, apiURL, collectionConfig, customHeader, data, globalConfig, isEditing } = props
|
||||
|
||||
return (
|
||||
<Gutter className={baseClass}>
|
||||
@@ -28,16 +28,15 @@ export const DocumentHeader: React.FC<{
|
||||
<RenderTitle
|
||||
className={`${baseClass}__title`}
|
||||
useAsTitle={collectionConfig?.admin?.useAsTitle}
|
||||
globalLabel={global?.label}
|
||||
globalSlug={global?.slug}
|
||||
globalLabel={globalConfig?.label}
|
||||
globalSlug={globalConfig?.slug}
|
||||
data={data}
|
||||
// fallback={`[${t('untitled')}]`}
|
||||
global={global}
|
||||
/>
|
||||
<DocumentTabs
|
||||
apiURL={apiURL}
|
||||
// collection={collectionConfig}
|
||||
global={global}
|
||||
globalConfig={globalConfig}
|
||||
id={id}
|
||||
isEditing={isEditing}
|
||||
/>
|
||||
|
||||
@@ -18,7 +18,6 @@ const RenderTitle: React.FC<Props> = (props) => {
|
||||
data,
|
||||
element = 'h1',
|
||||
fallback = '[untitled]',
|
||||
global,
|
||||
title: titleFromProps,
|
||||
} = props
|
||||
|
||||
|
||||
@@ -10,6 +10,5 @@ export type Props = {
|
||||
}
|
||||
element?: React.ElementType
|
||||
fallback?: string
|
||||
global?: SanitizedGlobalConfig
|
||||
title?: string
|
||||
}
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
export { findLocaleFromCode } from '../utilities/findLocaleFromCode'
|
||||
export { default as formatFields } from '../utilities/formatFields'
|
||||
export { formatFields } from '../utilities/formatFields'
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
export { DefaultAccount } from '../views/Account'
|
||||
export { DefaultDashboard } from '../views/Dashboard'
|
||||
export { DefaultList } from '../views/List'
|
||||
export { DefaultEdit } from '../views/Edit'
|
||||
export { DefaultEditView } from '../views/Edit'
|
||||
export { DefaultGlobalView } from '../views/Global'
|
||||
export type { DefaultEditViewProps } from '../views/Edit/types'
|
||||
export type { DefaultGlobalViewProps } from '../views/Global/types'
|
||||
export type { DefaultAccountViewProps } from '../views/Account/types'
|
||||
|
||||
@@ -4,7 +4,7 @@ import type { TFunction } from 'i18next'
|
||||
import ObjectID from 'bson-objectid'
|
||||
|
||||
import type { User } from 'payload/auth'
|
||||
import type { NonPresentationalField, SanitizedCollectionConfig } from 'payload/types'
|
||||
import type { NonPresentationalField, SanitizedConfig } from 'payload/types'
|
||||
import type { Data, Fields, FormField } from '../types'
|
||||
|
||||
import { fieldAffectsData, fieldHasSubFields, tabHasName } from 'payload/types'
|
||||
@@ -12,7 +12,7 @@ import getValueWithDefault from 'payload/dist/fields/getDefaultValue' // TODO: r
|
||||
import { iterateFields } from './iterateFields'
|
||||
|
||||
type Args = {
|
||||
config: SanitizedCollectionConfig
|
||||
config: SanitizedConfig
|
||||
data: Data
|
||||
field: NonPresentationalField
|
||||
fullData: Data
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
import type { TFunction } from 'i18next'
|
||||
|
||||
import type { User } from 'payload/auth'
|
||||
import type { Field as FieldSchema, SanitizedCollectionConfig } from 'payload/types'
|
||||
import type { Field as FieldSchema, SanitizedConfig } from 'payload/types'
|
||||
import type { Data, Fields } from '../types'
|
||||
|
||||
import { iterateFields } from './iterateFields'
|
||||
|
||||
type Args = {
|
||||
config: SanitizedCollectionConfig
|
||||
config: SanitizedConfig
|
||||
data?: Data
|
||||
fieldSchema: FieldSchema[] | undefined
|
||||
id?: number | string
|
||||
|
||||
@@ -1,14 +1,13 @@
|
||||
import type { TFunction } from 'i18next'
|
||||
|
||||
import type { User } from 'payload/auth'
|
||||
import type { Field as FieldSchema, SanitizedCollectionConfig } from 'payload/types'
|
||||
import type { Field as FieldSchema, SanitizedConfig } from 'payload/types'
|
||||
import type { Data, Fields } from '../types'
|
||||
|
||||
import { fieldIsPresentationalOnly } from 'payload/types'
|
||||
import { addFieldStatePromise } from './addFieldStatePromise'
|
||||
|
||||
type Args = {
|
||||
config: SanitizedCollectionConfig
|
||||
config: SanitizedConfig
|
||||
data: Data
|
||||
fields: FieldSchema[]
|
||||
fullData: Data
|
||||
|
||||
@@ -1,106 +1,82 @@
|
||||
'use client'
|
||||
import type { ChangeEvent } from 'react'
|
||||
|
||||
import React from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
|
||||
import type { TextField } from 'payload/types'
|
||||
import type { Description } from '../../FieldDescription/types'
|
||||
import type { SanitizedConfig } from 'payload/types'
|
||||
|
||||
import { getTranslation } from 'payload/utilities'
|
||||
import DefaultError from '../../Error'
|
||||
import FieldDescription from '../../FieldDescription'
|
||||
import DefaultLabel from '../../Label'
|
||||
import { fieldBaseClass } from '../shared'
|
||||
import { isFieldRTL } from '../shared'
|
||||
import './index.scss'
|
||||
import useField from '../../useField'
|
||||
import { useLocale } from '../../../providers/Locale'
|
||||
|
||||
export type TextInputProps = Omit<TextField, 'type'> & {
|
||||
Error?: React.ComponentType<any>
|
||||
Label?: React.ComponentType<any>
|
||||
afterInput?: React.ComponentType<any>[]
|
||||
beforeInput?: React.ComponentType<any>[]
|
||||
className?: string
|
||||
description?: Description
|
||||
errorMessage?: string
|
||||
inputRef?: React.MutableRefObject<HTMLInputElement>
|
||||
onChange?: (e: ChangeEvent<HTMLInputElement>) => void
|
||||
onKeyDown?: React.KeyboardEventHandler<HTMLInputElement>
|
||||
path: string
|
||||
placeholder?: Record<string, string> | string
|
||||
export const TextInput: React.FC<{
|
||||
name: string
|
||||
autoComplete?: string
|
||||
// condition?: Condition
|
||||
readOnly?: boolean
|
||||
path: string
|
||||
required?: boolean
|
||||
placeholder?: Record<string, string> | string
|
||||
localized?: boolean
|
||||
localizationConfig?: SanitizedConfig['localization']
|
||||
rtl?: boolean
|
||||
showError?: boolean
|
||||
style?: React.CSSProperties
|
||||
value?: string
|
||||
width?: string
|
||||
}
|
||||
|
||||
const TextInput: React.FC<TextInputProps> = (props) => {
|
||||
maxLength?: number
|
||||
minLength?: number
|
||||
}> = (props) => {
|
||||
const {
|
||||
Error,
|
||||
Label,
|
||||
afterInput,
|
||||
beforeInput,
|
||||
className,
|
||||
description,
|
||||
errorMessage,
|
||||
inputRef,
|
||||
label,
|
||||
onChange,
|
||||
onKeyDown,
|
||||
path,
|
||||
placeholder,
|
||||
readOnly,
|
||||
required,
|
||||
localized,
|
||||
localizationConfig,
|
||||
rtl,
|
||||
showError,
|
||||
style,
|
||||
value,
|
||||
width,
|
||||
// maxLength,
|
||||
// minLength,
|
||||
} = props
|
||||
|
||||
const { i18n } = useTranslation()
|
||||
const locale = useLocale()
|
||||
|
||||
const ErrorComp = Error || DefaultError
|
||||
const LabelComp = Label || DefaultLabel
|
||||
const {
|
||||
// errorMessage,
|
||||
setValue,
|
||||
// showError,
|
||||
value,
|
||||
} = useField({
|
||||
// condition,
|
||||
path,
|
||||
// validate: memoizedValidate,
|
||||
})
|
||||
|
||||
// const memoizedValidate = useCallback(
|
||||
// (value, options) => {
|
||||
// return validate(value, { ...options, maxLength, minLength, required })
|
||||
// },
|
||||
// [validate, minLength, maxLength, required],
|
||||
// )
|
||||
|
||||
const renderRTL = isFieldRTL({
|
||||
fieldLocalized: localized,
|
||||
fieldRTL: rtl,
|
||||
locale,
|
||||
localizationConfig: localizationConfig || undefined,
|
||||
})
|
||||
|
||||
return (
|
||||
<div
|
||||
className={[fieldBaseClass, 'text', className, showError && 'error', readOnly && 'read-only']
|
||||
.filter(Boolean)
|
||||
.join(' ')}
|
||||
style={{
|
||||
...style,
|
||||
width,
|
||||
<input
|
||||
data-rtl={renderRTL}
|
||||
disabled={readOnly}
|
||||
id={`field-${path.replace(/\./g, '__')}`}
|
||||
name={path}
|
||||
onChange={(e) => {
|
||||
setValue(e.target.value)
|
||||
}}
|
||||
>
|
||||
<ErrorComp message={errorMessage} showError={showError} />
|
||||
<LabelComp htmlFor={`field-${path.replace(/\./g, '__')}`} label={label} required={required} />
|
||||
<div className="input-wrapper">
|
||||
{Array.isArray(beforeInput) && beforeInput.map((Component, i) => <Component key={i} />)}
|
||||
<input
|
||||
data-rtl={rtl}
|
||||
disabled={readOnly}
|
||||
id={`field-${path.replace(/\./g, '__')}`}
|
||||
name={path}
|
||||
onChange={onChange}
|
||||
onKeyDown={onKeyDown}
|
||||
placeholder={getTranslation(placeholder, i18n)}
|
||||
ref={inputRef}
|
||||
type="text"
|
||||
value={value || ''}
|
||||
/>
|
||||
{Array.isArray(afterInput) && afterInput.map((Component, i) => <Component key={i} />)}
|
||||
</div>
|
||||
<FieldDescription
|
||||
className={`field-description-${path.replace(/\./g, '__')}`}
|
||||
description={description}
|
||||
path={path}
|
||||
value={value}
|
||||
/>
|
||||
</div>
|
||||
// onKeyDown={onKeyDown}
|
||||
placeholder={getTranslation(placeholder, i18n)}
|
||||
// ref={inputRef}
|
||||
type="text"
|
||||
value={(value as string) || ''}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
export default TextInput
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
import React, { useCallback } from 'react'
|
||||
import React from 'react'
|
||||
|
||||
import type { Props } from './types'
|
||||
|
||||
import { text } from 'payload/fields/validations'
|
||||
import { useConfig } from '../../../providers/Config'
|
||||
import { useLocale } from '../../../providers/Locale'
|
||||
import useField from '../../useField'
|
||||
import { isFieldRTL } from '../shared'
|
||||
import TextInput from './Input'
|
||||
import { fieldBaseClass, isFieldRTL } from '../shared'
|
||||
import { TextInput } from './Input'
|
||||
import FieldDescription from '../../FieldDescription'
|
||||
import DefaultError from '../../Error'
|
||||
import DefaultLabel from '../../Label'
|
||||
|
||||
const Text: React.FC<Props> = (props) => {
|
||||
const {
|
||||
@@ -15,7 +15,7 @@ const Text: React.FC<Props> = (props) => {
|
||||
admin: {
|
||||
className,
|
||||
components: { Error, Label, afterInput, beforeInput } = {},
|
||||
condition,
|
||||
// condition,
|
||||
description,
|
||||
placeholder,
|
||||
readOnly,
|
||||
@@ -23,7 +23,7 @@ const Text: React.FC<Props> = (props) => {
|
||||
style,
|
||||
width,
|
||||
} = {},
|
||||
inputRef,
|
||||
// inputRef,
|
||||
label,
|
||||
localized,
|
||||
maxLength,
|
||||
@@ -34,30 +34,52 @@ const Text: React.FC<Props> = (props) => {
|
||||
} = props
|
||||
|
||||
const path = pathFromProps || name
|
||||
const locale = useLocale()
|
||||
|
||||
const { localization } = useConfig()
|
||||
const isRTL = isFieldRTL({
|
||||
fieldLocalized: localized,
|
||||
fieldRTL: rtl,
|
||||
locale,
|
||||
localizationConfig: localization || undefined,
|
||||
})
|
||||
const ErrorComp = Error || DefaultError
|
||||
const LabelComp = Label || DefaultLabel
|
||||
|
||||
const memoizedValidate = useCallback(
|
||||
(value, options) => {
|
||||
return validate(value, { ...options, maxLength, minLength, required })
|
||||
},
|
||||
[validate, minLength, maxLength, required],
|
||||
return (
|
||||
<div
|
||||
className={[
|
||||
fieldBaseClass,
|
||||
'text',
|
||||
className,
|
||||
// showError && 'error', readOnly && 'read-only'
|
||||
]
|
||||
.filter(Boolean)
|
||||
.join(' ')}
|
||||
style={{
|
||||
...style,
|
||||
width,
|
||||
}}
|
||||
>
|
||||
<ErrorComp
|
||||
// message={errorMessage}
|
||||
// showError={showError}
|
||||
/>
|
||||
<LabelComp htmlFor={`field-${path.replace(/\./g, '__')}`} label={label} required={required} />
|
||||
<div className="input-wrapper">
|
||||
{Array.isArray(beforeInput) && beforeInput.map((Component, i) => <Component key={i} />)}
|
||||
<TextInput
|
||||
path={path}
|
||||
name={name}
|
||||
localized={localized}
|
||||
rtl={rtl}
|
||||
placeholder={placeholder}
|
||||
readOnly={readOnly}
|
||||
maxLength={maxLength}
|
||||
minLength={minLength}
|
||||
/>
|
||||
{Array.isArray(afterInput) && afterInput.map((Component, i) => <Component key={i} />)}
|
||||
</div>
|
||||
<FieldDescription
|
||||
className={`field-description-${path.replace(/\./g, '__')}`}
|
||||
description={description}
|
||||
path={path}
|
||||
// value={value}
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
|
||||
const { errorMessage, setValue, showError, value } = useField<string>({
|
||||
condition,
|
||||
path,
|
||||
validate: memoizedValidate,
|
||||
})
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
export default Text
|
||||
|
||||
@@ -1,11 +1,8 @@
|
||||
import type { SanitizedCollectionConfig } from 'payload/types'
|
||||
import type { Field } from 'payload/types'
|
||||
|
||||
import { fieldAffectsData } from 'payload/types'
|
||||
|
||||
const formatFields = (collection: SanitizedCollectionConfig, isEditing?: boolean): Field[] =>
|
||||
export const formatFields = (fields: Field[], isEditing?: boolean): Field[] =>
|
||||
isEditing
|
||||
? collection.fields.filter((field) => (fieldAffectsData(field) && field.name !== 'id') || true)
|
||||
: collection.fields
|
||||
|
||||
export default formatFields
|
||||
? fields.filter((field) => (fieldAffectsData(field) && field.name !== 'id') || true)
|
||||
: fields
|
||||
|
||||
@@ -30,7 +30,6 @@ export const DefaultCollectionEdit: React.FC<
|
||||
disableLeaveWithoutSaving,
|
||||
fieldTypes,
|
||||
hasSavePermission,
|
||||
internalState,
|
||||
isEditing,
|
||||
permissions,
|
||||
} = props
|
||||
@@ -58,7 +57,7 @@ export const DefaultCollectionEdit: React.FC<
|
||||
collectionSlug={collectionConfig?.slug}
|
||||
useAsTitle={collectionConfig?.admin?.useAsTitle}
|
||||
id={id}
|
||||
isEditing={isEditing}
|
||||
isEditing={isEditing || false}
|
||||
pluralLabel={collectionConfig?.labels?.plural}
|
||||
/>
|
||||
<DocumentControls
|
||||
|
||||
@@ -7,7 +7,6 @@ import type { CollectionEditViewProps } from '../types'
|
||||
// import VersionView from '../../../Version/Version'
|
||||
// import VersionsView from '../../../Versions'
|
||||
import { DefaultCollectionEdit } from './Default/index'
|
||||
import { SanitizedCollectionConfig } from 'payload/types'
|
||||
|
||||
export type collectionViewType =
|
||||
| 'API'
|
||||
|
||||
@@ -18,10 +18,19 @@ export const SetStepNav: React.FC<{
|
||||
globalSlug?: SanitizedGlobalConfig['slug']
|
||||
pluralLabel?: SanitizedCollectionConfig['labels']['plural']
|
||||
id?: number | string
|
||||
isEditing: boolean
|
||||
isEditing?: boolean
|
||||
view?: string
|
||||
}> = (props) => {
|
||||
const { collectionSlug, globalSlug, pluralLabel, useAsTitle, id, isEditing, globalLabel } = props
|
||||
const {
|
||||
collectionSlug,
|
||||
globalSlug,
|
||||
pluralLabel,
|
||||
useAsTitle,
|
||||
id,
|
||||
isEditing = true,
|
||||
globalLabel,
|
||||
} = props
|
||||
|
||||
const view: string | undefined = props?.view || undefined
|
||||
|
||||
const title = useTitle({
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import React from 'react'
|
||||
import React, { Fragment } from 'react'
|
||||
|
||||
import type { DefaultEditViewProps } from './types'
|
||||
|
||||
@@ -11,7 +11,7 @@ import { RenderCustomView } from './RenderCustomView'
|
||||
|
||||
const baseClass = 'collection-edit'
|
||||
|
||||
export const DefaultEdit: React.FC<DefaultEditViewProps> = async (props) => {
|
||||
export const DefaultEditView: React.FC<DefaultEditViewProps> = async (props) => {
|
||||
const {
|
||||
id,
|
||||
action,
|
||||
@@ -20,10 +20,10 @@ export const DefaultEdit: React.FC<DefaultEditViewProps> = async (props) => {
|
||||
customHeader,
|
||||
data,
|
||||
hasSavePermission,
|
||||
internalState,
|
||||
initialState,
|
||||
isEditing,
|
||||
isLoading,
|
||||
onSave: onSaveFromProps,
|
||||
// isLoading,
|
||||
// onSave: onSaveFromProps,
|
||||
} = props
|
||||
|
||||
// const { auth } = collectionConfig
|
||||
@@ -75,13 +75,13 @@ export const DefaultEdit: React.FC<DefaultEditViewProps> = async (props) => {
|
||||
action={action}
|
||||
className={`${baseClass}__form`}
|
||||
disabled={!hasSavePermission}
|
||||
initialState={internalState}
|
||||
initialState={initialState}
|
||||
method={id ? 'PATCH' : 'POST'}
|
||||
// onSuccess={onSave}
|
||||
>
|
||||
<FormLoadingOverlayToggle
|
||||
action={isLoading ? 'loading' : operation}
|
||||
formIsLoading={isLoading}
|
||||
action={operation}
|
||||
// formIsLoading={isLoading}
|
||||
// loadingSuffix={getTranslation(collectionConfig.labels.singular, i18n)}
|
||||
name={`collection-edit--${
|
||||
typeof collectionConfig?.labels?.singular === 'string'
|
||||
@@ -90,19 +90,17 @@ export const DefaultEdit: React.FC<DefaultEditViewProps> = async (props) => {
|
||||
}`}
|
||||
type="withoutNav"
|
||||
/>
|
||||
{!isLoading && (
|
||||
<React.Fragment>
|
||||
<DocumentHeader
|
||||
apiURL={apiURL}
|
||||
collectionConfig={collectionConfig}
|
||||
customHeader={customHeader}
|
||||
data={data}
|
||||
id={id}
|
||||
isEditing={isEditing}
|
||||
/>
|
||||
<RenderCustomView view="Default" {...props} />
|
||||
</React.Fragment>
|
||||
)}
|
||||
<Fragment>
|
||||
<DocumentHeader
|
||||
apiURL={apiURL}
|
||||
collectionConfig={collectionConfig}
|
||||
customHeader={customHeader}
|
||||
data={data}
|
||||
id={id}
|
||||
isEditing={isEditing}
|
||||
/>
|
||||
<RenderCustomView {...props} view="Default" />
|
||||
</Fragment>
|
||||
</Form>
|
||||
</OperationProvider>
|
||||
</main>
|
||||
|
||||
@@ -1,41 +1,35 @@
|
||||
import React from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
|
||||
import type { FieldTypes } from '../../../forms/field-types'
|
||||
import type { GlobalEditViewProps } from '../../types'
|
||||
|
||||
import { getTranslation } from '../../../../../utilities/getTranslation'
|
||||
import { DocumentControls } from '../../../elements/DocumentControls'
|
||||
import { DocumentFields } from '../../../elements/DocumentFields'
|
||||
import { LeaveWithoutSaving } from '../../../modals/LeaveWithoutSaving'
|
||||
import Meta from '../../../utilities/Meta'
|
||||
import { SetStepNav } from '../../collections/Edit/SetStepNav'
|
||||
import { LeaveWithoutSaving } from '../../../elements/LeaveWithoutSaving'
|
||||
import { SetStepNav } from '../../Edit/SetStepNav'
|
||||
|
||||
export const DefaultGlobalEdit: React.FC<
|
||||
GlobalEditViewProps & {
|
||||
fieldTypes: FieldTypes
|
||||
}
|
||||
> = (props) => {
|
||||
const { apiURL, data, fieldTypes, global, permissions } = props
|
||||
const { i18n } = useTranslation()
|
||||
const { apiURL, data, fieldTypes, globalConfig, permissions, config } = props
|
||||
|
||||
const { admin: { description } = {}, fields, label } = global
|
||||
const { admin: { description } = {}, fields, label } = globalConfig
|
||||
|
||||
const hasSavePermission = permissions?.update?.permission
|
||||
|
||||
return (
|
||||
<React.Fragment>
|
||||
<Meta
|
||||
description={getTranslation(label, i18n)}
|
||||
keywords={`${getTranslation(label, i18n)}, Payload, CMS`}
|
||||
title={getTranslation(label, i18n)}
|
||||
/>
|
||||
{!(global.versions?.drafts && global.versions?.drafts?.autosave) && <LeaveWithoutSaving />}
|
||||
<SetStepNav global={global} />
|
||||
{!(globalConfig.versions?.drafts && globalConfig.versions?.drafts?.autosave) && (
|
||||
<LeaveWithoutSaving />
|
||||
)}
|
||||
<SetStepNav globalSlug={globalConfig.slug} globalLabel={label} />
|
||||
<DocumentControls
|
||||
apiURL={apiURL}
|
||||
data={data}
|
||||
global={global}
|
||||
config={config}
|
||||
globalConfig={globalConfig}
|
||||
hasSavePermission={hasSavePermission}
|
||||
isEditing
|
||||
permissions={permissions}
|
||||
@@ -1,12 +1,8 @@
|
||||
import React from 'react'
|
||||
|
||||
import type { GlobalEditViewProps } from '../../types'
|
||||
import type { GlobalEditViewProps } from '../types'
|
||||
|
||||
import { API } from '../../API'
|
||||
import { LivePreviewView } from '../../LivePreview'
|
||||
import VersionView from '../../Version/Version'
|
||||
import VersionsView from '../../Versions'
|
||||
import { DefaultGlobalEdit } from '../Default/index'
|
||||
import { DefaultGlobalEdit } from './Default/index'
|
||||
|
||||
export type globalViewType =
|
||||
| 'API'
|
||||
@@ -20,23 +16,23 @@ export type globalViewType =
|
||||
export const defaultGlobalViews: {
|
||||
[key in globalViewType]: React.ComponentType<any>
|
||||
} = {
|
||||
API,
|
||||
API: null,
|
||||
Default: DefaultGlobalEdit,
|
||||
LivePreview: LivePreviewView,
|
||||
LivePreview: null,
|
||||
References: null,
|
||||
Relationships: null,
|
||||
Version: VersionView,
|
||||
Versions: VersionsView,
|
||||
Version: null,
|
||||
Versions: null,
|
||||
}
|
||||
|
||||
export const CustomGlobalComponent = (
|
||||
export const RenderCustomView = (
|
||||
args: GlobalEditViewProps & {
|
||||
view: globalViewType
|
||||
},
|
||||
) => {
|
||||
const { global, view } = args
|
||||
const { globalConfig, view } = args
|
||||
|
||||
const { admin: { components: { views: { Edit } = {} } = {} } = {} } = global
|
||||
const { admin: { components: { views: { Edit } = {} } = {} } = {} } = globalConfig
|
||||
|
||||
// Overriding components may come from multiple places in the config
|
||||
// Need to cascade through the hierarchy to find the correct component to render
|
||||
@@ -6,7 +6,7 @@ import { Route } from 'react-router-dom'
|
||||
import type { GlobalPermission, User } from '../../../../../auth'
|
||||
import type { EditView } from '../../../../../config/types'
|
||||
import type { SanitizedGlobalConfig } from '../../../../../exports/types'
|
||||
import type { globalViewType } from './CustomComponent'
|
||||
import type { globalViewType } from '../RenderCustomView'
|
||||
|
||||
import Unauthorized from '../../Unauthorized'
|
||||
|
||||
@@ -8,7 +8,7 @@ import type { GlobalEditViewProps } from '../../types'
|
||||
import { useAuth } from '../../../utilities/Auth'
|
||||
import { useConfig } from '../../../utilities/Config'
|
||||
import NotFound from '../../NotFound'
|
||||
import { CustomGlobalComponent } from './CustomComponent'
|
||||
import { CustomGlobalComponent } from '../RenderCustomView'
|
||||
import { globalCustomRoutes } from './custom'
|
||||
|
||||
// @ts-expect-error Just TypeScript being broken // TODO: Open TypeScript issue
|
||||
@@ -1,4 +1,4 @@
|
||||
@import '../../../scss/styles.scss';
|
||||
@import '../../scss/styles.scss';
|
||||
|
||||
.collection-edit {
|
||||
width: 100%;
|
||||
114
packages/ui/src/views/Global/index.tsx
Normal file
114
packages/ui/src/views/Global/index.tsx
Normal file
@@ -0,0 +1,114 @@
|
||||
import React from 'react'
|
||||
|
||||
import { DocumentHeader } from '../../elements/DocumentHeader'
|
||||
import { FormLoadingOverlayToggle } from '../../elements/Loading'
|
||||
import Form from '../../forms/Form'
|
||||
// import { useActions } from '../../providers/ActionsProvider'
|
||||
import { OperationProvider } from '../../providers/OperationProvider'
|
||||
import './index.scss'
|
||||
import { RenderCustomView } from './RenderCustomView'
|
||||
import { DefaultGlobalViewProps } from './types'
|
||||
|
||||
const baseClass = 'global-edit'
|
||||
|
||||
export const DefaultGlobalView: React.FC<DefaultGlobalViewProps> = (props) => {
|
||||
// const { i18n } = useTranslation('general')
|
||||
|
||||
const {
|
||||
action,
|
||||
apiURL,
|
||||
data,
|
||||
// disableRoutes,
|
||||
// fieldTypes,
|
||||
globalConfig,
|
||||
initialState,
|
||||
// onSave,
|
||||
permissions,
|
||||
} = props
|
||||
|
||||
// const { setViewActions } = useActions()
|
||||
|
||||
const { label } = globalConfig
|
||||
|
||||
// const onSave = useCallback(
|
||||
// async (json) => {
|
||||
// reportUpdate({
|
||||
// entitySlug: global.slug,
|
||||
// updatedAt: json?.result?.updatedAt || new Date().toISOString(),
|
||||
// })
|
||||
|
||||
// getVersions()
|
||||
// getDocPermissions()
|
||||
// setUpdatedAt(json?.result?.updatedAt)
|
||||
|
||||
// const preferences = await getDocPreferences()
|
||||
|
||||
// const state = await buildStateFromSchema({
|
||||
// config,
|
||||
// data: json.result,
|
||||
// fieldSchema: fields,
|
||||
// locale,
|
||||
// operation: 'update',
|
||||
// preferences,
|
||||
// t,
|
||||
// user,
|
||||
// })
|
||||
// setInitialState(state)
|
||||
// },
|
||||
// [
|
||||
// getVersions,
|
||||
// fields,
|
||||
// user,
|
||||
// locale,
|
||||
// t,
|
||||
// getDocPermissions,
|
||||
// getDocPreferences,
|
||||
// config,
|
||||
// global,
|
||||
// reportUpdate,
|
||||
// ],
|
||||
// )
|
||||
|
||||
const hasSavePermission = permissions?.update?.permission
|
||||
|
||||
// useEffect(() => {
|
||||
// const path = location.pathname
|
||||
|
||||
// if (!path.endsWith(global.slug)) {
|
||||
// return
|
||||
// }
|
||||
|
||||
// const editConfig = global?.admin?.components?.views?.Edit
|
||||
// const defaultActions =
|
||||
// editConfig && 'Default' in editConfig && 'actions' in editConfig.Default
|
||||
// ? editConfig.Default.actions
|
||||
// : []
|
||||
|
||||
// setViewActions(defaultActions)
|
||||
// }, [global.slug, location.pathname, global?.admin?.components?.views?.Edit, setViewActions])
|
||||
|
||||
return (
|
||||
<main className={baseClass}>
|
||||
<OperationProvider operation="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}`}
|
||||
/>
|
||||
<React.Fragment>
|
||||
<DocumentHeader apiURL={apiURL} data={data} globalConfig={globalConfig} />
|
||||
<RenderCustomView {...props} view="Default" />
|
||||
</React.Fragment>
|
||||
</Form>
|
||||
</OperationProvider>
|
||||
</main>
|
||||
)
|
||||
}
|
||||
12
packages/ui/src/views/Global/types.ts
Normal file
12
packages/ui/src/views/Global/types.ts
Normal file
@@ -0,0 +1,12 @@
|
||||
import type { SanitizedGlobalConfig } from 'payload/types'
|
||||
import { GlobalEditViewProps } from '../types'
|
||||
import { FieldTypes } from '../../forms/field-types'
|
||||
|
||||
export type IndexProps = {
|
||||
global: SanitizedGlobalConfig
|
||||
}
|
||||
|
||||
export type DefaultGlobalViewProps = GlobalEditViewProps & {
|
||||
disableRoutes?: boolean
|
||||
fieldTypes: FieldTypes
|
||||
}
|
||||
@@ -64,6 +64,8 @@ export const DefaultList: React.FC<Props> = (props) => {
|
||||
})
|
||||
}
|
||||
|
||||
console.log(pluralLabel)
|
||||
|
||||
return (
|
||||
<div className={baseClass}>
|
||||
<SetStepNav
|
||||
@@ -82,7 +84,7 @@ export const DefaultList: React.FC<Props> = (props) => {
|
||||
{customHeader && customHeader}
|
||||
{!customHeader && (
|
||||
<Fragment>
|
||||
<h1>{pluralLabel['en']}</h1>
|
||||
<h1>{typeof pluralLabel === 'string' ? pluralLabel : pluralLabel['en']}</h1>
|
||||
{/* <h1>{getTranslation(pluralLabel, i18n)}</h1> */}
|
||||
{hasCreatePermission && (
|
||||
<Pill
|
||||
|
||||
@@ -14,13 +14,13 @@ export type CollectionEditViewProps = BaseEditViewProps & {
|
||||
hasSavePermission?: boolean
|
||||
id: string
|
||||
initialState?: Fields
|
||||
internalState?: Fields
|
||||
isEditing?: boolean
|
||||
permissions: CollectionPermission | null
|
||||
}
|
||||
|
||||
export type GlobalEditViewProps = BaseEditViewProps & {
|
||||
global: SanitizedGlobalConfig
|
||||
config: SanitizedConfig
|
||||
globalConfig: SanitizedGlobalConfig
|
||||
initialState?: Fields
|
||||
permissions: GlobalPermission | null
|
||||
}
|
||||
@@ -30,7 +30,7 @@ export type BaseEditViewProps = {
|
||||
apiURL: string
|
||||
canAccessAdmin?: boolean
|
||||
data: any
|
||||
isLoading: boolean
|
||||
// isLoading: boolean
|
||||
onSave: (json: any) => void
|
||||
updatedAt: string
|
||||
user: User | null | undefined
|
||||
|
||||
Reference in New Issue
Block a user