payload-nested-docs-page-tree 1.4.1 → 1.4.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -27,6 +27,8 @@ pnpm add payload-nested-docs-page-tree
27
27
  - a nested docs breadcrumbs field
28
28
  - a top-level `admin.useAsTitle` field
29
29
 
30
+ These fields may live inside presentational containers — tabs, rows, collapsibles, and unnamed groups — because Payload still stores them at the top level of the document. Fields inside a **named** tab or **named** group are nested in the data and are not supported.
31
+
30
32
  Add `nestedDocsPageTreePlugin(...)` right after `nestedDocsPlugin(...)`:
31
33
 
32
34
  ```ts
package/dist/index.js CHANGED
@@ -3,6 +3,7 @@ import { createReorderPageEndpoint } from './endpoints/createReorderPageEndpoint
3
3
  import { nestedDocsPageTreePluginCustomKey, pageTreeWriteContextKey } from './types.js';
4
4
  import { normalizeNestedDocsPageTreePluginBadgeConfig } from './utilities/badgeConfig.js';
5
5
  import { DIAGNOSTICS_FLOW_CONTEXT_KEY, createFlowID, projectField, resolveDiagnostics } from './utilities/diagnostics.js';
6
+ import { findTopLevelField, mapTopLevelFields } from './utilities/fields.js';
6
7
  const DEFAULT_BREADCRUMBS_FIELD_SLUG = 'breadcrumbs';
7
8
  const DEFAULT_HOME_INDICATOR_COLLECTIONS = [
8
9
  'pages'
@@ -85,9 +86,6 @@ const PAGE_TREE_LIST_VIEW_PATH = 'payload-nested-docs-page-tree/rsc#NestedDocsPa
85
86
  return doc;
86
87
  };
87
88
  }
88
- function getTopLevelField(collection, fieldName) {
89
- return collection.fields.find((field)=>'name' in field && field.name === fieldName);
90
- }
91
89
  function getCollectionEndpoints(collection) {
92
90
  return Array.isArray(collection.endpoints) ? [
93
91
  ...collection.endpoints
@@ -111,13 +109,13 @@ function validateTargetCollection(args) {
111
109
  if (typeof collection.admin?.useAsTitle !== 'string' || collection.admin.useAsTitle.includes('.')) {
112
110
  throw new Error(`payload-nested-docs-page-tree requires "${collection.slug}" to define a top-level admin.useAsTitle field.`);
113
111
  }
114
- if (!getTopLevelField(collection, collection.admin.useAsTitle)) {
115
- throw new Error(`payload-nested-docs-page-tree could not find the useAsTitle field "${collection.admin.useAsTitle}" on "${collection.slug}".`);
112
+ if (!findTopLevelField(collection.fields, collection.admin.useAsTitle)) {
113
+ throw new Error(`payload-nested-docs-page-tree could not find the useAsTitle field "${collection.admin.useAsTitle}" on "${collection.slug}". Fields inside tabs, rows, collapsibles, and unnamed groups are supported; fields inside a named tab or named group are not top-level.`);
116
114
  }
117
- if (!getTopLevelField(collection, parentFieldSlug)) {
115
+ if (!findTopLevelField(collection.fields, parentFieldSlug)) {
118
116
  throw new Error(`payload-nested-docs-page-tree requires "${collection.slug}" to already define the nested docs parent field "${parentFieldSlug}". Register @payloadcms/plugin-nested-docs before payload-nested-docs-page-tree.`);
119
117
  }
120
- if (!getTopLevelField(collection, breadcrumbsFieldSlug)) {
118
+ if (!findTopLevelField(collection.fields, breadcrumbsFieldSlug)) {
121
119
  throw new Error(`payload-nested-docs-page-tree requires "${collection.slug}" to already define the nested docs breadcrumbs field "${breadcrumbsFieldSlug}". Register @payloadcms/plugin-nested-docs before payload-nested-docs-page-tree.`);
122
120
  }
123
121
  const existingListView = collection.admin?.components?.views?.list?.Component;
@@ -237,7 +235,7 @@ export const nestedDocsPageTreePlugin = (pluginOptions)=>(config)=>{
237
235
  })
238
236
  ] : []
239
237
  ],
240
- fields: collection.fields.map((field)=>patchBreadcrumbField({
238
+ fields: mapTopLevelFields(collection.fields, (field)=>patchBreadcrumbField({
241
239
  breadcrumbsFieldSlug,
242
240
  field,
243
241
  hideBreadcrumbs
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts"],"sourcesContent":["import type {\n CollectionAfterChangeHook,\n CollectionConfig,\n Config,\n} from 'payload'\n\nimport { createMovePageEndpoint } from './endpoints/createMovePageEndpoint.js'\nimport { createReorderPageEndpoint } from './endpoints/createReorderPageEndpoint.js'\nimport type {\n NestedDocsPageTreePluginCollectionCustom,\n NestedDocsPageTreePluginConfig,\n} from './types.js'\nimport { nestedDocsPageTreePluginCustomKey, pageTreeWriteContextKey } from './types.js'\nimport { normalizeNestedDocsPageTreePluginBadgeConfig } from './utilities/badgeConfig.js'\nimport {\n DIAGNOSTICS_FLOW_CONTEXT_KEY,\n type Diagnostics,\n createFlowID,\n projectField,\n resolveDiagnostics,\n} from './utilities/diagnostics.js'\n\nconst DEFAULT_BREADCRUMBS_FIELD_SLUG = 'breadcrumbs'\nconst DEFAULT_HOME_INDICATOR_COLLECTIONS = ['pages']\nconst DEFAULT_LIMIT = 100\nconst DEFAULT_PARENT_FIELD_SLUG = 'parent'\nconst PAGE_TREE_LIST_VIEW_PATH =\n 'payload-nested-docs-page-tree/rsc#NestedDocsPageTreeListView'\ntype CollectionEndpoint = NonNullable<Exclude<CollectionConfig['endpoints'], false>>[number]\n\n/**\n * When diagnostics are enabled this hook emits a structured event for each\n * page-tree-tagged create/update, including a small before/after diff of the\n * fields most relevant to tree publish/draft regressions.\n */\nfunction createDiagnosticsAfterChangeHook(args: {\n collectionSlug: string\n diagnostics: Diagnostics\n orderableFieldName: null | string\n parentFieldSlug: string\n}): CollectionAfterChangeHook {\n const { collectionSlug, diagnostics, orderableFieldName, parentFieldSlug } = args\n const snapshotFields: string[] = ['_status', parentFieldSlug]\n\n if (orderableFieldName) {\n snapshotFields.push(orderableFieldName)\n }\n\n return async ({ doc, operation, previousDoc, req }) => {\n if (!diagnostics.enabled) {\n return doc\n }\n\n if (operation !== 'update' && operation !== 'create') {\n return doc\n }\n\n // Gated on the write flag, not the deploy opt-out flag: a published move\n // withholds the latter, and that is the case most worth tracing.\n if (!req.context?.[pageTreeWriteContextKey]) {\n return doc\n }\n\n const docID = (doc as Record<string, unknown>)?.id\n\n if (typeof docID !== 'string' && typeof docID !== 'number') {\n return doc\n }\n\n const flow =\n (req.context?.[DIAGNOSTICS_FLOW_CONTEXT_KEY] as string | undefined) ??\n createFlowID('page-tree-change')\n const before: Record<string, unknown> = {}\n const after: Record<string, unknown> = {}\n const changed: string[] = []\n\n for (const field of snapshotFields) {\n const beforeValue = projectField((previousDoc as Record<string, unknown> | undefined)?.[field])\n const afterValue = projectField((doc as Record<string, unknown>)?.[field])\n\n before[field] = beforeValue\n after[field] = afterValue\n\n if (JSON.stringify(beforeValue) !== JSON.stringify(afterValue)) {\n changed.push(field)\n }\n }\n\n diagnostics.log({\n collection: collectionSlug,\n data: {\n after,\n before,\n changed,\n docID: String(docID),\n operation,\n },\n flow,\n level: 'info',\n message: `${operation} on ${collectionSlug}#${String(docID)}`,\n source: 'page-tree-change:after',\n })\n\n const beforeStatus = (previousDoc as Record<string, unknown> | undefined)?._status\n const afterStatus = (doc as Record<string, unknown>)?._status\n\n if (beforeStatus === 'published' && afterStatus !== 'published') {\n diagnostics.log({\n collection: collectionSlug,\n data: {\n afterStatus,\n beforeStatus,\n docID: String(docID),\n },\n flow,\n level: 'warn',\n message: `Published doc was demoted to \"${String(afterStatus ?? 'missing')}\" by a page-tree operation. Inspect the move-endpoint:enter/ok snapshots in flow ${flow} to confirm whether the main row was touched.`,\n source: 'page-tree-change:status-flip',\n })\n }\n\n return doc\n }\n}\n\nfunction getTopLevelField(\n collection: Pick<CollectionConfig, 'fields'>,\n fieldName: string,\n) {\n return collection.fields.find((field) => 'name' in field && field.name === fieldName)\n}\n\nfunction getCollectionEndpoints(collection: CollectionConfig): CollectionEndpoint[] {\n return Array.isArray(collection.endpoints) ? [...collection.endpoints] : []\n}\n\nfunction patchBreadcrumbField<TField extends CollectionConfig['fields'][number]>(args: {\n breadcrumbsFieldSlug: string\n field: TField\n hideBreadcrumbs: boolean\n}): TField {\n const { breadcrumbsFieldSlug, field, hideBreadcrumbs } = args\n\n if (!('name' in field) || field.name !== breadcrumbsFieldSlug) {\n return field\n }\n\n return {\n ...field,\n admin: {\n ...(field.admin ?? {}),\n hidden: hideBreadcrumbs,\n },\n } as TField\n}\n\nfunction validateTargetCollection(args: {\n breadcrumbsFieldSlug: string\n collection: CollectionConfig\n parentFieldSlug: string\n}) {\n const { breadcrumbsFieldSlug, collection, parentFieldSlug } = args\n\n if (typeof collection.admin?.useAsTitle !== 'string' || collection.admin.useAsTitle.includes('.')) {\n throw new Error(\n `payload-nested-docs-page-tree requires \"${collection.slug}\" to define a top-level admin.useAsTitle field.`,\n )\n }\n\n if (!getTopLevelField(collection, collection.admin.useAsTitle)) {\n throw new Error(\n `payload-nested-docs-page-tree could not find the useAsTitle field \"${collection.admin.useAsTitle}\" on \"${collection.slug}\".`,\n )\n }\n\n if (!getTopLevelField(collection, parentFieldSlug)) {\n throw new Error(\n `payload-nested-docs-page-tree requires \"${collection.slug}\" to already define the nested docs parent field \"${parentFieldSlug}\". Register @payloadcms/plugin-nested-docs before payload-nested-docs-page-tree.`,\n )\n }\n\n if (!getTopLevelField(collection, breadcrumbsFieldSlug)) {\n throw new Error(\n `payload-nested-docs-page-tree requires \"${collection.slug}\" to already define the nested docs breadcrumbs field \"${breadcrumbsFieldSlug}\". Register @payloadcms/plugin-nested-docs before payload-nested-docs-page-tree.`,\n )\n }\n\n const existingListView = collection.admin?.components?.views?.list?.Component\n\n if (existingListView && existingListView !== PAGE_TREE_LIST_VIEW_PATH) {\n throw new Error(\n `payload-nested-docs-page-tree cannot own the \"${collection.slug}\" list view because the collection already defines a custom admin.components.views.list.Component.`,\n )\n }\n\n const existingMoveEndpoint = getCollectionEndpoints(collection).find(\n (endpoint) => endpoint.path === '/:id/move',\n )\n const existingReorderEndpoint = getCollectionEndpoints(collection).find(\n (endpoint) => endpoint.path === '/:id/reorder',\n )\n\n if (existingMoveEndpoint) {\n throw new Error(\n `payload-nested-docs-page-tree cannot add the move endpoint to \"${collection.slug}\" because the collection already defines POST /:id/move.`,\n )\n }\n\n if (existingReorderEndpoint) {\n throw new Error(\n `payload-nested-docs-page-tree cannot add the reorder endpoint to \"${collection.slug}\" because the collection already defines POST /:id/reorder.`,\n )\n }\n}\n\nfunction buildCollectionCustom(args: {\n badges: NestedDocsPageTreePluginCollectionCustom['badges']\n breadcrumbsFieldSlug: string\n defaultLimit: number\n hideBreadcrumbs: boolean\n homeIndicator: NestedDocsPageTreePluginCollectionCustom['homeIndicator']\n parentFieldSlug: string\n}): NestedDocsPageTreePluginCollectionCustom {\n const {\n badges,\n breadcrumbsFieldSlug,\n defaultLimit,\n hideBreadcrumbs,\n homeIndicator,\n parentFieldSlug,\n } = args\n\n return {\n badges,\n breadcrumbsFieldSlug,\n defaultLimit,\n hideBreadcrumbs,\n homeIndicator,\n parentFieldSlug,\n }\n}\n\nfunction getHomeIndicatorCollectionSlugs(\n homeIndicator: NestedDocsPageTreePluginConfig['homeIndicator'],\n): Set<string> {\n if (homeIndicator === false) {\n return new Set()\n }\n\n return new Set(homeIndicator?.collections ?? DEFAULT_HOME_INDICATOR_COLLECTIONS)\n}\n\nexport type {\n NestedDocsPageTreePluginBadgeConfig,\n NestedDocsPageTreePluginBadgeMap,\n NestedDocsPageTreePluginBadgeStatus,\n NestedDocsPageTreePluginConfig,\n NestedDocsPageTreePluginHomeIndicatorConfig,\n PageTreeMoveContext,\n} from './types.js'\n\nexport { pageTreeMoveContextKey } from './types.js'\n\nexport const nestedDocsPageTreePlugin =\n (pluginOptions: NestedDocsPageTreePluginConfig) =>\n (config: Config): Config => {\n if (!pluginOptions.collections?.length) {\n throw new Error('payload-nested-docs-page-tree requires at least one collection slug.')\n }\n\n if (pluginOptions.disabled) {\n return config\n }\n\n const breadcrumbsFieldSlug =\n pluginOptions.breadcrumbsFieldSlug ?? DEFAULT_BREADCRUMBS_FIELD_SLUG\n const defaultLimit = pluginOptions.defaultLimit ?? DEFAULT_LIMIT\n const hideBreadcrumbs = pluginOptions.hideBreadcrumbs ?? true\n const parentFieldSlug = pluginOptions.parentFieldSlug ?? DEFAULT_PARENT_FIELD_SLUG\n const publishOnMove = pluginOptions.publishOnMove ?? false\n const badges = normalizeNestedDocsPageTreePluginBadgeConfig(pluginOptions.badges)\n const diagnostics = resolveDiagnostics(pluginOptions.diagnostics)\n const homeIndicatorCollectionSlugs = getHomeIndicatorCollectionSlugs(\n pluginOptions.homeIndicator,\n )\n const targetedCollectionSlugs = new Set<string>(pluginOptions.collections)\n\n if (!config.collections?.length) {\n throw new Error('payload-nested-docs-page-tree could not find any collections to patch.')\n }\n\n const foundCollectionSlugs = new Set<string>()\n const nextCollections = config.collections.map((collection) => {\n if (!targetedCollectionSlugs.has(collection.slug)) {\n return collection\n }\n\n foundCollectionSlugs.add(collection.slug)\n validateTargetCollection({\n breadcrumbsFieldSlug,\n collection,\n parentFieldSlug,\n })\n const orderableFieldName =\n typeof collection.orderable === 'string'\n ? collection.orderable\n : collection.orderable\n ? '_order'\n : null\n const diagnosticsAfterChangeHook = diagnostics.enabled\n ? createDiagnosticsAfterChangeHook({\n collectionSlug: collection.slug,\n diagnostics,\n orderableFieldName,\n parentFieldSlug,\n })\n : null\n\n return {\n ...collection,\n admin: {\n ...(collection.admin ?? {}),\n components: {\n ...(collection.admin?.components ?? {}),\n views: {\n ...(collection.admin?.components?.views ?? {}),\n list: {\n ...(collection.admin?.components?.views?.list ?? {}),\n Component: PAGE_TREE_LIST_VIEW_PATH,\n },\n },\n },\n pagination: {\n ...(collection.admin?.pagination ?? {}),\n defaultLimit:\n collection.admin?.pagination?.defaultLimit === undefined\n ? defaultLimit\n : collection.admin.pagination.defaultLimit,\n },\n },\n custom: {\n ...(collection.custom ?? {}),\n [nestedDocsPageTreePluginCustomKey]: buildCollectionCustom({\n badges,\n breadcrumbsFieldSlug,\n defaultLimit,\n hideBreadcrumbs,\n homeIndicator: {\n enabled: homeIndicatorCollectionSlugs.has(collection.slug),\n },\n parentFieldSlug,\n }),\n },\n endpoints: [\n ...getCollectionEndpoints(collection),\n createMovePageEndpoint({\n collectionSlug: collection.slug,\n diagnostics,\n parentFieldSlug,\n publishOnMove,\n }),\n ...(orderableFieldName\n ? [\n createReorderPageEndpoint({\n collectionSlug: collection.slug,\n diagnostics,\n orderableFieldName,\n parentFieldSlug,\n }),\n ]\n : []),\n ],\n fields: collection.fields.map((field) =>\n patchBreadcrumbField({\n breadcrumbsFieldSlug,\n field,\n hideBreadcrumbs,\n }),\n ),\n hooks: {\n ...(collection.hooks ?? {}),\n ...(diagnosticsAfterChangeHook\n ? {\n afterChange: [\n ...(collection.hooks?.afterChange ?? []),\n diagnosticsAfterChangeHook,\n ],\n }\n : {}),\n },\n }\n })\n\n const missingCollections = pluginOptions.collections.filter(\n (collectionSlug) => !foundCollectionSlugs.has(collectionSlug),\n )\n\n if (missingCollections.length > 0) {\n throw new Error(\n `payload-nested-docs-page-tree could not find the following collections: ${missingCollections.join(', ')}`,\n )\n }\n\n return {\n ...config,\n collections: nextCollections as CollectionConfig[],\n }\n }\n"],"names":["createMovePageEndpoint","createReorderPageEndpoint","nestedDocsPageTreePluginCustomKey","pageTreeWriteContextKey","normalizeNestedDocsPageTreePluginBadgeConfig","DIAGNOSTICS_FLOW_CONTEXT_KEY","createFlowID","projectField","resolveDiagnostics","DEFAULT_BREADCRUMBS_FIELD_SLUG","DEFAULT_HOME_INDICATOR_COLLECTIONS","DEFAULT_LIMIT","DEFAULT_PARENT_FIELD_SLUG","PAGE_TREE_LIST_VIEW_PATH","createDiagnosticsAfterChangeHook","args","collectionSlug","diagnostics","orderableFieldName","parentFieldSlug","snapshotFields","push","doc","operation","previousDoc","req","enabled","context","docID","id","flow","before","after","changed","field","beforeValue","afterValue","JSON","stringify","log","collection","data","String","level","message","source","beforeStatus","_status","afterStatus","getTopLevelField","fieldName","fields","find","name","getCollectionEndpoints","Array","isArray","endpoints","patchBreadcrumbField","breadcrumbsFieldSlug","hideBreadcrumbs","admin","hidden","validateTargetCollection","useAsTitle","includes","Error","slug","existingListView","components","views","list","Component","existingMoveEndpoint","endpoint","path","existingReorderEndpoint","buildCollectionCustom","badges","defaultLimit","homeIndicator","getHomeIndicatorCollectionSlugs","Set","collections","pageTreeMoveContextKey","nestedDocsPageTreePlugin","pluginOptions","config","length","disabled","publishOnMove","homeIndicatorCollectionSlugs","targetedCollectionSlugs","foundCollectionSlugs","nextCollections","map","has","add","orderable","diagnosticsAfterChangeHook","pagination","undefined","custom","hooks","afterChange","missingCollections","filter","join"],"mappings":"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"}
1
+ {"version":3,"sources":["../src/index.ts"],"sourcesContent":["import type {\n CollectionAfterChangeHook,\n CollectionConfig,\n Config,\n} from 'payload'\n\nimport { createMovePageEndpoint } from './endpoints/createMovePageEndpoint.js'\nimport { createReorderPageEndpoint } from './endpoints/createReorderPageEndpoint.js'\nimport type {\n NestedDocsPageTreePluginCollectionCustom,\n NestedDocsPageTreePluginConfig,\n} from './types.js'\nimport { nestedDocsPageTreePluginCustomKey, pageTreeWriteContextKey } from './types.js'\nimport { normalizeNestedDocsPageTreePluginBadgeConfig } from './utilities/badgeConfig.js'\nimport {\n DIAGNOSTICS_FLOW_CONTEXT_KEY,\n type Diagnostics,\n createFlowID,\n projectField,\n resolveDiagnostics,\n} from './utilities/diagnostics.js'\nimport { findTopLevelField, mapTopLevelFields } from './utilities/fields.js'\n\nconst DEFAULT_BREADCRUMBS_FIELD_SLUG = 'breadcrumbs'\nconst DEFAULT_HOME_INDICATOR_COLLECTIONS = ['pages']\nconst DEFAULT_LIMIT = 100\nconst DEFAULT_PARENT_FIELD_SLUG = 'parent'\nconst PAGE_TREE_LIST_VIEW_PATH =\n 'payload-nested-docs-page-tree/rsc#NestedDocsPageTreeListView'\ntype CollectionEndpoint = NonNullable<Exclude<CollectionConfig['endpoints'], false>>[number]\n\n/**\n * When diagnostics are enabled this hook emits a structured event for each\n * page-tree-tagged create/update, including a small before/after diff of the\n * fields most relevant to tree publish/draft regressions.\n */\nfunction createDiagnosticsAfterChangeHook(args: {\n collectionSlug: string\n diagnostics: Diagnostics\n orderableFieldName: null | string\n parentFieldSlug: string\n}): CollectionAfterChangeHook {\n const { collectionSlug, diagnostics, orderableFieldName, parentFieldSlug } = args\n const snapshotFields: string[] = ['_status', parentFieldSlug]\n\n if (orderableFieldName) {\n snapshotFields.push(orderableFieldName)\n }\n\n return async ({ doc, operation, previousDoc, req }) => {\n if (!diagnostics.enabled) {\n return doc\n }\n\n if (operation !== 'update' && operation !== 'create') {\n return doc\n }\n\n // Gated on the write flag, not the deploy opt-out flag: a published move\n // withholds the latter, and that is the case most worth tracing.\n if (!req.context?.[pageTreeWriteContextKey]) {\n return doc\n }\n\n const docID = (doc as Record<string, unknown>)?.id\n\n if (typeof docID !== 'string' && typeof docID !== 'number') {\n return doc\n }\n\n const flow =\n (req.context?.[DIAGNOSTICS_FLOW_CONTEXT_KEY] as string | undefined) ??\n createFlowID('page-tree-change')\n const before: Record<string, unknown> = {}\n const after: Record<string, unknown> = {}\n const changed: string[] = []\n\n for (const field of snapshotFields) {\n const beforeValue = projectField((previousDoc as Record<string, unknown> | undefined)?.[field])\n const afterValue = projectField((doc as Record<string, unknown>)?.[field])\n\n before[field] = beforeValue\n after[field] = afterValue\n\n if (JSON.stringify(beforeValue) !== JSON.stringify(afterValue)) {\n changed.push(field)\n }\n }\n\n diagnostics.log({\n collection: collectionSlug,\n data: {\n after,\n before,\n changed,\n docID: String(docID),\n operation,\n },\n flow,\n level: 'info',\n message: `${operation} on ${collectionSlug}#${String(docID)}`,\n source: 'page-tree-change:after',\n })\n\n const beforeStatus = (previousDoc as Record<string, unknown> | undefined)?._status\n const afterStatus = (doc as Record<string, unknown>)?._status\n\n if (beforeStatus === 'published' && afterStatus !== 'published') {\n diagnostics.log({\n collection: collectionSlug,\n data: {\n afterStatus,\n beforeStatus,\n docID: String(docID),\n },\n flow,\n level: 'warn',\n message: `Published doc was demoted to \"${String(afterStatus ?? 'missing')}\" by a page-tree operation. Inspect the move-endpoint:enter/ok snapshots in flow ${flow} to confirm whether the main row was touched.`,\n source: 'page-tree-change:status-flip',\n })\n }\n\n return doc\n }\n}\n\nfunction getCollectionEndpoints(collection: CollectionConfig): CollectionEndpoint[] {\n return Array.isArray(collection.endpoints) ? [...collection.endpoints] : []\n}\n\nfunction patchBreadcrumbField<TField extends CollectionConfig['fields'][number]>(args: {\n breadcrumbsFieldSlug: string\n field: TField\n hideBreadcrumbs: boolean\n}): TField {\n const { breadcrumbsFieldSlug, field, hideBreadcrumbs } = args\n\n if (!('name' in field) || field.name !== breadcrumbsFieldSlug) {\n return field\n }\n\n return {\n ...field,\n admin: {\n ...(field.admin ?? {}),\n hidden: hideBreadcrumbs,\n },\n } as TField\n}\n\nfunction validateTargetCollection(args: {\n breadcrumbsFieldSlug: string\n collection: CollectionConfig\n parentFieldSlug: string\n}) {\n const { breadcrumbsFieldSlug, collection, parentFieldSlug } = args\n\n if (typeof collection.admin?.useAsTitle !== 'string' || collection.admin.useAsTitle.includes('.')) {\n throw new Error(\n `payload-nested-docs-page-tree requires \"${collection.slug}\" to define a top-level admin.useAsTitle field.`,\n )\n }\n\n if (!findTopLevelField(collection.fields, collection.admin.useAsTitle)) {\n throw new Error(\n `payload-nested-docs-page-tree could not find the useAsTitle field \"${collection.admin.useAsTitle}\" on \"${collection.slug}\". Fields inside tabs, rows, collapsibles, and unnamed groups are supported; fields inside a named tab or named group are not top-level.`,\n )\n }\n\n if (!findTopLevelField(collection.fields, parentFieldSlug)) {\n throw new Error(\n `payload-nested-docs-page-tree requires \"${collection.slug}\" to already define the nested docs parent field \"${parentFieldSlug}\". Register @payloadcms/plugin-nested-docs before payload-nested-docs-page-tree.`,\n )\n }\n\n if (!findTopLevelField(collection.fields, breadcrumbsFieldSlug)) {\n throw new Error(\n `payload-nested-docs-page-tree requires \"${collection.slug}\" to already define the nested docs breadcrumbs field \"${breadcrumbsFieldSlug}\". Register @payloadcms/plugin-nested-docs before payload-nested-docs-page-tree.`,\n )\n }\n\n const existingListView = collection.admin?.components?.views?.list?.Component\n\n if (existingListView && existingListView !== PAGE_TREE_LIST_VIEW_PATH) {\n throw new Error(\n `payload-nested-docs-page-tree cannot own the \"${collection.slug}\" list view because the collection already defines a custom admin.components.views.list.Component.`,\n )\n }\n\n const existingMoveEndpoint = getCollectionEndpoints(collection).find(\n (endpoint) => endpoint.path === '/:id/move',\n )\n const existingReorderEndpoint = getCollectionEndpoints(collection).find(\n (endpoint) => endpoint.path === '/:id/reorder',\n )\n\n if (existingMoveEndpoint) {\n throw new Error(\n `payload-nested-docs-page-tree cannot add the move endpoint to \"${collection.slug}\" because the collection already defines POST /:id/move.`,\n )\n }\n\n if (existingReorderEndpoint) {\n throw new Error(\n `payload-nested-docs-page-tree cannot add the reorder endpoint to \"${collection.slug}\" because the collection already defines POST /:id/reorder.`,\n )\n }\n}\n\nfunction buildCollectionCustom(args: {\n badges: NestedDocsPageTreePluginCollectionCustom['badges']\n breadcrumbsFieldSlug: string\n defaultLimit: number\n hideBreadcrumbs: boolean\n homeIndicator: NestedDocsPageTreePluginCollectionCustom['homeIndicator']\n parentFieldSlug: string\n}): NestedDocsPageTreePluginCollectionCustom {\n const {\n badges,\n breadcrumbsFieldSlug,\n defaultLimit,\n hideBreadcrumbs,\n homeIndicator,\n parentFieldSlug,\n } = args\n\n return {\n badges,\n breadcrumbsFieldSlug,\n defaultLimit,\n hideBreadcrumbs,\n homeIndicator,\n parentFieldSlug,\n }\n}\n\nfunction getHomeIndicatorCollectionSlugs(\n homeIndicator: NestedDocsPageTreePluginConfig['homeIndicator'],\n): Set<string> {\n if (homeIndicator === false) {\n return new Set()\n }\n\n return new Set(homeIndicator?.collections ?? DEFAULT_HOME_INDICATOR_COLLECTIONS)\n}\n\nexport type {\n NestedDocsPageTreePluginBadgeConfig,\n NestedDocsPageTreePluginBadgeMap,\n NestedDocsPageTreePluginBadgeStatus,\n NestedDocsPageTreePluginConfig,\n NestedDocsPageTreePluginHomeIndicatorConfig,\n PageTreeMoveContext,\n} from './types.js'\n\nexport { pageTreeMoveContextKey } from './types.js'\n\nexport const nestedDocsPageTreePlugin =\n (pluginOptions: NestedDocsPageTreePluginConfig) =>\n (config: Config): Config => {\n if (!pluginOptions.collections?.length) {\n throw new Error('payload-nested-docs-page-tree requires at least one collection slug.')\n }\n\n if (pluginOptions.disabled) {\n return config\n }\n\n const breadcrumbsFieldSlug =\n pluginOptions.breadcrumbsFieldSlug ?? DEFAULT_BREADCRUMBS_FIELD_SLUG\n const defaultLimit = pluginOptions.defaultLimit ?? DEFAULT_LIMIT\n const hideBreadcrumbs = pluginOptions.hideBreadcrumbs ?? true\n const parentFieldSlug = pluginOptions.parentFieldSlug ?? DEFAULT_PARENT_FIELD_SLUG\n const publishOnMove = pluginOptions.publishOnMove ?? false\n const badges = normalizeNestedDocsPageTreePluginBadgeConfig(pluginOptions.badges)\n const diagnostics = resolveDiagnostics(pluginOptions.diagnostics)\n const homeIndicatorCollectionSlugs = getHomeIndicatorCollectionSlugs(\n pluginOptions.homeIndicator,\n )\n const targetedCollectionSlugs = new Set<string>(pluginOptions.collections)\n\n if (!config.collections?.length) {\n throw new Error('payload-nested-docs-page-tree could not find any collections to patch.')\n }\n\n const foundCollectionSlugs = new Set<string>()\n const nextCollections = config.collections.map((collection) => {\n if (!targetedCollectionSlugs.has(collection.slug)) {\n return collection\n }\n\n foundCollectionSlugs.add(collection.slug)\n validateTargetCollection({\n breadcrumbsFieldSlug,\n collection,\n parentFieldSlug,\n })\n const orderableFieldName =\n typeof collection.orderable === 'string'\n ? collection.orderable\n : collection.orderable\n ? '_order'\n : null\n const diagnosticsAfterChangeHook = diagnostics.enabled\n ? createDiagnosticsAfterChangeHook({\n collectionSlug: collection.slug,\n diagnostics,\n orderableFieldName,\n parentFieldSlug,\n })\n : null\n\n return {\n ...collection,\n admin: {\n ...(collection.admin ?? {}),\n components: {\n ...(collection.admin?.components ?? {}),\n views: {\n ...(collection.admin?.components?.views ?? {}),\n list: {\n ...(collection.admin?.components?.views?.list ?? {}),\n Component: PAGE_TREE_LIST_VIEW_PATH,\n },\n },\n },\n pagination: {\n ...(collection.admin?.pagination ?? {}),\n defaultLimit:\n collection.admin?.pagination?.defaultLimit === undefined\n ? defaultLimit\n : collection.admin.pagination.defaultLimit,\n },\n },\n custom: {\n ...(collection.custom ?? {}),\n [nestedDocsPageTreePluginCustomKey]: buildCollectionCustom({\n badges,\n breadcrumbsFieldSlug,\n defaultLimit,\n hideBreadcrumbs,\n homeIndicator: {\n enabled: homeIndicatorCollectionSlugs.has(collection.slug),\n },\n parentFieldSlug,\n }),\n },\n endpoints: [\n ...getCollectionEndpoints(collection),\n createMovePageEndpoint({\n collectionSlug: collection.slug,\n diagnostics,\n parentFieldSlug,\n publishOnMove,\n }),\n ...(orderableFieldName\n ? [\n createReorderPageEndpoint({\n collectionSlug: collection.slug,\n diagnostics,\n orderableFieldName,\n parentFieldSlug,\n }),\n ]\n : []),\n ],\n fields: mapTopLevelFields(collection.fields, (field) =>\n patchBreadcrumbField({\n breadcrumbsFieldSlug,\n field,\n hideBreadcrumbs,\n }),\n ),\n hooks: {\n ...(collection.hooks ?? {}),\n ...(diagnosticsAfterChangeHook\n ? {\n afterChange: [\n ...(collection.hooks?.afterChange ?? []),\n diagnosticsAfterChangeHook,\n ],\n }\n : {}),\n },\n }\n })\n\n const missingCollections = pluginOptions.collections.filter(\n (collectionSlug) => !foundCollectionSlugs.has(collectionSlug),\n )\n\n if (missingCollections.length > 0) {\n throw new Error(\n `payload-nested-docs-page-tree could not find the following collections: ${missingCollections.join(', ')}`,\n )\n }\n\n return {\n ...config,\n collections: nextCollections as CollectionConfig[],\n }\n }\n"],"names":["createMovePageEndpoint","createReorderPageEndpoint","nestedDocsPageTreePluginCustomKey","pageTreeWriteContextKey","normalizeNestedDocsPageTreePluginBadgeConfig","DIAGNOSTICS_FLOW_CONTEXT_KEY","createFlowID","projectField","resolveDiagnostics","findTopLevelField","mapTopLevelFields","DEFAULT_BREADCRUMBS_FIELD_SLUG","DEFAULT_HOME_INDICATOR_COLLECTIONS","DEFAULT_LIMIT","DEFAULT_PARENT_FIELD_SLUG","PAGE_TREE_LIST_VIEW_PATH","createDiagnosticsAfterChangeHook","args","collectionSlug","diagnostics","orderableFieldName","parentFieldSlug","snapshotFields","push","doc","operation","previousDoc","req","enabled","context","docID","id","flow","before","after","changed","field","beforeValue","afterValue","JSON","stringify","log","collection","data","String","level","message","source","beforeStatus","_status","afterStatus","getCollectionEndpoints","Array","isArray","endpoints","patchBreadcrumbField","breadcrumbsFieldSlug","hideBreadcrumbs","name","admin","hidden","validateTargetCollection","useAsTitle","includes","Error","slug","fields","existingListView","components","views","list","Component","existingMoveEndpoint","find","endpoint","path","existingReorderEndpoint","buildCollectionCustom","badges","defaultLimit","homeIndicator","getHomeIndicatorCollectionSlugs","Set","collections","pageTreeMoveContextKey","nestedDocsPageTreePlugin","pluginOptions","config","length","disabled","publishOnMove","homeIndicatorCollectionSlugs","targetedCollectionSlugs","foundCollectionSlugs","nextCollections","map","has","add","orderable","diagnosticsAfterChangeHook","pagination","undefined","custom","hooks","afterChange","missingCollections","filter","join"],"mappings":"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"}
@@ -0,0 +1,11 @@
1
+ import type { Field } from 'payload';
2
+ /**
3
+ * Finds the field stored under `fieldName` at the top level of the document,
4
+ * looking through presentational containers such as tabs and rows.
5
+ */
6
+ export declare function findTopLevelField(fields: Field[], fieldName: string): Field | undefined;
7
+ /**
8
+ * Maps `mapField` over every field stored at the top level of the document,
9
+ * rebuilding presentational containers so nested fields are patched in place.
10
+ */
11
+ export declare function mapTopLevelFields(fields: Field[], mapField: (field: Field) => Field): Field[];
@@ -0,0 +1,61 @@
1
+ /**
2
+ * Rows, collapsibles, unnamed groups, and unnamed tabs are presentational
3
+ * only: Payload stores their children directly on the document, so a field
4
+ * nested inside one is still a top-level field as far as the data is
5
+ * concerned. Named groups and named tabs nest their children under their own
6
+ * key, so traversal stops at those.
7
+ */ function getPresentationalChildFields(field) {
8
+ if (field.type === 'row' || field.type === 'collapsible') {
9
+ return field.fields;
10
+ }
11
+ if (field.type === 'group' && !('name' in field)) {
12
+ return field.fields;
13
+ }
14
+ if (field.type === 'tabs') {
15
+ return field.tabs.flatMap((tab)=>'name' in tab ? [] : tab.fields);
16
+ }
17
+ return null;
18
+ }
19
+ /**
20
+ * Finds the field stored under `fieldName` at the top level of the document,
21
+ * looking through presentational containers such as tabs and rows.
22
+ */ export function findTopLevelField(fields, fieldName) {
23
+ for (const field of fields){
24
+ if ('name' in field && field.name === fieldName) {
25
+ return field;
26
+ }
27
+ const childFields = getPresentationalChildFields(field);
28
+ if (childFields) {
29
+ const match = findTopLevelField(childFields, fieldName);
30
+ if (match) {
31
+ return match;
32
+ }
33
+ }
34
+ }
35
+ return undefined;
36
+ }
37
+ /**
38
+ * Maps `mapField` over every field stored at the top level of the document,
39
+ * rebuilding presentational containers so nested fields are patched in place.
40
+ */ export function mapTopLevelFields(fields, mapField) {
41
+ return fields.map((field)=>{
42
+ if (field.type === 'row' || field.type === 'collapsible' || field.type === 'group' && !('name' in field)) {
43
+ return {
44
+ ...field,
45
+ fields: mapTopLevelFields(field.fields, mapField)
46
+ };
47
+ }
48
+ if (field.type === 'tabs') {
49
+ return {
50
+ ...field,
51
+ tabs: field.tabs.map((tab)=>'name' in tab ? tab : {
52
+ ...tab,
53
+ fields: mapTopLevelFields(tab.fields, mapField)
54
+ })
55
+ };
56
+ }
57
+ return mapField(field);
58
+ });
59
+ }
60
+
61
+ //# sourceMappingURL=fields.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/utilities/fields.ts"],"sourcesContent":["import type { Field } from 'payload'\n\n/**\n * Rows, collapsibles, unnamed groups, and unnamed tabs are presentational\n * only: Payload stores their children directly on the document, so a field\n * nested inside one is still a top-level field as far as the data is\n * concerned. Named groups and named tabs nest their children under their own\n * key, so traversal stops at those.\n */\nfunction getPresentationalChildFields(field: Field): Field[] | null {\n if (field.type === 'row' || field.type === 'collapsible') {\n return field.fields\n }\n\n if (field.type === 'group' && !('name' in field)) {\n return field.fields\n }\n\n if (field.type === 'tabs') {\n return field.tabs.flatMap((tab) => ('name' in tab ? [] : tab.fields))\n }\n\n return null\n}\n\n/**\n * Finds the field stored under `fieldName` at the top level of the document,\n * looking through presentational containers such as tabs and rows.\n */\nexport function findTopLevelField(fields: Field[], fieldName: string): Field | undefined {\n for (const field of fields) {\n if ('name' in field && field.name === fieldName) {\n return field\n }\n\n const childFields = getPresentationalChildFields(field)\n\n if (childFields) {\n const match = findTopLevelField(childFields, fieldName)\n\n if (match) {\n return match\n }\n }\n }\n\n return undefined\n}\n\n/**\n * Maps `mapField` over every field stored at the top level of the document,\n * rebuilding presentational containers so nested fields are patched in place.\n */\nexport function mapTopLevelFields(\n fields: Field[],\n mapField: (field: Field) => Field,\n): Field[] {\n return fields.map((field) => {\n if (\n field.type === 'row' ||\n field.type === 'collapsible' ||\n (field.type === 'group' && !('name' in field))\n ) {\n return {\n ...field,\n fields: mapTopLevelFields(field.fields, mapField),\n } as Field\n }\n\n if (field.type === 'tabs') {\n return {\n ...field,\n tabs: field.tabs.map((tab) =>\n 'name' in tab\n ? tab\n : {\n ...tab,\n fields: mapTopLevelFields(tab.fields, mapField),\n },\n ),\n } as Field\n }\n\n return mapField(field)\n })\n}\n"],"names":["getPresentationalChildFields","field","type","fields","tabs","flatMap","tab","findTopLevelField","fieldName","name","childFields","match","undefined","mapTopLevelFields","mapField","map"],"mappings":"AAEA;;;;;;CAMC,GACD,SAASA,6BAA6BC,KAAY;IAChD,IAAIA,MAAMC,IAAI,KAAK,SAASD,MAAMC,IAAI,KAAK,eAAe;QACxD,OAAOD,MAAME,MAAM;IACrB;IAEA,IAAIF,MAAMC,IAAI,KAAK,WAAW,CAAE,CAAA,UAAUD,KAAI,GAAI;QAChD,OAAOA,MAAME,MAAM;IACrB;IAEA,IAAIF,MAAMC,IAAI,KAAK,QAAQ;QACzB,OAAOD,MAAMG,IAAI,CAACC,OAAO,CAAC,CAACC,MAAS,UAAUA,MAAM,EAAE,GAAGA,IAAIH,MAAM;IACrE;IAEA,OAAO;AACT;AAEA;;;CAGC,GACD,OAAO,SAASI,kBAAkBJ,MAAe,EAAEK,SAAiB;IAClE,KAAK,MAAMP,SAASE,OAAQ;QAC1B,IAAI,UAAUF,SAASA,MAAMQ,IAAI,KAAKD,WAAW;YAC/C,OAAOP;QACT;QAEA,MAAMS,cAAcV,6BAA6BC;QAEjD,IAAIS,aAAa;YACf,MAAMC,QAAQJ,kBAAkBG,aAAaF;YAE7C,IAAIG,OAAO;gBACT,OAAOA;YACT;QACF;IACF;IAEA,OAAOC;AACT;AAEA;;;CAGC,GACD,OAAO,SAASC,kBACdV,MAAe,EACfW,QAAiC;IAEjC,OAAOX,OAAOY,GAAG,CAAC,CAACd;QACjB,IACEA,MAAMC,IAAI,KAAK,SACfD,MAAMC,IAAI,KAAK,iBACdD,MAAMC,IAAI,KAAK,WAAW,CAAE,CAAA,UAAUD,KAAI,GAC3C;YACA,OAAO;gBACL,GAAGA,KAAK;gBACRE,QAAQU,kBAAkBZ,MAAME,MAAM,EAAEW;YAC1C;QACF;QAEA,IAAIb,MAAMC,IAAI,KAAK,QAAQ;YACzB,OAAO;gBACL,GAAGD,KAAK;gBACRG,MAAMH,MAAMG,IAAI,CAACW,GAAG,CAAC,CAACT,MACpB,UAAUA,MACNA,MACA;wBACE,GAAGA,GAAG;wBACNH,QAAQU,kBAAkBP,IAAIH,MAAM,EAAEW;oBACxC;YAER;QACF;QAEA,OAAOA,SAASb;IAClB;AACF"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "payload-nested-docs-page-tree",
3
- "version": "1.4.1",
3
+ "version": "1.4.2",
4
4
  "description": "Page tree plugin for Payload nested docs collections",
5
5
  "license": "MIT",
6
6
  "author": "WLF Studios",