payload-nested-docs-page-tree 1.5.1 → 1.6.0

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.
Files changed (35) hide show
  1. package/README.md +141 -7
  2. package/dist/components/PageTreeListView.client.js +9 -4
  3. package/dist/components/PageTreeListView.client.js.map +1 -1
  4. package/dist/components/PageTreeListView.module.css +27 -0
  5. package/dist/components/PageTreeListView.server.js +30 -14
  6. package/dist/components/PageTreeListView.server.js.map +1 -1
  7. package/dist/components/PageTreeLocaleStatusBadges.d.ts +7 -0
  8. package/dist/components/PageTreeLocaleStatusBadges.js +79 -0
  9. package/dist/components/PageTreeLocaleStatusBadges.js.map +1 -0
  10. package/dist/components/PageTreeStatusBadge.d.ts +2 -1
  11. package/dist/components/PageTreeStatusBadge.js +10 -1
  12. package/dist/components/PageTreeStatusBadge.js.map +1 -1
  13. package/dist/components/PageTreeTitleCell.js +8 -8
  14. package/dist/components/PageTreeTitleCell.js.map +1 -1
  15. package/dist/index.d.ts +1 -1
  16. package/dist/index.js +8 -4
  17. package/dist/index.js.map +1 -1
  18. package/dist/types.d.ts +47 -8
  19. package/dist/types.js.map +1 -1
  20. package/dist/utilities/badgeConfig.js +3 -0
  21. package/dist/utilities/badgeConfig.js.map +1 -1
  22. package/dist/utilities/badgeLinks.d.ts +1 -1
  23. package/dist/utilities/badgeLinks.js +13 -3
  24. package/dist/utilities/badgeLinks.js.map +1 -1
  25. package/dist/utilities/localeStatus.d.ts +11 -0
  26. package/dist/utilities/localeStatus.js +83 -0
  27. package/dist/utilities/localeStatus.js.map +1 -0
  28. package/dist/utilities/pageTree.js +1 -1
  29. package/dist/utilities/pageTree.js.map +1 -1
  30. package/dist/utilities/pageTreeConfig.d.ts +1 -1
  31. package/dist/utilities/pageTreeConfig.js +2 -0
  32. package/dist/utilities/pageTreeConfig.js.map +1 -1
  33. package/dist/utilities/status.d.ts +2 -2
  34. package/dist/utilities/status.js.map +1 -1
  35. package/package.json +1 -1
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'\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 badgesLinks?: NestedDocsPageTreePluginConfig['badgesLinks']\n breadcrumbsFieldSlug: string\n defaultLimit: number\n hideBreadcrumbs: boolean\n homeIndicator: NestedDocsPageTreePluginCollectionCustom['homeIndicator']\n parentFieldSlug: string\n}): NestedDocsPageTreePluginCollectionCustom {\n const {\n badges,\n badgesLinks,\n breadcrumbsFieldSlug,\n defaultLimit,\n hideBreadcrumbs,\n homeIndicator,\n parentFieldSlug,\n } = args\n\n return {\n badges,\n badgesLinks,\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 NestedDocsPageTreePluginBadgesLinks,\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 badgesLinks: pluginOptions.badgesLinks,\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","badgesLinks","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 type {\n NestedDocsPageTreePluginCollectionCustom,\n NestedDocsPageTreePluginConfig,\n} from './types.js'\n\nimport { createMovePageEndpoint } from './endpoints/createMovePageEndpoint.js'\nimport { createReorderPageEndpoint } from './endpoints/createReorderPageEndpoint.js'\nimport { nestedDocsPageTreePluginCustomKey, pageTreeWriteContextKey } from './types.js'\nimport { normalizeNestedDocsPageTreePluginBadgeConfig } from './utilities/badgeConfig.js'\nimport {\n createFlowID,\n type Diagnostics,\n DIAGNOSTICS_FLOW_CONTEXT_KEY,\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 ({ 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 \"${typeof afterStatus === 'string' ? afterStatus : JSON.stringify(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 badgesLinks?: NestedDocsPageTreePluginConfig['badgesLinks']\n breadcrumbsFieldSlug: string\n defaultLimit: number\n hideBreadcrumbs: boolean\n homeIndicator: NestedDocsPageTreePluginCollectionCustom['homeIndicator']\n localeBadgeStatus?: NestedDocsPageTreePluginConfig['localeBadgeStatus']\n localeBadgeVisibility?: NestedDocsPageTreePluginConfig['localeBadgeVisibility']\n parentFieldSlug: string\n}): NestedDocsPageTreePluginCollectionCustom {\n const {\n badges,\n badgesLinks,\n breadcrumbsFieldSlug,\n defaultLimit,\n hideBreadcrumbs,\n homeIndicator,\n localeBadgeStatus,\n localeBadgeVisibility,\n parentFieldSlug,\n } = args\n\n return {\n badges,\n badgesLinks,\n breadcrumbsFieldSlug,\n defaultLimit,\n hideBreadcrumbs,\n homeIndicator,\n localeBadgeStatus,\n localeBadgeVisibility,\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 NestedDocsPageTreePluginBadgesLinks,\n NestedDocsPageTreePluginBadgeStatus,\n NestedDocsPageTreePluginConfig,\n NestedDocsPageTreePluginHomeIndicatorConfig,\n PageTreeLiveURL,\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 badgesLinks: pluginOptions.badgesLinks,\n breadcrumbsFieldSlug,\n defaultLimit,\n hideBreadcrumbs,\n homeIndicator: {\n enabled: homeIndicatorCollectionSlugs.has(collection.slug),\n },\n localeBadgeStatus: pluginOptions.localeBadgeStatus,\n localeBadgeVisibility: pluginOptions.localeBadgeVisibility,\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,\n }\n }\n"],"names":["createMovePageEndpoint","createReorderPageEndpoint","nestedDocsPageTreePluginCustomKey","pageTreeWriteContextKey","normalizeNestedDocsPageTreePluginBadgeConfig","createFlowID","DIAGNOSTICS_FLOW_CONTEXT_KEY","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","badgesLinks","defaultLimit","homeIndicator","localeBadgeStatus","localeBadgeVisibility","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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"}
package/dist/types.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import type { CollectionSlug } from 'payload';
1
+ import type { CollectionSlug, PayloadRequest } from 'payload';
2
2
  import type { NestedDocsPageTreePluginDiagnosticsConfig } from './utilities/diagnostics.js';
3
3
  export type { NestedDocsPageTreePluginDiagnosticEvent, NestedDocsPageTreePluginDiagnosticsConfig, } from './utilities/diagnostics.js';
4
4
  export declare const nestedDocsPageTreePluginBadgeStatuses: readonly ["published", "changed", "draft"];
@@ -7,17 +7,35 @@ export type NestedDocsPageTreePluginBadgeMap = Partial<Record<NestedDocsPageTree
7
7
  export type NestedDocsPageTreePluginBadgeConfig = {
8
8
  colors?: NestedDocsPageTreePluginBadgeMap;
9
9
  labels?: NestedDocsPageTreePluginBadgeMap;
10
+ /** Show locale badges when the collection enables localized draft status. */
11
+ locales?: boolean;
10
12
  };
11
13
  export type NestedDocsPageTreePluginResolvedBadgeConfig = {
12
14
  colors: NestedDocsPageTreePluginBadgeMap;
13
15
  labels: NestedDocsPageTreePluginBadgeMap;
16
+ locales?: boolean;
14
17
  };
15
- export type NestedDocsPageTreePluginHomeIndicatorConfig = false | {
18
+ export type NestedDocsPageTreePluginHomeIndicatorConfig = {
16
19
  collections?: CollectionSlug[];
17
- };
20
+ } | false;
18
21
  export type NestedDocsPageTreePluginResolvedHomeIndicatorConfig = {
19
22
  enabled: boolean;
20
23
  };
24
+ export type PageTreeLocaleBadgeVisibility = (args: {
25
+ /** Latest draft document with all locales, read with the current user's access. */
26
+ doc: Record<string, unknown>;
27
+ locale: string;
28
+ req: PayloadRequest;
29
+ }) => boolean;
30
+ export type PageTreeLocaleBadgeStatus = (args: {
31
+ /** Latest draft document with all locales, read with the current user's access. */
32
+ doc: Record<string, unknown>;
33
+ locale: string;
34
+ /** Current document, if readable. Check its locale status before treating it as published. */
35
+ publishedDoc?: Record<string, unknown>;
36
+ req: PayloadRequest;
37
+ status: PageTreeLocaleStatus['status'];
38
+ }) => PageTreeLocaleStatus['status'];
21
39
  export type NestedDocsPageTreePluginConfig = {
22
40
  badges?: NestedDocsPageTreePluginBadgeConfig;
23
41
  /** Opt in to status badge links. Preview uses the collection's admin.preview. */
@@ -35,6 +53,10 @@ export type NestedDocsPageTreePluginConfig = {
35
53
  disabled?: boolean;
36
54
  hideBreadcrumbs?: boolean;
37
55
  homeIndicator?: NestedDocsPageTreePluginHomeIndicatorConfig;
56
+ /** Server-only display override. Does not change stored publication status. */
57
+ localeBadgeStatus?: PageTreeLocaleBadgeStatus;
58
+ /** Server-only rule. False hides the badge while preserving its aligned slot. */
59
+ localeBadgeVisibility?: PageTreeLocaleBadgeVisibility;
38
60
  parentFieldSlug?: string;
39
61
  /**
40
62
  * Publish a hierarchy move immediately instead of staging it as a draft - but
@@ -58,13 +80,24 @@ export type NestedDocsPageTreePluginCollectionCustom = {
58
80
  defaultLimit: number;
59
81
  hideBreadcrumbs: boolean;
60
82
  homeIndicator: NestedDocsPageTreePluginResolvedHomeIndicatorConfig;
83
+ localeBadgeStatus?: PageTreeLocaleBadgeStatus;
84
+ localeBadgeVisibility?: PageTreeLocaleBadgeVisibility;
61
85
  parentFieldSlug: string;
62
86
  };
63
- export type NestedDocsPageTreePluginBadgesLinks = {
87
+ export type PageTreeLiveURL<TRequest = PayloadRequest> = (args: {
88
+ collectionSlug: string;
89
+ /** Published document read with the current user's access, at depth 0. */
90
+ doc: PageTreeSourceDoc;
91
+ locale?: string;
92
+ /** Published document's last breadcrumb URL, when available. */
93
+ path?: string;
94
+ req: TRequest;
95
+ }) => null | Promise<null | string | undefined> | string | undefined;
96
+ export type NestedDocsPageTreePluginBadgesLinks<TRequest = PayloadRequest> = {
64
97
  /** Which links to offer for a draft with a published version. @default 'both' */
65
98
  draftHasPublishedVersion?: 'both' | 'live' | 'preview';
66
- /** Website base URL, resolved with the published document's last breadcrumb URL. */
67
- liveURL?: string;
99
+ /** Website base URL, or a server-only callback returning the final live URL. */
100
+ liveURL?: PageTreeLiveURL<TRequest> | string;
68
101
  /** Show live link and preview eye icons. When false, 'both' keeps an external-link preview action. @default true */
69
102
  showIcons?: boolean;
70
103
  };
@@ -72,13 +105,19 @@ export type PageTreeStatusLinks = {
72
105
  previewURL?: string;
73
106
  publicURL?: string;
74
107
  };
75
- export type PageTreeSourceDoc = Record<string, unknown> & {
108
+ export type PageTreeLocaleStatus = {
109
+ locale: string;
110
+ status: 'changed' | 'draft' | 'published' | 'unknown';
111
+ visible?: boolean;
112
+ };
113
+ export type PageTreeSourceDoc = {
114
+ __pageTreeLocaleStatuses?: PageTreeLocaleStatus[];
76
115
  __pageTreeStatusLinks?: PageTreeStatusLinks;
77
116
  _displayStatus?: null | string;
78
117
  _status?: null | string;
79
118
  id?: number | string;
80
119
  slug?: null | string;
81
- };
120
+ } & Record<string, unknown>;
82
121
  export declare const nestedDocsPageTreePluginCustomKey = "nestedDocsPageTreePlugin";
