diff --git a/packages/next/src/pages/Document/index.tsx b/packages/next/src/pages/Document/index.tsx index 4533b00b140..b2c1269e1af 100644 --- a/packages/next/src/pages/Document/index.tsx +++ b/packages/next/src/pages/Document/index.tsx @@ -204,7 +204,6 @@ export const Document = async ({ collectionSlug={collectionConfig?.slug} globalSlug={globalConfig?.slug} id={id} - versionsConfig={collectionConfig?.versions || globalConfig?.versions} /> diff --git a/packages/next/src/pages/Edit/index.client.tsx b/packages/next/src/pages/Edit/index.client.tsx new file mode 100644 index 00000000000..37dfd11f30c --- /dev/null +++ b/packages/next/src/pages/Edit/index.client.tsx @@ -0,0 +1,34 @@ +'use client' +import React from 'react' +import { DefaultEditView, EditViewProps, useDocumentInfo } from '@payloadcms/ui' +import { useCallback } from 'react' + +export const DefaultEditViewClient: React.FC = (props) => { + const id = 'id' in props ? props.id : undefined + const collectionSlug = 'collectionSlug' in props ? props.collectionSlug : undefined + const isEditing = Boolean(id && collectionSlug) + + const { getVersions, getDocPermissions } = useDocumentInfo() + + const onSave = useCallback( + async (json: { doc }) => { + getVersions() + getDocPermissions() + + if (!isEditing) { + // setRedirect(`${admin}/collections/${collection.slug}/${json?.doc?.id}`) + } else { + // buildState(json.doc, { + // fieldSchema: collection.fields, + // }) + // setFormQueryParams((params) => ({ + // ...params, + // uploadEdits: undefined, + // })) + } + }, + [getVersions, isEditing, getDocPermissions, collectionSlug], + ) + + return +} diff --git a/packages/next/src/pages/Edit/index.tsx b/packages/next/src/pages/Edit/index.tsx index 2ca044c2dc0..4862217a6ae 100644 --- a/packages/next/src/pages/Edit/index.tsx +++ b/packages/next/src/pages/Edit/index.tsx @@ -1,9 +1,9 @@ import React from 'react' -import { DefaultEditView } from '@payloadcms/ui' import { ServerSideEditViewProps } from '../../../../ui/src/views/types' import { sanitizedEditViewProps } from './sanitizedEditViewProps' +import { DefaultEditViewClient } from './index.client' export const EditView: React.FC = async (props) => { const clientSideProps = sanitizedEditViewProps(props) - return + return } diff --git a/packages/payload/src/admin/elements/Tab.ts b/packages/payload/src/admin/elements/Tab.ts index 2f5435e7d15..4d954f66931 100644 --- a/packages/payload/src/admin/elements/Tab.ts +++ b/packages/payload/src/admin/elements/Tab.ts @@ -3,8 +3,6 @@ import type { I18n } from '@payloadcms/translations' import type { SanitizedCollectionConfig } from '../../collections/config/types' import type { SanitizedConfig } from '../../config/types' import type { SanitizedGlobalConfig } from '../../globals/config/types' -import type { Document } from '../../types' -import type { DocumentInfoContext } from '../providers/DocumentInfo' export type DocumentTabProps = { apiURL?: string @@ -17,13 +15,13 @@ export type DocumentTabProps = { export type DocumentTabCondition = (args: { collectionConfig: SanitizedCollectionConfig config: SanitizedConfig - documentInfo: DocumentInfoContext globalConfig: SanitizedGlobalConfig }) => boolean // Everything is optional because we merge in the defaults // i.e. the config may override the `Default` view with a `label` but not an `href` export type DocumentTabConfig = { + Pill?: React.ComponentType condition?: DocumentTabCondition href?: | ((args: { @@ -34,17 +32,13 @@ export type DocumentTabConfig = { routes: SanitizedConfig['routes'] }) => string) | string - isActive?: boolean - // isActive?: ((args: { href: string }) => boolean) | boolean + isActive?: ((args: { href: string }) => boolean) | boolean label?: ((args: { t: (key: string) => string }) => string) | string newTab?: boolean - pillLabel?: ((args: { versions: Document }) => string) | string } -export type DocumentTabComponent = React.ComponentType< - DocumentTabProps & { - path: string - } -> +export type DocumentTabComponent = React.ComponentType<{ + path: string +}> export type DocumentTab = DocumentTabComponent | DocumentTabConfig diff --git a/packages/payload/src/admin/providers/DocumentInfo.ts b/packages/payload/src/admin/providers/DocumentInfo.ts index adae3c356cc..e450b8aefaa 100644 --- a/packages/payload/src/admin/providers/DocumentInfo.ts +++ b/packages/payload/src/admin/providers/DocumentInfo.ts @@ -9,6 +9,7 @@ import type { SanitizedGlobalConfig } from '../../globals/config/types' export type DocumentInfoContext = { collectionSlug?: SanitizedCollectionConfig['slug'] + docConfig?: SanitizedCollectionConfig | SanitizedGlobalConfig docPermissions: DocumentPermissions getDocPermissions: () => Promise getDocPreferences: () => Promise<{ [key: string]: unknown }> @@ -23,7 +24,6 @@ export type DocumentInfoContext = { collectionSlug: SanitizedCollectionConfig['slug'] globalSlug: SanitizedGlobalConfig['slug'] id: number | string - versionsConfig: SanitizedCollectionConfig['versions'] | SanitizedGlobalConfig['versions'] }>, ) => void setDocumentTitle: (title: string) => void @@ -31,6 +31,5 @@ export type DocumentInfoContext = { title?: string unpublishedVersions?: PaginatedDocs> versions?: PaginatedDocs> - versionsConfig?: SanitizedCollectionConfig['versions'] | SanitizedGlobalConfig['versions'] versionsCount?: PaginatedDocs> } diff --git a/packages/ui/src/elements/Autosave/index.tsx b/packages/ui/src/elements/Autosave/index.tsx index b5870e54884..21676c62e30 100644 --- a/packages/ui/src/elements/Autosave/index.tsx +++ b/packages/ui/src/elements/Autosave/index.tsx @@ -23,7 +23,9 @@ const Autosave: React.FC = ({ id, collection, global, publishedDocUpdated routes: { admin, api }, serverURL, } = useConfig() - const { getVersions, versionsConfig, versions } = useDocumentInfo() + const { getVersions, docConfig, versions } = useDocumentInfo() + const versionsConfig = docConfig?.versions + const [fields] = useAllFormFields() const modified = useFormModified() const { code: locale } = useLocale() diff --git a/packages/ui/src/elements/DocumentHeader/Tabs/ShouldRenderTabs.tsx b/packages/ui/src/elements/DocumentHeader/Tabs/ShouldRenderTabs.tsx index 92dd8a10a05..e7824ac0d78 100644 --- a/packages/ui/src/elements/DocumentHeader/Tabs/ShouldRenderTabs.tsx +++ b/packages/ui/src/elements/DocumentHeader/Tabs/ShouldRenderTabs.tsx @@ -1,17 +1,13 @@ 'use client' import React from 'react' -import { useParams } from '../../../providers/Params' +import { useDocumentInfo } from '../../../providers/DocumentInfo' export const ShouldRenderTabs: React.FC<{ children: React.ReactNode }> = ({ children }) => { - const { - collection: collectionSlug, - global: globalSlug, - segments: [idFromParam] = [], - } = useParams() + const { collectionSlug, globalSlug, id: idFromContext } = useDocumentInfo() - const id = idFromParam !== 'create' ? idFromParam : null + const id = idFromContext !== 'create' ? idFromContext : null // Don't show tabs when creating new documents if ((collectionSlug && id) || globalSlug) { diff --git a/packages/ui/src/elements/DocumentHeader/Tabs/Tab/index.tsx b/packages/ui/src/elements/DocumentHeader/Tabs/Tab/index.tsx index 2e52f219114..ec2f18a1050 100644 --- a/packages/ui/src/elements/DocumentHeader/Tabs/Tab/index.tsx +++ b/packages/ui/src/elements/DocumentHeader/Tabs/Tab/index.tsx @@ -2,35 +2,34 @@ import React, { Fragment } from 'react' import { DocumentTabLink } from './TabLink' -import './index.scss' import { DocumentTabConfig, DocumentTabProps } from 'payload/types' -const baseClass = 'doc-tab' +import './index.scss' + +export const baseClass = 'doc-tab' export const DocumentTab: React.FC = (props) => { const { - id, apiURL, config, collectionConfig, condition, globalConfig, href: tabHref, - isActive: checkIsActive, + isActive: tabIsActive, label, newTab, - pillLabel, + Pill, i18n, } = props const { routes } = config - // const { versions } = documentInfo let href = typeof tabHref === 'string' ? tabHref : '' + let isActive = typeof tabIsActive === 'boolean' ? tabIsActive : false if (typeof tabHref === 'function') { href = tabHref({ - id, apiURL, collection: collectionConfig, global: globalConfig, @@ -38,10 +37,13 @@ export const DocumentTab: React.FC = (prop }) } - if ( - !condition || - (condition && condition({ collectionConfig, config, documentInfo: undefined, globalConfig })) - ) { + if (typeof tabIsActive === 'function') { + isActive = tabIsActive({ + href, + }) + } + + if (!condition || (condition && condition({ collectionConfig, config, globalConfig }))) { const labelToRender = typeof label === 'function' ? label({ @@ -49,24 +51,21 @@ export const DocumentTab: React.FC = (prop }) : label - const pillToRender = - typeof pillLabel === 'function' ? pillLabel({ versions: undefined }) : pillLabel - return ( {labelToRender} - {pillToRender && ( + {Pill && (   - {pillToRender} + )} diff --git a/packages/ui/src/elements/DocumentHeader/Tabs/index.tsx b/packages/ui/src/elements/DocumentHeader/Tabs/index.tsx index e2b80b63302..aa5fe492a1d 100644 --- a/packages/ui/src/elements/DocumentHeader/Tabs/index.tsx +++ b/packages/ui/src/elements/DocumentHeader/Tabs/index.tsx @@ -3,16 +3,22 @@ import React from 'react' import { DocumentTab } from './Tab' import { getCustomViews } from './getCustomViews' import { getViewConfig } from './getViewConfig' -import { tabs as defaultViews } from './tabs' -import { DocumentTabProps } from 'payload/types' +import { tabs as defaultTabs } from './tabs' import { ShouldRenderTabs } from './ShouldRenderTabs' +import { SanitizedCollectionConfig, SanitizedConfig, SanitizedGlobalConfig } from 'payload/types' +import { I18n } from '@payloadcms/translations' import './index.scss' const baseClass = 'doc-tabs' -export const DocumentTabs: React.FC = (props) => { - const { collectionConfig, globalConfig } = props +export const DocumentTabs: React.FC<{ + config: SanitizedConfig + collectionConfig: SanitizedCollectionConfig + globalConfig: SanitizedGlobalConfig + i18n: I18n +}> = (props) => { + const { collectionConfig, globalConfig, config } = props const customViews = getCustomViews({ collectionConfig, globalConfig }) @@ -21,7 +27,7 @@ export const DocumentTabs: React.FC = (props) => {
    - {Object.entries(defaultViews) + {Object.entries(defaultTabs) // sort `defaultViews` based on `order` property from smallest to largest // if no `order`, append the view to the end // TODO: open `order` to the config and merge `defaultViews` with `customViews` @@ -31,20 +37,30 @@ export const DocumentTabs: React.FC = (props) => { else if (b.order === undefined) return -1 return a.order - b.order }) - ?.map(([name, Tab], index) => { + ?.map(([name, tab], index) => { const viewConfig = getViewConfig({ name, collectionConfig, globalConfig }) - const tabOverrides = viewConfig && 'Tab' in viewConfig ? viewConfig.Tab : undefined + const tabFromConfig = viewConfig && 'Tab' in viewConfig ? viewConfig.Tab : undefined + const tabConfig = typeof tabFromConfig === 'object' ? tabFromConfig : undefined - return ( - - ) + const { condition } = tabConfig || {} + + const meetsCondition = + !condition || (condition && condition({ collectionConfig, config, globalConfig })) + + if (meetsCondition) { + return ( + + ) + } + + return null })} {customViews?.map((CustomView, index) => { if ('Tab' in CustomView) { @@ -56,11 +72,11 @@ export const DocumentTabs: React.FC = (props) => { return ( ) } diff --git a/packages/ui/src/elements/DocumentHeader/Tabs/tabs/VersionsPill/index.tsx b/packages/ui/src/elements/DocumentHeader/Tabs/tabs/VersionsPill/index.tsx new file mode 100644 index 00000000000..02f37dd9d8a --- /dev/null +++ b/packages/ui/src/elements/DocumentHeader/Tabs/tabs/VersionsPill/index.tsx @@ -0,0 +1,9 @@ +'use client' +import React from 'react' +import { useDocumentInfo } from '../../../../../providers/DocumentInfo' +import { baseClass } from '../../Tab' + +export const VersionsPill: React.FC = () => { + const { versions } = useDocumentInfo() + return {versions?.totalDocs?.toString()} +} diff --git a/packages/ui/src/elements/DocumentHeader/Tabs/tabs.ts b/packages/ui/src/elements/DocumentHeader/Tabs/tabs/index.tsx similarity index 91% rename from packages/ui/src/elements/DocumentHeader/Tabs/tabs.ts rename to packages/ui/src/elements/DocumentHeader/Tabs/tabs/index.tsx index dcb60354850..e486ba06e23 100644 --- a/packages/ui/src/elements/DocumentHeader/Tabs/tabs.ts +++ b/packages/ui/src/elements/DocumentHeader/Tabs/tabs/index.tsx @@ -1,4 +1,5 @@ import type { DocumentTabConfig } from 'payload/types' +import { VersionsPill } from './VersionsPill' export const documentViewKeys = [ 'API', @@ -70,9 +71,6 @@ export const tabs: Record< href: '/versions', label: ({ t }) => t('version:versions'), order: 200, - pillLabel: ({ versions }) => - typeof versions?.totalDocs === 'number' && versions?.totalDocs > 0 - ? versions?.totalDocs.toString() - : '', + Pill: VersionsPill, }, } diff --git a/packages/ui/src/elements/ListDrawer/DrawerContent.tsx b/packages/ui/src/elements/ListDrawer/DrawerContent.tsx index fc106b7f058..e3d1696b1a0 100644 --- a/packages/ui/src/elements/ListDrawer/DrawerContent.tsx +++ b/packages/ui/src/elements/ListDrawer/DrawerContent.tsx @@ -3,7 +3,7 @@ import React, { useCallback, useEffect, useReducer, useState } from 'react' import { useTranslation } from '../../providers/Translation' import type { SanitizedCollectionConfig } from 'payload/types' -import type { Where, Field } from 'payload/types' +import type { Where } from 'payload/types' import type { ListDrawerProps } from './types' import { baseClass } from '.' @@ -305,10 +305,7 @@ export const ListDrawerContent: React.FC = ({ ]} collectionSlug={selectedCollectionConfig.slug} > - + = ({ + user, + permissions, +}) => { + const { setUser, setPermissions } = useAuth() + + useEffect(() => { + setUser(user) + setPermissions(permissions) + }, [user, permissions, setUser, setPermissions]) + + return null +} diff --git a/packages/ui/src/providers/DocumentInfo/SetDocumentInfo/index.tsx b/packages/ui/src/providers/DocumentInfo/SetDocumentInfo/index.tsx index a4160a97c05..07786f6da0d 100644 --- a/packages/ui/src/providers/DocumentInfo/SetDocumentInfo/index.tsx +++ b/packages/ui/src/providers/DocumentInfo/SetDocumentInfo/index.tsx @@ -7,13 +7,12 @@ export const SetDocumentInfo: React.FC<{ collectionSlug: string globalSlug: string id: string - versionsConfig?: any -}> = ({ collectionSlug, globalSlug, id, versionsConfig }) => { +}> = ({ collectionSlug, globalSlug, id }) => { const { setDocumentInfo } = useDocumentInfo() useEffect(() => { - setDocumentInfo({ collectionSlug, globalSlug, id, versionsConfig }) - }, [collectionSlug, globalSlug, id, setDocumentInfo, versionsConfig]) + setDocumentInfo({ collectionSlug, globalSlug, id }) + }, [collectionSlug, globalSlug, id, setDocumentInfo]) return null } diff --git a/packages/ui/src/providers/DocumentInfo/index.tsx b/packages/ui/src/providers/DocumentInfo/index.tsx index be118b1bd62..fb85790e9bf 100644 --- a/packages/ui/src/providers/DocumentInfo/index.tsx +++ b/packages/ui/src/providers/DocumentInfo/index.tsx @@ -24,11 +24,24 @@ const Context = createContext({} as DocumentInfoContext) export const useDocumentInfo = (): DocumentInfoContext => useContext(Context) export const DocumentInfoProvider: React.FC = ({ children, ...rest }) => { + const [propsToUse, setPropsToUse] = useState({ + ...rest, + }) + + const { globalSlug, collectionSlug, id } = propsToUse + const { routes: { api }, serverURL, + collections, + globals, } = useConfig() + const collectionConfig = collections.find((c) => c.slug === collectionSlug) + const globalConfig = globals.find((g) => g.slug === globalSlug) + const docConfig = collectionConfig || globalConfig + const versionsConfig = docConfig?.versions + const { getPreference, setPreference } = usePreferences() const { i18n } = useTranslation() const { permissions } = useAuth() @@ -41,14 +54,8 @@ export const DocumentInfoProvider: React.FC = ({ children, ...rest }) => const [docPermissions, setDocPermissions] = useState(null) - const [propsToUse, setPropsToUse] = useState({ - ...rest, - }) - const [title, setTitle] = useState('') - const { globalSlug, collectionSlug, id, versionsConfig } = propsToUse - const baseURL = `${serverURL}${api}` let slug: string let pluralType: 'collections' | 'globals' @@ -280,7 +287,7 @@ export const DocumentInfoProvider: React.FC = ({ children, ...rest }) => setDocFieldPreferences, slug, unpublishedVersions, - versionsConfig, + docConfig, versions, setDocumentInfo: setPropsToUse, setDocumentTitle, diff --git a/packages/ui/src/providers/DocumentInfo/types.ts b/packages/ui/src/providers/DocumentInfo/types.ts index 8858faa61df..eec91c63b22 100644 --- a/packages/ui/src/providers/DocumentInfo/types.ts +++ b/packages/ui/src/providers/DocumentInfo/types.ts @@ -8,5 +8,4 @@ export type Props = { globalSlug?: SanitizedGlobalConfig['slug'] id?: number | string idFromParams?: boolean - versionsConfig?: SanitizedCollectionConfig['versions'] | SanitizedGlobalConfig['versions'] } diff --git a/packages/ui/src/providers/Root/index.tsx b/packages/ui/src/providers/Root/index.tsx index ad89b63f112..e83263fefff 100644 --- a/packages/ui/src/providers/Root/index.tsx +++ b/packages/ui/src/providers/Root/index.tsx @@ -22,7 +22,7 @@ import { ComponentMap } from '../../utilities/buildComponentMap/types' import { ComponentMapProvider } from '../ComponentMapProvider' import { SearchParamsProvider } from '../SearchParams' import { ParamsProvider } from '../Params' -import { DocumentInfoProvider } from '../..' +import { DocumentInfoProvider } from '../DocumentInfo' type Props = { config: ClientConfig diff --git a/test/_community/collections/Posts/index.ts b/test/_community/collections/Posts/index.ts index a2fd60466db..569cdd53a02 100644 --- a/test/_community/collections/Posts/index.ts +++ b/test/_community/collections/Posts/index.ts @@ -20,5 +20,6 @@ export const PostsCollection: CollectionConfig = { type: 'upload', }, ], + versions: true, slug: postsSlug, }