83
122
  /**
84
123
  * Set on Payload's hook context for every page-tree write that leaves the
package/dist/types.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/types.ts"],"sourcesContent":["import type { CollectionSlug } from 'payload'\n\nimport type { NestedDocsPageTreePluginDiagnosticsConfig } from './utilities/diagnostics.js'\n\nexport type {\n NestedDocsPageTreePluginDiagnosticEvent,\n NestedDocsPageTreePluginDiagnosticsConfig,\n} from './utilities/diagnostics.js'\n\nexport const nestedDocsPageTreePluginBadgeStatuses = ['published', 'changed', 'draft'] as const\n\nexport type NestedDocsPageTreePluginBadgeStatus =\n (typeof nestedDocsPageTreePluginBadgeStatuses)[number]\n\nexport type NestedDocsPageTreePluginBadgeMap = Partial<\n Record<NestedDocsPageTreePluginBadgeStatus, string>\n>\n\nexport type NestedDocsPageTreePluginBadgeConfig = {\n colors?: NestedDocsPageTreePluginBadgeMap\n labels?: NestedDocsPageTreePluginBadgeMap\n}\n\nexport type NestedDocsPageTreePluginResolvedBadgeConfig = {\n colors: NestedDocsPageTreePluginBadgeMap\n labels: NestedDocsPageTreePluginBadgeMap\n}\n\nexport type NestedDocsPageTreePluginHomeIndicatorConfig =\n | false\n | {\n collections?: CollectionSlug[]\n }\n\nexport type NestedDocsPageTreePluginResolvedHomeIndicatorConfig = {\n enabled: boolean\n}\n\nexport type NestedDocsPageTreePluginConfig = {\n badges?: NestedDocsPageTreePluginBadgeConfig\n /** Opt in to status badge links. Preview uses the collection's admin.preview. */\n badgesLinks?: NestedDocsPageTreePluginBadgesLinks\n breadcrumbsFieldSlug?: string\n collections: CollectionSlug[]\n defaultLimit?: number\n /**\n * When set, the plugin emits structured diagnostic events for page-tree\n * triggered moves, including before/after snapshots of the published main row.\n * Disabled by default. Pass `true` to log to `console`, or pass an object\n * with a custom `logger` to route events elsewhere.\n */\n diagnostics?: NestedDocsPageTreePluginDiagnosticsConfig\n disabled?: boolean\n hideBreadcrumbs?: boolean\n homeIndicator?: NestedDocsPageTreePluginHomeIndicatorConfig\n parentFieldSlug?: string\n /**\n * Publish a hierarchy move immediately instead of staging it as a draft - but\n * ONLY when the moved document had no unpublished changes before the move (its\n * latest version is already published). A document with pending draft edits (a\n * \"changed\" or draft-only doc) always stays staged, so in-progress edits are\n * never published as a side effect of a move. Only affects collections with\n * drafts enabled; collections without drafts move live regardless.\n *\n * Disabled by default: every move is staged as a draft and the live URL/path\n * changes only when the document is next published.\n *\n * @default false\n */\n publishOnMove?: boolean\n}\n\nexport type NestedDocsPageTreePluginCollectionCustom = {\n badges: NestedDocsPageTreePluginResolvedBadgeConfig\n badgesLinks?: NestedDocsPageTreePluginBadgesLinks\n breadcrumbsFieldSlug: string\n defaultLimit: number\n hideBreadcrumbs: boolean\n homeIndicator: NestedDocsPageTreePluginResolvedHomeIndicatorConfig\n parentFieldSlug: string\n}\n\nexport type NestedDocsPageTreePluginBadgesLinks = {\n /** Which links to offer for a draft with a published version. @default 'both' */\n draftHasPublishedVersion?: 'both' | 'live' | 'preview'\n /** Website base URL, resolved with the published document's last breadcrumb URL. */\n liveURL?: string\n /** Show live link and preview eye icons. When false, 'both' keeps an external-link preview action. @default true */\n showIcons?: boolean\n}\n\nexport type PageTreeStatusLinks = {\n previewURL?: string\n publicURL?: string\n}\n\nexport type PageTreeSourceDoc = Record<string, unknown> & {\n __pageTreeStatusLinks?: PageTreeStatusLinks\n _displayStatus?: null | string\n _status?: null | string\n id?: number | string\n slug?: null | string\n}\n\nexport const nestedDocsPageTreePluginCustomKey = 'nestedDocsPageTreePlugin'\n\n/**\n * Set on Payload's hook context for every page-tree write that leaves the\n * published site unchanged: sibling reorders, and parent moves staged as\n * drafts. Deploy/revalidate hooks read it to skip rebuilds they do not need.\n *\n * It is deliberately NOT set when `publishOnMove` publishes a move, because\n * that move changed the live URL of the page and its descendants and the site\n * does need rebuilding. That way one guard covers every configuration:\n *\n * ```ts\n * if (req.context?.[pageTreeMoveContextKey]) return\n * ```\n *\n * Note the flag describes the *effect* of the write, not its kind - it is\n * absent on published moves even though those are still page-tree moves. Use\n * `pageTreeWriteContextKey` when you need \"was this a page-tree write at all\".\n */\nexport const pageTreeMoveContextKey = 'pageTreeMove'\n\n/**\n * Internal: set on every page-tree write regardless of whether it published.\n * Diagnostics uses it so that published moves are still traced, which is the\n * case most worth observing. Not part of the public API.\n */\nexport const pageTreeWriteContextKey = 'pageTreeWrite'\n\nexport type PageTreeMoveContext = {\n [pageTreeMoveContextKey]?: boolean\n [pageTreeWriteContextKey]?: boolean\n}\n"],"names":["nestedDocsPageTreePluginBadgeStatuses","nestedDocsPageTreePluginCustomKey","pageTreeMoveContextKey","pageTreeWriteContextKey"],"mappings":"AASA,OAAO,MAAMA,wCAAwC;IAAC;IAAa;IAAW;CAAQ,CAAS;AA+F/F,OAAO,MAAMC,oCAAoC,2BAA0B;AAE3E;;;;;;;;;;;;;;;;CAgBC,GACD,OAAO,MAAMC,yBAAyB,eAAc;AAEpD;;;;CAIC,GACD,OAAO,MAAMC,0BAA0B,gBAAe"}
1
+ {"version":3,"sources":["../src/types.ts"],"sourcesContent":["import type { CollectionSlug, PayloadRequest } from 'payload'\n\nimport type { NestedDocsPageTreePluginDiagnosticsConfig } from './utilities/diagnostics.js'\n\nexport type {\n NestedDocsPageTreePluginDiagnosticEvent,\n NestedDocsPageTreePluginDiagnosticsConfig,\n} from './utilities/diagnostics.js'\n\nexport const nestedDocsPageTreePluginBadgeStatuses = ['published', 'changed', 'draft'] as const\n\nexport type NestedDocsPageTreePluginBadgeStatus =\n (typeof nestedDocsPageTreePluginBadgeStatuses)[number]\n\nexport type NestedDocsPageTreePluginBadgeMap = Partial<\n Record<NestedDocsPageTreePluginBadgeStatus, string>\n>\n\nexport type NestedDocsPageTreePluginBadgeConfig = {\n colors?: NestedDocsPageTreePluginBadgeMap\n labels?: NestedDocsPageTreePluginBadgeMap\n /** Show locale badges when the collection enables localized draft status. */\n locales?: boolean\n}\n\nexport type NestedDocsPageTreePluginResolvedBadgeConfig = {\n colors: NestedDocsPageTreePluginBadgeMap\n labels: NestedDocsPageTreePluginBadgeMap\n locales?: boolean\n}\n\nexport type NestedDocsPageTreePluginHomeIndicatorConfig =\n | {\n collections?: CollectionSlug[]\n }\n | false\n\nexport type NestedDocsPageTreePluginResolvedHomeIndicatorConfig = {\n enabled: boolean\n}\n\nexport type PageTreeLocaleBadgeVisibility = (args: {\n /** Latest draft document with all locales, read with the current user's access. */\n doc: Record<string, unknown>\n locale: string\n req: PayloadRequest\n}) => boolean\n\nexport type PageTreeLocaleBadgeStatus = (args: {\n /** Latest draft document with all locales, read with the current user's access. */\n doc: Record<string, unknown>\n locale: string\n /** Current document, if readable. Check its locale status before treating it as published. */\n publishedDoc?: Record<string, unknown>\n req: PayloadRequest\n status: PageTreeLocaleStatus['status']\n}) => PageTreeLocaleStatus['status']\n\nexport type NestedDocsPageTreePluginConfig = {\n badges?: NestedDocsPageTreePluginBadgeConfig\n /** Opt in to status badge links. Preview uses the collection's admin.preview. */\n badgesLinks?: NestedDocsPageTreePluginBadgesLinks\n breadcrumbsFieldSlug?: string\n collections: CollectionSlug[]\n defaultLimit?: number\n /**\n * When set, the plugin emits structured diagnostic events for page-tree\n * triggered moves, including before/after snapshots of the published main row.\n * Disabled by default. Pass `true` to log to `console`, or pass an object\n * with a custom `logger` to route events elsewhere.\n */\n diagnostics?: NestedDocsPageTreePluginDiagnosticsConfig\n disabled?: boolean\n hideBreadcrumbs?: boolean\n homeIndicator?: NestedDocsPageTreePluginHomeIndicatorConfig\n /** Server-only display override. Does not change stored publication status. */\n localeBadgeStatus?: PageTreeLocaleBadgeStatus\n /** Server-only rule. False hides the badge while preserving its aligned slot. */\n localeBadgeVisibility?: PageTreeLocaleBadgeVisibility\n parentFieldSlug?: string\n /**\n * Publish a hierarchy move immediately instead of staging it as a draft - but\n * ONLY when the moved document had no unpublished changes before the move (its\n * latest version is already published). A document with pending draft edits (a\n * \"changed\" or draft-only doc) always stays staged, so in-progress edits are\n * never published as a side effect of a move. Only affects collections with\n * drafts enabled; collections without drafts move live regardless.\n *\n * Disabled by default: every move is staged as a draft and the live URL/path\n * changes only when the document is next published.\n *\n * @default false\n */\n publishOnMove?: boolean\n}\n\nexport type NestedDocsPageTreePluginCollectionCustom = {\n badges: NestedDocsPageTreePluginResolvedBadgeConfig\n badgesLinks?: NestedDocsPageTreePluginBadgesLinks\n breadcrumbsFieldSlug: string\n defaultLimit: number\n hideBreadcrumbs: boolean\n homeIndicator: NestedDocsPageTreePluginResolvedHomeIndicatorConfig\n localeBadgeStatus?: PageTreeLocaleBadgeStatus\n localeBadgeVisibility?: PageTreeLocaleBadgeVisibility\n parentFieldSlug: string\n}\n\nexport type PageTreeLiveURL<TRequest = PayloadRequest> = (args: {\n collectionSlug: string\n /** Published document read with the current user's access, at depth 0. */\n doc: PageTreeSourceDoc\n locale?: string\n /** Published document's last breadcrumb URL, when available. */\n path?: string\n req: TRequest\n}) => null | Promise<null | string | undefined> | string | undefined\n\nexport type NestedDocsPageTreePluginBadgesLinks<TRequest = PayloadRequest> = {\n /** Which links to offer for a draft with a published version. @default 'both' */\n draftHasPublishedVersion?: 'both' | 'live' | 'preview'\n /** Website base URL, or a server-only callback returning the final live URL. */\n liveURL?: PageTreeLiveURL<TRequest> | string\n /** Show live link and preview eye icons. When false, 'both' keeps an external-link preview action. @default true */\n showIcons?: boolean\n}\n\nexport type PageTreeStatusLinks = {\n previewURL?: string\n publicURL?: string\n}\n\nexport type PageTreeLocaleStatus = {\n locale: string\n status: 'changed' | 'draft' | 'published' | 'unknown'\n visible?: boolean\n}\n\nexport type PageTreeSourceDoc = {\n __pageTreeLocaleStatuses?: PageTreeLocaleStatus[]\n __pageTreeStatusLinks?: PageTreeStatusLinks\n _displayStatus?: null | string\n _status?: null | string\n id?: number | string\n slug?: null | string\n} & Record<string, unknown>\n\nexport const nestedDocsPageTreePluginCustomKey = 'nestedDocsPageTreePlugin'\n\n/**\n * Set on Payload's hook context for every page-tree write that leaves the\n * published site unchanged: sibling reorders, and parent moves staged as\n * drafts. Deploy/revalidate hooks read it to skip rebuilds they do not need.\n *\n * It is deliberately NOT set when `publishOnMove` publishes a move, because\n * that move changed the live URL of the page and its descendants and the site\n * does need rebuilding. That way one guard covers every configuration:\n *\n * ```ts\n * if (req.context?.[pageTreeMoveContextKey]) return\n * ```\n *\n * Note the flag describes the *effect* of the write, not its kind - it is\n * absent on published moves even though those are still page-tree moves. Use\n * `pageTreeWriteContextKey` when you need \"was this a page-tree write at all\".\n */\nexport const pageTreeMoveContextKey = 'pageTreeMove'\n\n/**\n * Internal: set on every page-tree write regardless of whether it published.\n * Diagnostics uses it so that published moves are still traced, which is the\n * case most worth observing. Not part of the public API.\n */\nexport const pageTreeWriteContextKey = 'pageTreeWrite'\n\nexport type PageTreeMoveContext = {\n [pageTreeMoveContextKey]?: boolean\n [pageTreeWriteContextKey]?: boolean\n}\n"],"names":["nestedDocsPageTreePluginBadgeStatuses","nestedDocsPageTreePluginCustomKey","pageTreeMoveContextKey","pageTreeWriteContextKey"],"mappings":"AASA,OAAO,MAAMA,wCAAwC;IAAC;IAAa;IAAW;CAAQ,CAAS;AA0I/F,OAAO,MAAMC,oCAAoC,2BAA0B;AAE3E;;;;;;;;;;;;;;;;CAgBC,GACD,OAAO,MAAMC,yBAAyB,eAAc;AAEpD;;;;CAIC,GACD,OAAO,MAAMC,0BAA0B,gBAAe"}
@@ -22,6 +22,9 @@ export function normalizeNestedDocsPageTreePluginBadgeConfig(value) {
22
22
  }
23
23
  const badgeConfig = value;
24
24
  return {
25
+ ...badgeConfig.locales === true ? {
26
+ locales: true
27
+ } : {},
25
28
  colors: normalizeBadgeMap(badgeConfig.colors),
26
29
  labels: normalizeBadgeMap(badgeConfig.labels)
27
30
  };
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/utilities/badgeConfig.ts"],"sourcesContent":["import type {\n NestedDocsPageTreePluginBadgeConfig,\n NestedDocsPageTreePluginBadgeMap,\n NestedDocsPageTreePluginResolvedBadgeConfig,\n} from '../types.js'\nimport { nestedDocsPageTreePluginBadgeStatuses } from '../types.js'\n\nfunction normalizeBadgeMap(value: unknown): NestedDocsPageTreePluginBadgeMap {\n const normalized: NestedDocsPageTreePluginBadgeMap = {}\n\n if (!value || typeof value !== 'object' || Array.isArray(value)) {\n return normalized\n }\n\n const badgeMap = value as Record<string, unknown>\n\n for (const status of nestedDocsPageTreePluginBadgeStatuses) {\n const statusValue = badgeMap[status]\n\n if (typeof statusValue === 'string' && statusValue.trim().length > 0) {\n normalized[status] = statusValue.trim()\n }\n }\n\n return normalized\n}\n\nexport function normalizeNestedDocsPageTreePluginBadgeConfig(\n value: NestedDocsPageTreePluginBadgeConfig | unknown,\n): NestedDocsPageTreePluginResolvedBadgeConfig {\n if (!value || typeof value !== 'object' || Array.isArray(value)) {\n return {\n colors: {},\n labels: {},\n }\n }\n\n const badgeConfig = value as NestedDocsPageTreePluginBadgeConfig\n\n return {\n colors: normalizeBadgeMap(badgeConfig.colors),\n labels: normalizeBadgeMap(badgeConfig.labels),\n }\n}\n"],"names":["nestedDocsPageTreePluginBadgeStatuses","normalizeBadgeMap","value","normalized","Array","isArray","badgeMap","status","statusValue","trim","length","normalizeNestedDocsPageTreePluginBadgeConfig","colors","labels","badgeConfig"],"mappings":"AAKA,SAASA,qCAAqC,QAAQ,cAAa;AAEnE,SAASC,kBAAkBC,KAAc;IACvC,MAAMC,aAA+C,CAAC;IAEtD,IAAI,CAACD,SAAS,OAAOA,UAAU,YAAYE,MAAMC,OAAO,CAACH,QAAQ;QAC/D,OAAOC;IACT;IAEA,MAAMG,WAAWJ;IAEjB,KAAK,MAAMK,UAAUP,sCAAuC;QAC1D,MAAMQ,cAAcF,QAAQ,CAACC,OAAO;QAEpC,IAAI,OAAOC,gBAAgB,YAAYA,YAAYC,IAAI,GAAGC,MAAM,GAAG,GAAG;YACpEP,UAAU,CAACI,OAAO,GAAGC,YAAYC,IAAI;QACvC;IACF;IAEA,OAAON;AACT;AAEA,OAAO,SAASQ,6CACdT,KAAoD;IAEpD,IAAI,CAACA,SAAS,OAAOA,UAAU,YAAYE,MAAMC,OAAO,CAACH,QAAQ;QAC/D,OAAO;YACLU,QAAQ,CAAC;YACTC,QAAQ,CAAC;QACX;IACF;IAEA,MAAMC,cAAcZ;IAEpB,OAAO;QACLU,QAAQX,kBAAkBa,YAAYF,MAAM;QAC5CC,QAAQZ,kBAAkBa,YAAYD,MAAM;IAC9C;AACF"}
1
+ {"version":3,"sources":["../../src/utilities/badgeConfig.ts"],"sourcesContent":["import type {\n NestedDocsPageTreePluginBadgeConfig,\n NestedDocsPageTreePluginBadgeMap,\n NestedDocsPageTreePluginResolvedBadgeConfig,\n} from '../types.js'\n\nimport { nestedDocsPageTreePluginBadgeStatuses } from '../types.js'\n\nfunction normalizeBadgeMap(value: unknown): NestedDocsPageTreePluginBadgeMap {\n const normalized: NestedDocsPageTreePluginBadgeMap = {}\n\n if (!value || typeof value !== 'object' || Array.isArray(value)) {\n return normalized\n }\n\n const badgeMap = value as Record<string, unknown>\n\n for (const status of nestedDocsPageTreePluginBadgeStatuses) {\n const statusValue = badgeMap[status]\n\n if (typeof statusValue === 'string' && statusValue.trim().length > 0) {\n normalized[status] = statusValue.trim()\n }\n }\n\n return normalized\n}\n\nexport function normalizeNestedDocsPageTreePluginBadgeConfig(\n value: NestedDocsPageTreePluginBadgeConfig | unknown,\n): NestedDocsPageTreePluginResolvedBadgeConfig {\n if (!value || typeof value !== 'object' || Array.isArray(value)) {\n return {\n colors: {},\n labels: {},\n }\n }\n\n const badgeConfig = value as NestedDocsPageTreePluginBadgeConfig\n\n return {\n ...(badgeConfig.locales === true ? { locales: true } : {}),\n colors: normalizeBadgeMap(badgeConfig.colors),\n labels: normalizeBadgeMap(badgeConfig.labels),\n }\n}\n"],"names":["nestedDocsPageTreePluginBadgeStatuses","normalizeBadgeMap","value","normalized","Array","isArray","badgeMap","status","statusValue","trim","length","normalizeNestedDocsPageTreePluginBadgeConfig","colors","labels","badgeConfig","locales"],"mappings":"AAMA,SAASA,qCAAqC,QAAQ,cAAa;AAEnE,SAASC,kBAAkBC,KAAc;IACvC,MAAMC,aAA+C,CAAC;IAEtD,IAAI,CAACD,SAAS,OAAOA,UAAU,YAAYE,MAAMC,OAAO,CAACH,QAAQ;QAC/D,OAAOC;IACT;IAEA,MAAMG,WAAWJ;IAEjB,KAAK,MAAMK,UAAUP,sCAAuC;QAC1D,MAAMQ,cAAcF,QAAQ,CAACC,OAAO;QAEpC,IAAI,OAAOC,gBAAgB,YAAYA,YAAYC,IAAI,GAAGC,MAAM,GAAG,GAAG;YACpEP,UAAU,CAACI,OAAO,GAAGC,YAAYC,IAAI;QACvC;IACF;IAEA,OAAON;AACT;AAEA,OAAO,SAASQ,6CACdT,KAAoD;IAEpD,IAAI,CAACA,SAAS,OAAOA,UAAU,YAAYE,MAAMC,OAAO,CAACH,QAAQ;QAC/D,OAAO;YACLU,QAAQ,CAAC;YACTC,QAAQ,CAAC;QACX;IACF;IAEA,MAAMC,cAAcZ;IAEpB,OAAO;QACL,GAAIY,YAAYC,OAAO,KAAK,OAAO;YAAEA,SAAS;QAAK,IAAI,CAAC,CAAC;QACzDH,QAAQX,kBAAkBa,YAAYF,MAAM;QAC5CC,QAAQZ,kBAAkBa,YAAYD,MAAM;IAC9C;AACF"}
@@ -19,7 +19,7 @@ export type BadgeLinkCollectionConfig<TRequest extends BadgeLinkRequest> = {
19
19
  slug: string;
20
20
  };
21
21
  export declare function resolvePageTreeBadgeLinks<TRequest extends BadgeLinkRequest>(args: {
22
- badgesLinks?: NestedDocsPageTreePluginBadgesLinks;
22
+ badgesLinks?: NestedDocsPageTreePluginBadgesLinks<TRequest>;
23
23
  breadcrumbsFieldSlug: string;
24
24
  collectionConfig: BadgeLinkCollectionConfig<TRequest>;
25
25
  draftDoc: PageTreeSourceDoc;
@@ -28,9 +28,19 @@ export async function resolvePageTreeBadgeLinks(args) {
28
28
  }
29
29
  if ((status === 'published' || status === 'changed' && mode !== 'preview') && badgesLinks.liveURL && publishedDoc?._status === 'published') {
30
30
  const breadcrumbs = publishedDoc[breadcrumbsFieldSlug];
31
- const path = Array.isArray(breadcrumbs) ? breadcrumbs.at(-1)?.url : undefined;
32
- if (typeof path === 'string' && path.trim()) {
33
- await resolve('publicURL', ()=>new URL(path.trim(), badgesLinks.liveURL).href);
31
+ const breadcrumbURL = Array.isArray(breadcrumbs) ? breadcrumbs.at(-1)?.url : undefined;
32
+ const path = typeof breadcrumbURL === 'string' ? breadcrumbURL.trim() || undefined : undefined;
33
+ const liveURL = badgesLinks.liveURL;
34
+ if (typeof liveURL === 'function') {
35
+ await resolve('publicURL', ()=>liveURL({
36
+ collectionSlug: collectionConfig.slug,
37
+ doc: publishedDoc,
38
+ locale: req.locale ?? undefined,
39
+ path,
40
+ req
41
+ }));
42
+ } else if (path) {
43
+ await resolve('publicURL', ()=>new URL(path, liveURL).href);
34
44
  }
35
45
  }
36
46
  if ((status === 'draft' || status === 'changed' && mode !== 'live') && collectionConfig.admin.preview) {
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/utilities/badgeLinks.ts"],"sourcesContent":["import type {\n NestedDocsPageTreePluginBadgesLinks,\n PageTreeSourceDoc,\n PageTreeStatusLinks,\n} from '../types.js'\n\nimport { getPageTreeDisplayStatus } from './status.js'\n\nexport type BadgeLinkRequest = {\n locale?: null | string\n payload: {\n logger: {\n error(value: unknown): unknown\n }\n }\n url?: string\n}\n\nexport type BadgeLinkCollectionConfig<TRequest extends BadgeLinkRequest> = {\n admin: {\n preview?: (\n doc: Record<string, unknown>,\n options: { locale: string; req: TRequest; token: null | string },\n ) => null | Promise<null | string> | string\n }\n slug: string\n}\n\nexport async function resolvePageTreeBadgeLinks<TRequest extends BadgeLinkRequest>(args: {\n badgesLinks?: NestedDocsPageTreePluginBadgesLinks\n breadcrumbsFieldSlug: string\n collectionConfig: BadgeLinkCollectionConfig<TRequest>\n draftDoc: PageTreeSourceDoc\n publishedDoc?: PageTreeSourceDoc\n req: TRequest\n token: null | string\n}): Promise<PageTreeStatusLinks> {\n const {\n badgesLinks,\n breadcrumbsFieldSlug,\n collectionConfig,\n draftDoc,\n publishedDoc,\n req,\n token,\n } = args\n if (!badgesLinks) {\n return {}\n }\n const mode = badgesLinks.draftHasPublishedVersion ?? 'both'\n const status = getPageTreeDisplayStatus(draftDoc)\n const links: PageTreeStatusLinks = {}\n\n async function resolve(kind: keyof PageTreeStatusLinks, generate: () => unknown) {\n try {\n const value = await generate()\n if (typeof value !== 'string' || !value.trim()) {\n return\n }\n const url = new URL(value.trim(), req.url)\n if (url.protocol === 'http:' || url.protocol === 'https:') {\n links[kind] = url.href\n }\n } catch {\n req.payload.logger.error({\n collection: collectionConfig.slug,\n destination: kind,\n docID: draftDoc.id,\n msg: 'Could not resolve page tree badge URL',\n })\n }\n }\n\n if (\n (status === 'published' || (status === 'changed' && mode !== 'preview')) &&\n badgesLinks.liveURL &&\n publishedDoc?._status === 'published'\n ) {\n const breadcrumbs = publishedDoc[breadcrumbsFieldSlug]\n const path: unknown = Array.isArray(breadcrumbs) ? breadcrumbs.at(-1)?.url : undefined\n if (typeof path === 'string' && path.trim()) {\n await resolve('publicURL', () => new URL(path.trim(), badgesLinks.liveURL).href)\n }\n }\n if (\n (status === 'draft' || (status === 'changed' && mode !== 'live')) &&\n collectionConfig.admin.preview\n ) {\n const preview = collectionConfig.admin.preview\n await resolve('previewURL', () =>\n preview(draftDoc, {\n locale: req.locale!,\n req,\n token,\n }),\n )\n }\n return links\n}\n"],"names":["getPageTreeDisplayStatus","resolvePageTreeBadgeLinks","args","badgesLinks","breadcrumbsFieldSlug","collectionConfig","draftDoc","publishedDoc","req","token","mode","draftHasPublishedVersion","status","links","resolve","kind","generate","value","trim","url","URL","protocol","href","payload","logger","error","collection","slug","destination","docID","id","msg","liveURL","_status","breadcrumbs","path","Array","isArray","at","undefined","admin","preview","locale"],"mappings":"AAMA,SAASA,wBAAwB,QAAQ,cAAa;AAsBtD,OAAO,eAAeC,0BAA6DC,IAQlF;IACC,MAAM,EACJC,WAAW,EACXC,oBAAoB,EACpBC,gBAAgB,EAChBC,QAAQ,EACRC,YAAY,EACZC,GAAG,EACHC,KAAK,EACN,GAAGP;IACJ,IAAI,CAACC,aAAa;QAChB,OAAO,CAAC;IACV;IACA,MAAMO,OAAOP,YAAYQ,wBAAwB,IAAI;IACrD,MAAMC,SAASZ,yBAAyBM;IACxC,MAAMO,QAA6B,CAAC;IAEpC,eAAeC,QAAQC,IAA+B,EAAEC,QAAuB;QAC7E,IAAI;YACF,MAAMC,QAAQ,MAAMD;YACpB,IAAI,OAAOC,UAAU,YAAY,CAACA,MAAMC,IAAI,IAAI;gBAC9C;YACF;YACA,MAAMC,MAAM,IAAIC,IAAIH,MAAMC,IAAI,IAAIV,IAAIW,GAAG;YACzC,IAAIA,IAAIE,QAAQ,KAAK,WAAWF,IAAIE,QAAQ,KAAK,UAAU;gBACzDR,KAAK,CAACE,KAAK,GAAGI,IAAIG,IAAI;YACxB;QACF,EAAE,OAAM;YACNd,IAAIe,OAAO,CAACC,MAAM,CAACC,KAAK,CAAC;gBACvBC,YAAYrB,iBAAiBsB,IAAI;gBACjCC,aAAab;gBACbc,OAAOvB,SAASwB,EAAE;gBAClBC,KAAK;YACP;QACF;IACF;IAEA,IACE,AAACnB,CAAAA,WAAW,eAAgBA,WAAW,aAAaF,SAAS,SAAS,KACtEP,YAAY6B,OAAO,IACnBzB,cAAc0B,YAAY,aAC1B;QACA,MAAMC,cAAc3B,YAAY,CAACH,qBAAqB;QACtD,MAAM+B,OAAgBC,MAAMC,OAAO,CAACH,eAAeA,YAAYI,EAAE,CAAC,CAAC,IAAInB,MAAMoB;QAC7E,IAAI,OAAOJ,SAAS,YAAYA,KAAKjB,IAAI,IAAI;YAC3C,MAAMJ,QAAQ,aAAa,IAAM,IAAIM,IAAIe,KAAKjB,IAAI,IAAIf,YAAY6B,OAAO,EAAEV,IAAI;QACjF;IACF;IACA,IACE,AAACV,CAAAA,WAAW,WAAYA,WAAW,aAAaF,SAAS,MAAM,KAC/DL,iBAAiBmC,KAAK,CAACC,OAAO,EAC9B;QACA,MAAMA,UAAUpC,iBAAiBmC,KAAK,CAACC,OAAO;QAC9C,MAAM3B,QAAQ,cAAc,IAC1B2B,QAAQnC,UAAU;gBAChBoC,QAAQlC,IAAIkC,MAAM;gBAClBlC;gBACAC;YACF;IAEJ;IACA,OAAOI;AACT"}
1
+ {"version":3,"sources":["../../src/utilities/badgeLinks.ts"],"sourcesContent":["import type {\n NestedDocsPageTreePluginBadgesLinks,\n PageTreeSourceDoc,\n PageTreeStatusLinks,\n} from '../types.js'\n\nimport { getPageTreeDisplayStatus } from './status.js'\n\nexport type BadgeLinkRequest = {\n locale?: null | string\n payload: {\n logger: {\n error(value: unknown): unknown\n }\n }\n url?: string\n}\n\nexport type BadgeLinkCollectionConfig<TRequest extends BadgeLinkRequest> = {\n admin: {\n preview?: (\n doc: Record<string, unknown>,\n options: { locale: string; req: TRequest; token: null | string },\n ) => null | Promise<null | string> | string\n }\n slug: string\n}\n\nexport async function resolvePageTreeBadgeLinks<TRequest extends BadgeLinkRequest>(args: {\n badgesLinks?: NestedDocsPageTreePluginBadgesLinks<TRequest>\n breadcrumbsFieldSlug: string\n collectionConfig: BadgeLinkCollectionConfig<TRequest>\n draftDoc: PageTreeSourceDoc\n publishedDoc?: PageTreeSourceDoc\n req: TRequest\n token: null | string\n}): Promise<PageTreeStatusLinks> {\n const {\n badgesLinks,\n breadcrumbsFieldSlug,\n collectionConfig,\n draftDoc,\n publishedDoc,\n req,\n token,\n } = args\n if (!badgesLinks) {\n return {}\n }\n const mode = badgesLinks.draftHasPublishedVersion ?? 'both'\n const status = getPageTreeDisplayStatus(draftDoc)\n const links: PageTreeStatusLinks = {}\n\n async function resolve(kind: keyof PageTreeStatusLinks, generate: () => unknown) {\n try {\n const value = await generate()\n if (typeof value !== 'string' || !value.trim()) {\n return\n }\n const url = new URL(value.trim(), req.url)\n if (url.protocol === 'http:' || url.protocol === 'https:') {\n links[kind] = url.href\n }\n } catch {\n req.payload.logger.error({\n collection: collectionConfig.slug,\n destination: kind,\n docID: draftDoc.id,\n msg: 'Could not resolve page tree badge URL',\n })\n }\n }\n\n if (\n (status === 'published' || (status === 'changed' && mode !== 'preview')) &&\n badgesLinks.liveURL &&\n publishedDoc?._status === 'published'\n ) {\n const breadcrumbs = publishedDoc[breadcrumbsFieldSlug]\n const breadcrumbURL: unknown = Array.isArray(breadcrumbs) ? breadcrumbs.at(-1)?.url : undefined\n const path = typeof breadcrumbURL === 'string' ? breadcrumbURL.trim() || undefined : undefined\n const liveURL = badgesLinks.liveURL\n if (typeof liveURL === 'function') {\n await resolve('publicURL', () =>\n liveURL({\n collectionSlug: collectionConfig.slug,\n doc: publishedDoc,\n locale: req.locale ?? undefined,\n path,\n req,\n }),\n )\n } else if (path) {\n await resolve('publicURL', () => new URL(path, liveURL).href)\n }\n }\n if (\n (status === 'draft' || (status === 'changed' && mode !== 'live')) &&\n collectionConfig.admin.preview\n ) {\n const preview = collectionConfig.admin.preview\n await resolve('previewURL', () =>\n preview(draftDoc, {\n locale: req.locale!,\n req,\n token,\n }),\n )\n }\n return links\n}\n"],"names":["getPageTreeDisplayStatus","resolvePageTreeBadgeLinks","args","badgesLinks","breadcrumbsFieldSlug","collectionConfig","draftDoc","publishedDoc","req","token","mode","draftHasPublishedVersion","status","links","resolve","kind","generate","value","trim","url","URL","protocol","href","payload","logger","error","collection","slug","destination","docID","id","msg","liveURL","_status","breadcrumbs","breadcrumbURL","Array","isArray","at","undefined","path","collectionSlug","doc","locale","admin","preview"],"mappings":"AAMA,SAASA,wBAAwB,QAAQ,cAAa;AAsBtD,OAAO,eAAeC,0BAA6DC,IAQlF;IACC,MAAM,EACJC,WAAW,EACXC,oBAAoB,EACpBC,gBAAgB,EAChBC,QAAQ,EACRC,YAAY,EACZC,GAAG,EACHC,KAAK,EACN,GAAGP;IACJ,IAAI,CAACC,aAAa;QAChB,OAAO,CAAC;IACV;IACA,MAAMO,OAAOP,YAAYQ,wBAAwB,IAAI;IACrD,MAAMC,SAASZ,yBAAyBM;IACxC,MAAMO,QAA6B,CAAC;IAEpC,eAAeC,QAAQC,IAA+B,EAAEC,QAAuB;QAC7E,IAAI;YACF,MAAMC,QAAQ,MAAMD;YACpB,IAAI,OAAOC,UAAU,YAAY,CAACA,MAAMC,IAAI,IAAI;gBAC9C;YACF;YACA,MAAMC,MAAM,IAAIC,IAAIH,MAAMC,IAAI,IAAIV,IAAIW,GAAG;YACzC,IAAIA,IAAIE,QAAQ,KAAK,WAAWF,IAAIE,QAAQ,KAAK,UAAU;gBACzDR,KAAK,CAACE,KAAK,GAAGI,IAAIG,IAAI;YACxB;QACF,EAAE,OAAM;YACNd,IAAIe,OAAO,CAACC,MAAM,CAACC,KAAK,CAAC;gBACvBC,YAAYrB,iBAAiBsB,IAAI;gBACjCC,aAAab;gBACbc,OAAOvB,SAASwB,EAAE;gBAClBC,KAAK;YACP;QACF;IACF;IAEA,IACE,AAACnB,CAAAA,WAAW,eAAgBA,WAAW,aAAaF,SAAS,SAAS,KACtEP,YAAY6B,OAAO,IACnBzB,cAAc0B,YAAY,aAC1B;QACA,MAAMC,cAAc3B,YAAY,CAACH,qBAAqB;QACtD,MAAM+B,gBAAyBC,MAAMC,OAAO,CAACH,eAAeA,YAAYI,EAAE,CAAC,CAAC,IAAInB,MAAMoB;QACtF,MAAMC,OAAO,OAAOL,kBAAkB,WAAWA,cAAcjB,IAAI,MAAMqB,YAAYA;QACrF,MAAMP,UAAU7B,YAAY6B,OAAO;QACnC,IAAI,OAAOA,YAAY,YAAY;YACjC,MAAMlB,QAAQ,aAAa,IACzBkB,QAAQ;oBACNS,gBAAgBpC,iBAAiBsB,IAAI;oBACrCe,KAAKnC;oBACLoC,QAAQnC,IAAImC,MAAM,IAAIJ;oBACtBC;oBACAhC;gBACF;QAEJ,OAAO,IAAIgC,MAAM;YACf,MAAM1B,QAAQ,aAAa,IAAM,IAAIM,IAAIoB,MAAMR,SAASV,IAAI;QAC9D;IACF;IACA,IACE,AAACV,CAAAA,WAAW,WAAYA,WAAW,aAAaF,SAAS,MAAM,KAC/DL,iBAAiBuC,KAAK,CAACC,OAAO,EAC9B;QACA,MAAMA,UAAUxC,iBAAiBuC,KAAK,CAACC,OAAO;QAC9C,MAAM/B,QAAQ,cAAc,IAC1B+B,QAAQvC,UAAU;gBAChBqC,QAAQnC,IAAImC,MAAM;gBAClBnC;gBACAC;YACF;IAEJ;IACA,OAAOI;AACT"}
@@ -0,0 +1,11 @@
1
+ import type { CollectionSlug, Payload, PayloadRequest } from 'payload';
2
+ import type { PageTreeLocaleBadgeStatus, PageTreeLocaleBadgeVisibility, PageTreeSourceDoc } from '../types.js';
3
+ export declare function withPageTreeLocaleStatuses({ collectionSlug, docs, localeBadgeStatus, localeBadgeVisibility, locales, payload, req, }: {
4
+ collectionSlug: CollectionSlug;
5
+ docs: PageTreeSourceDoc[];
6
+ localeBadgeStatus?: PageTreeLocaleBadgeStatus;
7
+ localeBadgeVisibility?: PageTreeLocaleBadgeVisibility;
8
+ locales: string[];
9
+ payload: Payload;
10
+ req: PayloadRequest;
11
+ }): Promise<PageTreeSourceDoc[]>;
@@ -0,0 +1,83 @@
1
+ import { getPageTreeDisplayStatus } from './status.js';
2
+ function readLocaleStatus(value, locale) {
3
+ if (!value || typeof value !== 'object' || Array.isArray(value)) {
4
+ return undefined;
5
+ }
6
+ const status = value[locale];
7
+ return typeof status === 'string' ? status : undefined;
8
+ }
9
+ export async function withPageTreeLocaleStatuses({ collectionSlug, docs, localeBadgeStatus, localeBadgeVisibility, locales, payload, req }) {
10
+ const ids = docs.map(({ id })=>id).filter((id)=>typeof id === 'number' || typeof id === 'string');
11
+ if (!ids.length || !locales.length) {
12
+ return docs;
13
+ }
14
+ const [draftResult, currentResult] = await Promise.all([
15
+ true,
16
+ false
17
+ ].map((draft)=>payload.find({
18
+ collection: collectionSlug,
19
+ depth: 0,
20
+ draft,
21
+ fallbackLocale: false,
22
+ locale: 'all',
23
+ overrideAccess: false,
24
+ pagination: false,
25
+ // Payload mutates the request locale for Local API calls.
26
+ req: {
27
+ ...req,
28
+ query: {
29
+ ...req.query
30
+ }
31
+ },
32
+ // Only opt-in callbacks need document content. Keep the two batched queries.
33
+ select: localeBadgeStatus || draft && localeBadgeVisibility ? undefined : {
34
+ id: true,
35
+ _status: true
36
+ },
37
+ where: {
38
+ id: {
39
+ in: ids
40
+ }
41
+ }
42
+ })));
43
+ const draftByID = new Map(draftResult.docs.map((doc)=>[
44
+ String(doc.id),
45
+ doc
46
+ ]));
47
+ const currentByID = new Map(currentResult.docs.map((doc)=>[
48
+ String(doc.id),
49
+ doc
50
+ ]));
51
+ return docs.map((doc)=>({
52
+ ...doc,
53
+ __pageTreeLocaleStatuses: locales.map((locale)=>{
54
+ const draftDoc = draftByID.get(String(doc.id));
55
+ const draft = readLocaleStatus(draftDoc?._status, locale);
56
+ const publishedDoc = currentByID.get(String(doc.id));
57
+ const current = readLocaleStatus(publishedDoc?._status, locale);
58
+ const status = getPageTreeDisplayStatus({
59
+ _displayStatus: draft === 'draft' && current === 'published' ? 'changed' : undefined,
60
+ _status: draft
61
+ });
62
+ return {
63
+ locale,
64
+ ...localeBadgeVisibility ? {
65
+ visible: Boolean(draftDoc && localeBadgeVisibility({
66
+ doc: draftDoc,
67
+ locale,
68
+ req
69
+ }))
70
+ } : {},
71
+ status: localeBadgeStatus && draftDoc ? localeBadgeStatus({
72
+ doc: draftDoc,
73
+ locale,
74
+ publishedDoc,
75
+ req,
76
+ status
77
+ }) : status
78
+ };
79
+ })
80
+ }));
81
+ }
82
+
83
+ //# sourceMappingURL=localeStatus.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/utilities/localeStatus.ts"],"sourcesContent":["import type { CollectionSlug, Payload, PayloadRequest } from 'payload'\n\nimport type {\n PageTreeLocaleBadgeStatus,\n PageTreeLocaleBadgeVisibility,\n PageTreeSourceDoc,\n} from '../types.js'\n\nimport { getPageTreeDisplayStatus } from './status.js'\n\nfunction readLocaleStatus(value: unknown, locale: string): string | undefined {\n if (!value || typeof value !== 'object' || Array.isArray(value)) {\n return undefined\n }\n const status = (value as Record<string, unknown>)[locale]\n return typeof status === 'string' ? status : undefined\n}\n\nexport async function withPageTreeLocaleStatuses({\n collectionSlug,\n docs,\n localeBadgeStatus,\n localeBadgeVisibility,\n locales,\n payload,\n req,\n}: {\n collectionSlug: CollectionSlug\n docs: PageTreeSourceDoc[]\n localeBadgeStatus?: PageTreeLocaleBadgeStatus\n localeBadgeVisibility?: PageTreeLocaleBadgeVisibility\n locales: string[]\n payload: Payload\n req: PayloadRequest\n}): Promise<PageTreeSourceDoc[]> {\n const ids = docs\n .map(({ id }) => id)\n .filter((id): id is number | string => typeof id === 'number' || typeof id === 'string')\n\n if (!ids.length || !locales.length) {\n return docs\n }\n\n const [draftResult, currentResult] = await Promise.all(\n [true, false].map((draft) =>\n payload.find({\n collection: collectionSlug,\n depth: 0,\n draft,\n fallbackLocale: false,\n locale: 'all',\n overrideAccess: false,\n pagination: false,\n // Payload mutates the request locale for Local API calls.\n req: { ...req, query: { ...req.query } },\n // Only opt-in callbacks need document content. Keep the two batched queries.\n select:\n localeBadgeStatus || (draft && localeBadgeVisibility)\n ? undefined\n : { id: true, _status: true },\n where: { id: { in: ids } },\n }),\n ),\n )\n const draftByID = new Map(draftResult.docs.map((doc) => [String(doc.id), doc]))\n const currentByID = new Map(currentResult.docs.map((doc) => [String(doc.id), doc]))\n\n return docs.map((doc) => ({\n ...doc,\n __pageTreeLocaleStatuses: locales.map((locale) => {\n const draftDoc = draftByID.get(String(doc.id))\n const draft = readLocaleStatus(draftDoc?._status, locale)\n const publishedDoc = currentByID.get(String(doc.id))\n const current = readLocaleStatus(publishedDoc?._status, locale)\n const status = getPageTreeDisplayStatus({\n _displayStatus: draft === 'draft' && current === 'published' ? 'changed' : undefined,\n _status: draft,\n })\n return {\n locale,\n ...(localeBadgeVisibility\n ? { visible: Boolean(draftDoc && localeBadgeVisibility({ doc: draftDoc, locale, req })) }\n : {}),\n status:\n localeBadgeStatus && draftDoc\n ? localeBadgeStatus({ doc: draftDoc, locale, publishedDoc, req, status })\n : status,\n }\n }),\n }))\n}\n"],"names":["getPageTreeDisplayStatus","readLocaleStatus","value","locale","Array","isArray","undefined","status","withPageTreeLocaleStatuses","collectionSlug","docs","localeBadgeStatus","localeBadgeVisibility","locales","payload","req","ids","map","id","filter","length","draftResult","currentResult","Promise","all","draft","find","collection","depth","fallbackLocale","overrideAccess","pagination","query","select","_status","where","in","draftByID","Map","doc","String","currentByID","__pageTreeLocaleStatuses","draftDoc","get","publishedDoc","current","_displayStatus","visible","Boolean"],"mappings":"AAQA,SAASA,wBAAwB,QAAQ,cAAa;AAEtD,SAASC,iBAAiBC,KAAc,EAAEC,MAAc;IACtD,IAAI,CAACD,SAAS,OAAOA,UAAU,YAAYE,MAAMC,OAAO,CAACH,QAAQ;QAC/D,OAAOI;IACT;IACA,MAAMC,SAAS,AAACL,KAAiC,CAACC,OAAO;IACzD,OAAO,OAAOI,WAAW,WAAWA,SAASD;AAC/C;AAEA,OAAO,eAAeE,2BAA2B,EAC/CC,cAAc,EACdC,IAAI,EACJC,iBAAiB,EACjBC,qBAAqB,EACrBC,OAAO,EACPC,OAAO,EACPC,GAAG,EASJ;IACC,MAAMC,MAAMN,KACTO,GAAG,CAAC,CAAC,EAAEC,EAAE,EAAE,GAAKA,IAChBC,MAAM,CAAC,CAACD,KAA8B,OAAOA,OAAO,YAAY,OAAOA,OAAO;IAEjF,IAAI,CAACF,IAAII,MAAM,IAAI,CAACP,QAAQO,MAAM,EAAE;QAClC,OAAOV;IACT;IAEA,MAAM,CAACW,aAAaC,cAAc,GAAG,MAAMC,QAAQC,GAAG,CACpD;QAAC;QAAM;KAAM,CAACP,GAAG,CAAC,CAACQ,QACjBX,QAAQY,IAAI,CAAC;YACXC,YAAYlB;YACZmB,OAAO;YACPH;YACAI,gBAAgB;YAChB1B,QAAQ;YACR2B,gBAAgB;YAChBC,YAAY;YACZ,0DAA0D;YAC1DhB,KAAK;gBAAE,GAAGA,GAAG;gBAAEiB,OAAO;oBAAE,GAAGjB,IAAIiB,KAAK;gBAAC;YAAE;YACvC,6EAA6E;YAC7EC,QACEtB,qBAAsBc,SAASb,wBAC3BN,YACA;gBAAEY,IAAI;gBAAMgB,SAAS;YAAK;YAChCC,OAAO;gBAAEjB,IAAI;oBAAEkB,IAAIpB;gBAAI;YAAE;QAC3B;IAGJ,MAAMqB,YAAY,IAAIC,IAAIjB,YAAYX,IAAI,CAACO,GAAG,CAAC,CAACsB,MAAQ;YAACC,OAAOD,IAAIrB,EAAE;YAAGqB;SAAI;IAC7E,MAAME,cAAc,IAAIH,IAAIhB,cAAcZ,IAAI,CAACO,GAAG,CAAC,CAACsB,MAAQ;YAACC,OAAOD,IAAIrB,EAAE;YAAGqB;SAAI;IAEjF,OAAO7B,KAAKO,GAAG,CAAC,CAACsB,MAAS,CAAA;YACxB,GAAGA,GAAG;YACNG,0BAA0B7B,QAAQI,GAAG,CAAC,CAACd;gBACrC,MAAMwC,WAAWN,UAAUO,GAAG,CAACJ,OAAOD,IAAIrB,EAAE;gBAC5C,MAAMO,QAAQxB,iBAAiB0C,UAAUT,SAAS/B;gBAClD,MAAM0C,eAAeJ,YAAYG,GAAG,CAACJ,OAAOD,IAAIrB,EAAE;gBAClD,MAAM4B,UAAU7C,iBAAiB4C,cAAcX,SAAS/B;gBACxD,MAAMI,SAASP,yBAAyB;oBACtC+C,gBAAgBtB,UAAU,WAAWqB,YAAY,cAAc,YAAYxC;oBAC3E4B,SAAST;gBACX;gBACA,OAAO;oBACLtB;oBACA,GAAIS,wBACA;wBAAEoC,SAASC,QAAQN,YAAY/B,sBAAsB;4BAAE2B,KAAKI;4BAAUxC;4BAAQY;wBAAI;oBAAI,IACtF,CAAC,CAAC;oBACNR,QACEI,qBAAqBgC,WACjBhC,kBAAkB;wBAAE4B,KAAKI;wBAAUxC;wBAAQ0C;wBAAc9B;wBAAKR;oBAAO,KACrEA;gBACR;YACF;QACF,CAAA;AACF"}
@@ -209,8 +209,8 @@ function createTreeNodeComparator(sort) {
209
209
  export function buildPageTreeDocs(docs, options = {}) {
210
210
  const parentFieldSlug = options.parentFieldSlug ?? 'parent';
211
211
  const nodes = docs.map((doc, index)=>({
212
- doc,
213
212
  id: stringifyDocID(doc.id),
213
+ doc,
214
214
  originalIndex: index,
215
215
  parentID: getDocParentID(doc, parentFieldSlug)
216
216
  }));
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/utilities/pageTree.ts"],"sourcesContent":["import type { PageTreeSourceDoc } from '../types.js'\nexport type { PageTreeSourceDoc } from '../types.js'\n\nexport type PageTreeMeta = {\n __pageTreeAncestorIDs: string[]\n __pageTreeDepth: number\n __pageTreeHasChildren: boolean\n __pageTreeID: string\n __pageTreeOrderIndex: number\n __pageTreeParentID: null | string\n __pageTreeShadeLevel: number\n}\n\nexport type PageTreeDoc = PageTreeMeta & PageTreeSourceDoc\n\ntype SortToken = {\n descending: boolean\n path: string[]\n}\n\ntype SortValue = null | number | string\n\ntype TreeNode = {\n doc: PageTreeSourceDoc\n id: string\n originalIndex: number\n parentID: null | string\n}\n\nconst dateLikePattern = /^\\d{4}-\\d{2}-\\d{2}(?:[T\\s].*)?$/\n\nexport type BuildPageTreeDocsOptions = {\n parentFieldSlug?: string\n sort?: string\n}\n\nexport function stringifyDocID(id: number | string | undefined): string {\n return String(id ?? '')\n}\n\nexport function getRelationshipID(value: unknown): null | string {\n if (typeof value === 'number' || typeof value === 'string') {\n return stringifyDocID(value)\n }\n\n if (value && typeof value === 'object' && 'id' in value) {\n const relationshipID = (value as { id?: number | string }).id\n\n if (typeof relationshipID === 'number' || typeof relationshipID === 'string') {\n return stringifyDocID(relationshipID)\n }\n }\n\n return null\n}\n\nexport function getDocParentID(\n doc: PageTreeSourceDoc,\n parentFieldSlug = 'parent',\n): null | string {\n return getRelationshipID(doc[parentFieldSlug])\n}\n\nexport function getDocDisplayLabel(doc: PageTreeDoc): string {\n const title = doc.title\n\n if (typeof title === 'string' && title.trim().length > 0) {\n return title\n }\n\n if (typeof doc.slug === 'string' && doc.slug.trim().length > 0) {\n return doc.slug\n }\n\n return doc.__pageTreeID\n}\n\nexport function getDocSlugSegment(doc: PageTreeDoc): string {\n if (typeof doc.slug === 'string' && doc.slug.trim().length > 0) {\n return doc.slug.trim().replace(/^\\/+|\\/+$/g, '')\n }\n\n return doc.__pageTreeID\n}\n\nexport function buildDocSlugPath(args: {\n doc: PageTreeDoc\n docsByID: Map<string, PageTreeDoc>\n}): string {\n const { doc, docsByID } = args\n const segments = doc.__pageTreeAncestorIDs\n .map((ancestorID) => docsByID.get(ancestorID))\n .filter((ancestorDoc): ancestorDoc is PageTreeDoc => Boolean(ancestorDoc))\n .map(getDocSlugSegment)\n\n segments.push(getDocSlugSegment(doc))\n\n return `/${segments.filter(Boolean).join('/')}`\n}\n\nexport function buildProspectiveDocSlugPath(args: {\n activeDoc: PageTreeDoc\n docsByID: Map<string, PageTreeDoc>\n targetDoc?: PageTreeDoc\n}): string {\n const { activeDoc, docsByID, targetDoc } = args\n\n if (!targetDoc) {\n return `/${getDocSlugSegment(activeDoc)}`\n }\n\n const segments = targetDoc.__pageTreeAncestorIDs\n .map((ancestorID) => docsByID.get(ancestorID))\n .filter((ancestorDoc): ancestorDoc is PageTreeDoc => Boolean(ancestorDoc))\n .map(getDocSlugSegment)\n\n segments.push(getDocSlugSegment(targetDoc), getDocSlugSegment(activeDoc))\n\n return `/${segments.filter(Boolean).join('/')}`\n}\n\nexport function buildChildrenByParentID(args: {\n docs: PageTreeSourceDoc[]\n parentFieldSlug?: string\n}): Map<null | string, string[]> {\n const { docs, parentFieldSlug = 'parent' } = args\n const childrenByParentID = new Map<null | string, string[]>()\n\n for (const doc of docs) {\n const docID = stringifyDocID(doc.id)\n const parentID = getDocParentID(doc, parentFieldSlug)\n const existingChildren = childrenByParentID.get(parentID) ?? []\n\n existingChildren.push(docID)\n childrenByParentID.set(parentID, existingChildren)\n }\n\n return childrenByParentID\n}\n\nexport function collectDescendantIDs(\n rootID: string,\n childrenByParentID: Map<null | string, string[]>,\n): string[] {\n const descendantIDs: string[] = []\n const stack = [...(childrenByParentID.get(rootID) ?? [])]\n\n while (stack.length > 0) {\n const currentID = stack.pop()\n\n if (!currentID) {\n continue\n }\n\n descendantIDs.push(currentID)\n stack.push(...(childrenByParentID.get(currentID) ?? []))\n }\n\n return descendantIDs\n}\n\nfunction getCycleNodeIDs(nodes: TreeNode[], nodesByID: Map<string, TreeNode>): Set<string> {\n const cycleNodeIDs = new Set<string>()\n const pathStack: string[] = []\n const visitState = new Map<string, 'done' | 'visiting'>()\n\n const walk = (node: TreeNode) => {\n const currentState = visitState.get(node.id)\n\n if (currentState === 'done') {\n return\n }\n\n if (currentState === 'visiting') {\n const cycleStartIndex = pathStack.lastIndexOf(node.id)\n const cycleIDs = cycleStartIndex >= 0 ? pathStack.slice(cycleStartIndex) : [node.id]\n\n for (const cycleID of cycleIDs) {\n cycleNodeIDs.add(cycleID)\n }\n\n return\n }\n\n visitState.set(node.id, 'visiting')\n pathStack.push(node.id)\n\n if (node.parentID !== null) {\n const parentNode = nodesByID.get(node.parentID)\n\n if (parentNode) {\n walk(parentNode)\n }\n }\n\n pathStack.pop()\n visitState.set(node.id, 'done')\n }\n\n for (const node of nodes) {\n walk(node)\n }\n\n return cycleNodeIDs\n}\n\nfunction parseSortTokens(sort?: string): SortToken[] {\n if (typeof sort !== 'string' || sort.trim().length === 0) {\n return []\n }\n\n return sort\n .split(',')\n .map((token) => token.trim())\n .filter((token) => token.length > 0)\n .map((token) => {\n const descending = token.startsWith('-')\n const normalizedToken = descending ? token.slice(1) : token\n\n return {\n descending,\n path: normalizedToken.split('.').filter(Boolean),\n }\n })\n .filter((token) => token.path.length > 0)\n}\n\nfunction resolveSortValue(source: unknown, path: string[]): SortValue | undefined {\n let currentValue = source\n\n for (const segment of path) {\n if (!currentValue || typeof currentValue !== 'object' || Array.isArray(currentValue)) {\n return undefined\n }\n\n if (!(segment in currentValue)) {\n return undefined\n }\n\n currentValue = (currentValue as Record<string, unknown>)[segment]\n }\n\n if (currentValue === null || currentValue === undefined) {\n return null\n }\n\n if (currentValue instanceof Date) {\n const timestamp = currentValue.getTime()\n\n return Number.isNaN(timestamp) ? undefined : timestamp\n }\n\n if (typeof currentValue === 'boolean') {\n return currentValue ? 1 : 0\n }\n\n if (typeof currentValue === 'number') {\n return Number.isFinite(currentValue) ? currentValue : undefined\n }\n\n if (typeof currentValue !== 'string') {\n return undefined\n }\n\n const normalizedValue = currentValue.trim()\n\n if (dateLikePattern.test(normalizedValue)) {\n const timestamp = Date.parse(normalizedValue)\n\n if (!Number.isNaN(timestamp)) {\n return timestamp\n }\n }\n\n return normalizedValue\n}\n\nfunction compareSortValues(leftValue: SortValue, rightValue: SortValue): number {\n if (leftValue === null && rightValue === null) {\n return 0\n }\n\n if (leftValue === null) {\n return -1\n }\n\n if (rightValue === null) {\n return 1\n }\n\n if (typeof leftValue === 'number' && typeof rightValue === 'number') {\n if (leftValue === rightValue) {\n return 0\n }\n\n return leftValue < rightValue ? -1 : 1\n }\n\n // Payload orderable keys use fractional indexing strings (for example `_order`\n // values like `a5`, `a53`, `a5i`). These must sort by raw lexicographic order\n // to match the database; numeric-aware locale comparison places `a53` after\n // `a5i`, which is wrong for these keys.\n const leftString = String(leftValue)\n const rightString = String(rightValue)\n\n if (leftString === rightString) {\n return 0\n }\n\n return leftString < rightString ? -1 : 1\n}\n\nfunction createTreeNodeComparator(sort?: string) {\n const sortTokens = parseSortTokens(sort)\n\n if (sortTokens.length === 0) {\n return null\n }\n\n return (leftNode: TreeNode, rightNode: TreeNode): number => {\n for (const sortToken of sortTokens) {\n const leftValue = resolveSortValue(leftNode.doc, sortToken.path)\n const rightValue = resolveSortValue(rightNode.doc, sortToken.path)\n\n if (leftValue === undefined || rightValue === undefined) {\n continue\n }\n\n const comparison = compareSortValues(leftValue, rightValue)\n\n if (comparison !== 0) {\n return sortToken.descending ? -comparison : comparison\n }\n }\n\n return leftNode.originalIndex - rightNode.originalIndex\n }\n}\n\nexport function buildPageTreeDocs(\n docs: PageTreeSourceDoc[],\n options: BuildPageTreeDocsOptions = {},\n): PageTreeDoc[] {\n const parentFieldSlug = options.parentFieldSlug ?? 'parent'\n const nodes: TreeNode[] = docs.map((doc, index) => ({\n doc,\n id: stringifyDocID(doc.id),\n originalIndex: index,\n parentID: getDocParentID(doc, parentFieldSlug),\n }))\n const nodesByID = new Map(nodes.map((node) => [node.id, node]))\n const cycleNodeIDs = getCycleNodeIDs(nodes, nodesByID)\n const effectiveParentIDByNodeID = new Map<string, null | string>()\n const childrenByParentID = new Map<null | string, TreeNode[]>()\n const compareTreeNodes = createTreeNodeComparator(options.sort)\n\n for (const node of nodes) {\n const parentExists = node.parentID !== null && nodesByID.has(node.parentID)\n const effectiveParentID =\n parentExists && !cycleNodeIDs.has(node.id) ? node.parentID : null\n\n effectiveParentIDByNodeID.set(node.id, effectiveParentID)\n\n const currentChildren = childrenByParentID.get(effectiveParentID) ?? []\n currentChildren.push(node)\n childrenByParentID.set(effectiveParentID, currentChildren)\n }\n\n if (compareTreeNodes) {\n for (const children of childrenByParentID.values()) {\n children.sort(compareTreeNodes)\n }\n }\n\n const orderedDocs: PageTreeDoc[] = []\n const subtreeDepthByID = new Map<string, number>()\n const visitedNodeIDs = new Set<string>()\n\n const getShadeLevel = (rootMaxDepth: number, depth: number): number => {\n if (rootMaxDepth === 0) {\n return 0\n }\n\n return Math.max(rootMaxDepth - depth + 1, 1)\n }\n\n const getSubtreeDepth = (node: TreeNode): number => {\n const cachedDepth = subtreeDepthByID.get(node.id)\n\n if (typeof cachedDepth === 'number') {\n return cachedDepth\n }\n\n const children = childrenByParentID.get(node.id) ?? []\n\n if (children.length === 0) {\n subtreeDepthByID.set(node.id, 0)\n return 0\n }\n\n const depth = Math.max(...children.map((child) => getSubtreeDepth(child) + 1))\n subtreeDepthByID.set(node.id, depth)\n return depth\n }\n\n const visit = (node: TreeNode, ancestorIDs: string[], rootMaxDepth: number) => {\n if (visitedNodeIDs.has(node.id)) {\n return\n }\n\n visitedNodeIDs.add(node.id)\n\n const children = childrenByParentID.get(node.id) ?? []\n const depth = ancestorIDs.length\n const shadeLevel = getShadeLevel(rootMaxDepth, depth)\n\n orderedDocs.push({\n ...(node.doc as PageTreeSourceDoc),\n __pageTreeAncestorIDs: ancestorIDs,\n __pageTreeDepth: depth,\n __pageTreeHasChildren: children.length > 0,\n __pageTreeID: node.id,\n __pageTreeOrderIndex: orderedDocs.length,\n __pageTreeParentID: effectiveParentIDByNodeID.get(node.id) ?? null,\n __pageTreeShadeLevel: shadeLevel,\n })\n\n for (const child of children) {\n visit(child, [...ancestorIDs, node.id], rootMaxDepth)\n }\n }\n\n const roots = [...(childrenByParentID.get(null) ?? [])]\n\n for (const root of roots) {\n visit(root, [], getSubtreeDepth(root))\n }\n\n const fallbackNodes = compareTreeNodes ? [...nodes].sort(compareTreeNodes) : nodes\n\n for (const node of fallbackNodes) {\n if (!visitedNodeIDs.has(node.id)) {\n visit(node, [], getSubtreeDepth(node))\n }\n }\n\n return orderedDocs\n}\n\nexport function getVisibleTreeDocs(\n docs: PageTreeDoc[],\n collapsedIDs: ReadonlySet<string>,\n): PageTreeDoc[] {\n return docs.filter((doc) =>\n doc.__pageTreeAncestorIDs.every((ancestorID) => !collapsedIDs.has(ancestorID)),\n )\n}\n"],"names":["dateLikePattern","stringifyDocID","id","String","getRelationshipID","value","relationshipID","getDocParentID","doc","parentFieldSlug","getDocDisplayLabel","title","trim","length","slug","__pageTreeID","getDocSlugSegment","replace","buildDocSlugPath","args","docsByID","segments","__pageTreeAncestorIDs","map","ancestorID","get","filter","ancestorDoc","Boolean","push","join","buildProspectiveDocSlugPath","activeDoc","targetDoc","buildChildrenByParentID","docs","childrenByParentID","Map","docID","parentID","existingChildren","set","collectDescendantIDs","rootID","descendantIDs","stack","currentID","pop","getCycleNodeIDs","nodes","nodesByID","cycleNodeIDs","Set","pathStack","visitState","walk","node","currentState","cycleStartIndex","lastIndexOf","cycleIDs","slice","cycleID","add","parentNode","parseSortTokens","sort","split","token","descending","startsWith","normalizedToken","path","resolveSortValue","source","currentValue","segment","Array","isArray","undefined","Date","timestamp","getTime","Number","isNaN","isFinite","normalizedValue","test","parse","compareSortValues","leftValue","rightValue","leftString","rightString","createTreeNodeComparator","sortTokens","leftNode","rightNode","sortToken","comparison","originalIndex","buildPageTreeDocs","options","index","effectiveParentIDByNodeID","compareTreeNodes","parentExists","has","effectiveParentID","currentChildren","children","values","orderedDocs","subtreeDepthByID","visitedNodeIDs","getShadeLevel","rootMaxDepth","depth","Math","max","getSubtreeDepth","cachedDepth","child","visit","ancestorIDs","shadeLevel","__pageTreeDepth","__pageTreeHasChildren","__pageTreeOrderIndex","__pageTreeParentID","__pageTreeShadeLevel","roots","root","fallbackNodes","getVisibleTreeDocs","collapsedIDs","every"],"mappings":"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"}
1
+ {"version":3,"sources":["../../src/utilities/pageTree.ts"],"sourcesContent":["import type { PageTreeSourceDoc } from '../types.js'\nexport type { PageTreeSourceDoc } from '../types.js'\n\nexport type PageTreeMeta = {\n __pageTreeAncestorIDs: string[]\n __pageTreeDepth: number\n __pageTreeHasChildren: boolean\n __pageTreeID: string\n __pageTreeOrderIndex: number\n __pageTreeParentID: null | string\n __pageTreeShadeLevel: number\n}\n\nexport type PageTreeDoc = PageTreeMeta & PageTreeSourceDoc\n\ntype SortToken = {\n descending: boolean\n path: string[]\n}\n\ntype SortValue = null | number | string\n\ntype TreeNode = {\n doc: PageTreeSourceDoc\n id: string\n originalIndex: number\n parentID: null | string\n}\n\nconst dateLikePattern = /^\\d{4}-\\d{2}-\\d{2}(?:[T\\s].*)?$/\n\nexport type BuildPageTreeDocsOptions = {\n parentFieldSlug?: string\n sort?: string\n}\n\nexport function stringifyDocID(id: number | string | undefined): string {\n return String(id ?? '')\n}\n\nexport function getRelationshipID(value: unknown): null | string {\n if (typeof value === 'number' || typeof value === 'string') {\n return stringifyDocID(value)\n }\n\n if (value && typeof value === 'object' && 'id' in value) {\n const relationshipID = (value as { id?: number | string }).id\n\n if (typeof relationshipID === 'number' || typeof relationshipID === 'string') {\n return stringifyDocID(relationshipID)\n }\n }\n\n return null\n}\n\nexport function getDocParentID(\n doc: PageTreeSourceDoc,\n parentFieldSlug = 'parent',\n): null | string {\n return getRelationshipID(doc[parentFieldSlug])\n}\n\nexport function getDocDisplayLabel(doc: PageTreeDoc): string {\n const title = doc.title\n\n if (typeof title === 'string' && title.trim().length > 0) {\n return title\n }\n\n if (typeof doc.slug === 'string' && doc.slug.trim().length > 0) {\n return doc.slug\n }\n\n return doc.__pageTreeID\n}\n\nexport function getDocSlugSegment(doc: PageTreeDoc): string {\n if (typeof doc.slug === 'string' && doc.slug.trim().length > 0) {\n return doc.slug.trim().replace(/^\\/+|\\/+$/g, '')\n }\n\n return doc.__pageTreeID\n}\n\nexport function buildDocSlugPath(args: {\n doc: PageTreeDoc\n docsByID: Map<string, PageTreeDoc>\n}): string {\n const { doc, docsByID } = args\n const segments = doc.__pageTreeAncestorIDs\n .map((ancestorID) => docsByID.get(ancestorID))\n .filter((ancestorDoc): ancestorDoc is PageTreeDoc => Boolean(ancestorDoc))\n .map(getDocSlugSegment)\n\n segments.push(getDocSlugSegment(doc))\n\n return `/${segments.filter(Boolean).join('/')}`\n}\n\nexport function buildProspectiveDocSlugPath(args: {\n activeDoc: PageTreeDoc\n docsByID: Map<string, PageTreeDoc>\n targetDoc?: PageTreeDoc\n}): string {\n const { activeDoc, docsByID, targetDoc } = args\n\n if (!targetDoc) {\n return `/${getDocSlugSegment(activeDoc)}`\n }\n\n const segments = targetDoc.__pageTreeAncestorIDs\n .map((ancestorID) => docsByID.get(ancestorID))\n .filter((ancestorDoc): ancestorDoc is PageTreeDoc => Boolean(ancestorDoc))\n .map(getDocSlugSegment)\n\n segments.push(getDocSlugSegment(targetDoc), getDocSlugSegment(activeDoc))\n\n return `/${segments.filter(Boolean).join('/')}`\n}\n\nexport function buildChildrenByParentID(args: {\n docs: PageTreeSourceDoc[]\n parentFieldSlug?: string\n}): Map<null | string, string[]> {\n const { docs, parentFieldSlug = 'parent' } = args\n const childrenByParentID = new Map<null | string, string[]>()\n\n for (const doc of docs) {\n const docID = stringifyDocID(doc.id)\n const parentID = getDocParentID(doc, parentFieldSlug)\n const existingChildren = childrenByParentID.get(parentID) ?? []\n\n existingChildren.push(docID)\n childrenByParentID.set(parentID, existingChildren)\n }\n\n return childrenByParentID\n}\n\nexport function collectDescendantIDs(\n rootID: string,\n childrenByParentID: Map<null | string, string[]>,\n): string[] {\n const descendantIDs: string[] = []\n const stack = [...(childrenByParentID.get(rootID) ?? [])]\n\n while (stack.length > 0) {\n const currentID = stack.pop()\n\n if (!currentID) {\n continue\n }\n\n descendantIDs.push(currentID)\n stack.push(...(childrenByParentID.get(currentID) ?? []))\n }\n\n return descendantIDs\n}\n\nfunction getCycleNodeIDs(nodes: TreeNode[], nodesByID: Map<string, TreeNode>): Set<string> {\n const cycleNodeIDs = new Set<string>()\n const pathStack: string[] = []\n const visitState = new Map<string, 'done' | 'visiting'>()\n\n const walk = (node: TreeNode) => {\n const currentState = visitState.get(node.id)\n\n if (currentState === 'done') {\n return\n }\n\n if (currentState === 'visiting') {\n const cycleStartIndex = pathStack.lastIndexOf(node.id)\n const cycleIDs = cycleStartIndex >= 0 ? pathStack.slice(cycleStartIndex) : [node.id]\n\n for (const cycleID of cycleIDs) {\n cycleNodeIDs.add(cycleID)\n }\n\n return\n }\n\n visitState.set(node.id, 'visiting')\n pathStack.push(node.id)\n\n if (node.parentID !== null) {\n const parentNode = nodesByID.get(node.parentID)\n\n if (parentNode) {\n walk(parentNode)\n }\n }\n\n pathStack.pop()\n visitState.set(node.id, 'done')\n }\n\n for (const node of nodes) {\n walk(node)\n }\n\n return cycleNodeIDs\n}\n\nfunction parseSortTokens(sort?: string): SortToken[] {\n if (typeof sort !== 'string' || sort.trim().length === 0) {\n return []\n }\n\n return sort\n .split(',')\n .map((token) => token.trim())\n .filter((token) => token.length > 0)\n .map((token) => {\n const descending = token.startsWith('-')\n const normalizedToken = descending ? token.slice(1) : token\n\n return {\n descending,\n path: normalizedToken.split('.').filter(Boolean),\n }\n })\n .filter((token) => token.path.length > 0)\n}\n\nfunction resolveSortValue(source: unknown, path: string[]): SortValue | undefined {\n let currentValue = source\n\n for (const segment of path) {\n if (!currentValue || typeof currentValue !== 'object' || Array.isArray(currentValue)) {\n return undefined\n }\n\n if (!(segment in currentValue)) {\n return undefined\n }\n\n currentValue = (currentValue as Record<string, unknown>)[segment]\n }\n\n if (currentValue === null || currentValue === undefined) {\n return null\n }\n\n if (currentValue instanceof Date) {\n const timestamp = currentValue.getTime()\n\n return Number.isNaN(timestamp) ? undefined : timestamp\n }\n\n if (typeof currentValue === 'boolean') {\n return currentValue ? 1 : 0\n }\n\n if (typeof currentValue === 'number') {\n return Number.isFinite(currentValue) ? currentValue : undefined\n }\n\n if (typeof currentValue !== 'string') {\n return undefined\n }\n\n const normalizedValue = currentValue.trim()\n\n if (dateLikePattern.test(normalizedValue)) {\n const timestamp = Date.parse(normalizedValue)\n\n if (!Number.isNaN(timestamp)) {\n return timestamp\n }\n }\n\n return normalizedValue\n}\n\nfunction compareSortValues(leftValue: SortValue, rightValue: SortValue): number {\n if (leftValue === null && rightValue === null) {\n return 0\n }\n\n if (leftValue === null) {\n return -1\n }\n\n if (rightValue === null) {\n return 1\n }\n\n if (typeof leftValue === 'number' && typeof rightValue === 'number') {\n if (leftValue === rightValue) {\n return 0\n }\n\n return leftValue < rightValue ? -1 : 1\n }\n\n // Payload orderable keys use fractional indexing strings (for example `_order`\n // values like `a5`, `a53`, `a5i`). These must sort by raw lexicographic order\n // to match the database; numeric-aware locale comparison places `a53` after\n // `a5i`, which is wrong for these keys.\n const leftString = String(leftValue)\n const rightString = String(rightValue)\n\n if (leftString === rightString) {\n return 0\n }\n\n return leftString < rightString ? -1 : 1\n}\n\nfunction createTreeNodeComparator(sort?: string) {\n const sortTokens = parseSortTokens(sort)\n\n if (sortTokens.length === 0) {\n return null\n }\n\n return (leftNode: TreeNode, rightNode: TreeNode): number => {\n for (const sortToken of sortTokens) {\n const leftValue = resolveSortValue(leftNode.doc, sortToken.path)\n const rightValue = resolveSortValue(rightNode.doc, sortToken.path)\n\n if (leftValue === undefined || rightValue === undefined) {\n continue\n }\n\n const comparison = compareSortValues(leftValue, rightValue)\n\n if (comparison !== 0) {\n return sortToken.descending ? -comparison : comparison\n }\n }\n\n return leftNode.originalIndex - rightNode.originalIndex\n }\n}\n\nexport function buildPageTreeDocs(\n docs: PageTreeSourceDoc[],\n options: BuildPageTreeDocsOptions = {},\n): PageTreeDoc[] {\n const parentFieldSlug = options.parentFieldSlug ?? 'parent'\n const nodes: TreeNode[] = docs.map((doc, index) => ({\n id: stringifyDocID(doc.id),\n doc,\n originalIndex: index,\n parentID: getDocParentID(doc, parentFieldSlug),\n }))\n const nodesByID = new Map(nodes.map((node) => [node.id, node]))\n const cycleNodeIDs = getCycleNodeIDs(nodes, nodesByID)\n const effectiveParentIDByNodeID = new Map<string, null | string>()\n const childrenByParentID = new Map<null | string, TreeNode[]>()\n const compareTreeNodes = createTreeNodeComparator(options.sort)\n\n for (const node of nodes) {\n const parentExists = node.parentID !== null && nodesByID.has(node.parentID)\n const effectiveParentID =\n parentExists && !cycleNodeIDs.has(node.id) ? node.parentID : null\n\n effectiveParentIDByNodeID.set(node.id, effectiveParentID)\n\n const currentChildren = childrenByParentID.get(effectiveParentID) ?? []\n currentChildren.push(node)\n childrenByParentID.set(effectiveParentID, currentChildren)\n }\n\n if (compareTreeNodes) {\n for (const children of childrenByParentID.values()) {\n children.sort(compareTreeNodes)\n }\n }\n\n const orderedDocs: PageTreeDoc[] = []\n const subtreeDepthByID = new Map<string, number>()\n const visitedNodeIDs = new Set<string>()\n\n const getShadeLevel = (rootMaxDepth: number, depth: number): number => {\n if (rootMaxDepth === 0) {\n return 0\n }\n\n return Math.max(rootMaxDepth - depth + 1, 1)\n }\n\n const getSubtreeDepth = (node: TreeNode): number => {\n const cachedDepth = subtreeDepthByID.get(node.id)\n\n if (typeof cachedDepth === 'number') {\n return cachedDepth\n }\n\n const children = childrenByParentID.get(node.id) ?? []\n\n if (children.length === 0) {\n subtreeDepthByID.set(node.id, 0)\n return 0\n }\n\n const depth = Math.max(...children.map((child) => getSubtreeDepth(child) + 1))\n subtreeDepthByID.set(node.id, depth)\n return depth\n }\n\n const visit = (node: TreeNode, ancestorIDs: string[], rootMaxDepth: number) => {\n if (visitedNodeIDs.has(node.id)) {\n return\n }\n\n visitedNodeIDs.add(node.id)\n\n const children = childrenByParentID.get(node.id) ?? []\n const depth = ancestorIDs.length\n const shadeLevel = getShadeLevel(rootMaxDepth, depth)\n\n orderedDocs.push({\n ...(node.doc),\n __pageTreeAncestorIDs: ancestorIDs,\n __pageTreeDepth: depth,\n __pageTreeHasChildren: children.length > 0,\n __pageTreeID: node.id,\n __pageTreeOrderIndex: orderedDocs.length,\n __pageTreeParentID: effectiveParentIDByNodeID.get(node.id) ?? null,\n __pageTreeShadeLevel: shadeLevel,\n })\n\n for (const child of children) {\n visit(child, [...ancestorIDs, node.id], rootMaxDepth)\n }\n }\n\n const roots = [...(childrenByParentID.get(null) ?? [])]\n\n for (const root of roots) {\n visit(root, [], getSubtreeDepth(root))\n }\n\n const fallbackNodes = compareTreeNodes ? [...nodes].sort(compareTreeNodes) : nodes\n\n for (const node of fallbackNodes) {\n if (!visitedNodeIDs.has(node.id)) {\n visit(node, [], getSubtreeDepth(node))\n }\n }\n\n return orderedDocs\n}\n\nexport function getVisibleTreeDocs(\n docs: PageTreeDoc[],\n collapsedIDs: ReadonlySet<string>,\n): PageTreeDoc[] {\n return docs.filter((doc) =>\n doc.__pageTreeAncestorIDs.every((ancestorID) => !collapsedIDs.has(ancestorID)),\n )\n}\n"],"names":["dateLikePattern","stringifyDocID","id","String","getRelationshipID","value","relationshipID","getDocParentID","doc","parentFieldSlug","getDocDisplayLabel","title","trim","length","slug","__pageTreeID","getDocSlugSegment","replace","buildDocSlugPath","args","docsByID","segments","__pageTreeAncestorIDs","map","ancestorID","get","filter","ancestorDoc","Boolean","push","join","buildProspectiveDocSlugPath","activeDoc","targetDoc","buildChildrenByParentID","docs","childrenByParentID","Map","docID","parentID","existingChildren","set","collectDescendantIDs","rootID","descendantIDs","stack","currentID","pop","getCycleNodeIDs","nodes","nodesByID","cycleNodeIDs","Set","pathStack","visitState","walk","node","currentState","cycleStartIndex","lastIndexOf","cycleIDs","slice","cycleID","add","parentNode","parseSortTokens","sort","split","token","descending","startsWith","normalizedToken","path","resolveSortValue","source","currentValue","segment","Array","isArray","undefined","Date","timestamp","getTime","Number","isNaN","isFinite","normalizedValue","test","parse","compareSortValues","leftValue","rightValue","leftString","rightString","createTreeNodeComparator","sortTokens","leftNode","rightNode","sortToken","comparison","originalIndex","buildPageTreeDocs","options","index","effectiveParentIDByNodeID","compareTreeNodes","parentExists","has","effectiveParentID","currentChildren","children","values","orderedDocs","subtreeDepthByID","visitedNodeIDs","getShadeLevel","rootMaxDepth","depth","Math","max","getSubtreeDepth","cachedDepth","child","visit","ancestorIDs","shadeLevel","__pageTreeDepth","__pageTreeHasChildren","__pageTreeOrderIndex","__pageTreeParentID","__pageTreeShadeLevel","roots","root","fallbackNodes","getVisibleTreeDocs","collapsedIDs","every"],"mappings":"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"}
@@ -1,3 +1,3 @@
1
1
  import type { CollectionConfig } from 'payload';
2
2
  import type { NestedDocsPageTreePluginCollectionCustom } from '../types.js';
3
- export declare function getCollectionPageTreeConfig(collection: Pick<CollectionConfig, 'custom'>): null | NestedDocsPageTreePluginCollectionCustom;
3
+ export declare function getCollectionPageTreeConfig(collection: Pick<CollectionConfig, 'custom'>): NestedDocsPageTreePluginCollectionCustom | null;
@@ -18,6 +18,8 @@ export function getCollectionPageTreeConfig(collection) {
18
18
  homeIndicator: {
19
19
  enabled: config.homeIndicator.enabled
20
20
  },
21
+ localeBadgeStatus: config.localeBadgeStatus,
22
+ localeBadgeVisibility: config.localeBadgeVisibility,
21
23
  parentFieldSlug: config.parentFieldSlug
22
24
  };
23
25
  }