@valkyrianlabs/payload-markdown-docs 0.3.1 → 0.4.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 (98) hide show
  1. package/README.md +76 -176
  2. package/dist/admin/DocsSetManager.js +5 -3
  3. package/dist/admin/DocsSetManager.js.map +1 -1
  4. package/dist/admin/docsSetManagerData.d.ts +6 -5
  5. package/dist/admin/docsSetManagerData.js +60 -33
  6. package/dist/admin/docsSetManagerData.js.map +1 -1
  7. package/dist/admin/docsSetManagerTypes.d.ts +12 -9
  8. package/dist/admin/docsSetManagerTypes.js.map +1 -1
  9. package/dist/cli/commands/manifest.js +1 -2
  10. package/dist/cli/commands/manifest.js.map +1 -1
  11. package/dist/cli/commands/plan.js +1 -2
  12. package/dist/cli/commands/plan.js.map +1 -1
  13. package/dist/cli/commands/push.js +2 -5
  14. package/dist/cli/commands/push.js.map +1 -1
  15. package/dist/cli/commands/validate.js +11 -6
  16. package/dist/cli/commands/validate.js.map +1 -1
  17. package/dist/cli/index.js +5 -14
  18. package/dist/cli/index.js.map +1 -1
  19. package/dist/cli/parseArgs.js +0 -3
  20. package/dist/cli/parseArgs.js.map +1 -1
  21. package/dist/cli/types.d.ts +0 -3
  22. package/dist/cli/types.js.map +1 -1
  23. package/dist/collections/docs.js +0 -24
  24. package/dist/collections/docs.js.map +1 -1
  25. package/dist/collections/docsGroups.js +8 -9
  26. package/dist/collections/docsGroups.js.map +1 -1
  27. package/dist/collections/docsKeys.d.ts +5 -0
  28. package/dist/collections/docsKeys.js +44 -0
  29. package/dist/collections/docsKeys.js.map +1 -0
  30. package/dist/collections/docsSets.js +47 -202
  31. package/dist/collections/docsSets.js.map +1 -1
  32. package/dist/collections/docsTrusted.d.ts +5 -0
  33. package/dist/collections/docsTrusted.js +60 -0
  34. package/dist/collections/docsTrusted.js.map +1 -0
  35. package/dist/collections/index.d.ts +4 -0
  36. package/dist/collections/index.js +2 -0
  37. package/dist/collections/index.js.map +1 -1
  38. package/dist/constants.d.ts +3 -1
  39. package/dist/constants.js +3 -1
  40. package/dist/constants.js.map +1 -1
  41. package/dist/endpoints/sync.d.ts +6 -7
  42. package/dist/endpoints/sync.js +57 -124
  43. package/dist/endpoints/sync.js.map +1 -1
  44. package/dist/index.d.ts +2 -2
  45. package/dist/index.js +1 -1
  46. package/dist/index.js.map +1 -1
  47. package/dist/next/PayloadMarkdownDocsPage.js +2 -6
  48. package/dist/next/PayloadMarkdownDocsPage.js.map +1 -1
  49. package/dist/next/index.d.ts +2 -0
  50. package/dist/next/index.js +1 -0
  51. package/dist/next/index.js.map +1 -1
  52. package/dist/next/links.d.ts +11 -0
  53. package/dist/next/links.js +79 -0
  54. package/dist/next/links.js.map +1 -0
  55. package/dist/next/markdown.js +91 -19
  56. package/dist/next/markdown.js.map +1 -1
  57. package/dist/next/metadata.js +6 -6
  58. package/dist/next/metadata.js.map +1 -1
  59. package/dist/next/records.js +13 -23
  60. package/dist/next/records.js.map +1 -1
  61. package/dist/next/route.js +141 -49
  62. package/dist/next/route.js.map +1 -1
  63. package/dist/next/types.d.ts +0 -14
  64. package/dist/next/types.js.map +1 -1
  65. package/dist/payload/docsKeys.d.ts +20 -0
  66. package/dist/payload/docsKeys.js +29 -0
  67. package/dist/payload/docsKeys.js.map +1 -0
  68. package/dist/payload/docsSets.d.ts +32 -6
  69. package/dist/payload/docsSets.js +146 -83
  70. package/dist/payload/docsSets.js.map +1 -1
  71. package/dist/payload/docsTrusted.d.ts +16 -0
  72. package/dist/payload/docsTrusted.js +49 -0
  73. package/dist/payload/docsTrusted.js.map +1 -0
  74. package/dist/payload/index.d.ts +5 -1
  75. package/dist/payload/index.js +3 -1
  76. package/dist/payload/index.js.map +1 -1
  77. package/dist/plugin.js +36 -9
  78. package/dist/plugin.js.map +1 -1
  79. package/dist/security/githubOidc.d.ts +18 -5
  80. package/dist/security/githubOidc.js +44 -16
  81. package/dist/security/githubOidc.js.map +1 -1
  82. package/dist/security/index.d.ts +1 -1
  83. package/dist/security/index.js.map +1 -1
  84. package/dist/skills/codex/SKILL.md +3 -4
  85. package/dist/skills/codex/examples/github-actions.md +0 -2
  86. package/dist/skills/codex/reference/admin.md +0 -6
  87. package/dist/skills/codex/reference/routing.md +2 -1
  88. package/dist/skills/codex/reference/sync.md +7 -5
  89. package/dist/skills/codex/reference/troubleshooting.md +3 -4
  90. package/dist/skills/codex/reference/workflow.md +0 -1
  91. package/dist/sync/manifest.d.ts +1 -3
  92. package/dist/sync/manifest.js +2 -3
  93. package/dist/sync/manifest.js.map +1 -1
  94. package/dist/sync/validate.js +1 -2
  95. package/dist/sync/validate.js.map +1 -1
  96. package/dist/types.d.ts +7 -50
  97. package/dist/types.js.map +1 -1
  98. package/package.json +4 -4
package/README.md CHANGED
@@ -3,42 +3,24 @@
3
3
  Git-backed Markdown documentation sync for Payload CMS, powered by
4
4
  `@valkyrianlabs/payload-markdown`.
5
5
 
6
- This package has two sides:
6
+ The default workflow is intentionally small:
7
7
 
8
- - The docs repo keeps Markdown files in source control and uses the CLI to
9
- validate, plan, and push them.
10
- - The Payload server installs the plugin, verifies signed or GitHub OIDC
11
- requests, and writes generated docs records into Payload-owned collections.
12
-
13
- The sync endpoint is not the human docs route. If your Payload site is deployed
14
- at `https://docs.valkyrianlabs.com`, the default sync endpoint is:
15
-
16
- ```text
17
- https://docs.valkyrianlabs.com/api/payload-markdown-docs/sync
18
- ```
19
-
20
- The human docs route is whatever docs set route base you configure, for example:
21
-
22
- ```text
23
- https://docs.valkyrianlabs.com/plugins/payload-markdown-docs
24
- ```
8
+ 1. Install the plugin in your Payload app.
9
+ 2. Create a docs set with a title and slug.
10
+ 3. Add a trusted GitHub owner once.
11
+ 4. Push Markdown from GitHub Actions.
12
+ 5. Render generated docs in your Next route.
25
13
 
26
14
  ## Install
27
15
 
28
- Install this package in the Payload app that will receive and render docs:
29
-
30
16
  ```bash
31
17
  pnpm add @valkyrianlabs/payload-markdown-docs @valkyrianlabs/payload-markdown
32
18
  ```
33
19
 
34
- Install the same package in any repo whose CI will run the
20
+ Install the same package in any repository that runs the
35
21
  `payload-markdown-docs` CLI.
36
22
 
37
- ## 1. Configure The Payload Server
38
-
39
- Add the plugin to `payload.config.ts`. Keep source authorization in Payload
40
- Admin docs sets; the plugin config should define the endpoint, collections, and
41
- sync lifecycle behavior.
23
+ ## Configure Payload
42
24
 
43
25
  ```ts
44
26
  import { payloadMarkdownDocs } from '@valkyrianlabs/payload-markdown-docs'
@@ -47,74 +29,49 @@ import { buildConfig } from 'payload'
47
29
  export default buildConfig({
48
30
  plugins: [
49
31
  payloadMarkdownDocs({
50
- enabled: true,
51
-
52
- // Optional default OIDC audience. Repository/workflow/environment
53
- // allowlists belong on the docs set in Payload Admin.
54
32
  auth: {
55
- githubOidc: {
56
- audience: 'payload-markdown-docs',
57
- },
33
+ githubOidc: true,
58
34
  },
59
-
60
35
  target: {
61
- type: 'docsCollection',
62
36
  enableDrafts: true,
63
37
  },
64
-
65
38
  sync: {
66
39
  allowWrites: true,
67
40
  allowPublish: true,
68
- allowHardDelete: false,
69
- defaultPublishMode: 'draft',
70
- deleteBehavior: 'archive',
71
41
  },
72
42
  }),
73
43
  ],
74
44
  })
75
45
  ```
76
46
 
77
- What this does:
47
+ This adds `Docs Globals` admin collections:
78
48
 
79
- - Adds docs groups, docs sets, generated docs, sync run, and nonce collections.
80
- - Registers the default Payload custom endpoint at
81
- `/api/payload-markdown-docs/sync`.
82
- - Accepts Ed25519 signed requests or GitHub OIDC bearer requests on the same
83
- endpoint when the matched docs set has those auth policies.
84
- - Uses docs sets in Payload Admin as the source allow-list. `sources` still
85
- exists as a legacy fallback, but it is not the recommended path.
86
- - Allows sync writes and publish requests, while archiving removed docs instead
87
- of hard-deleting them.
49
+ - `Sets`: docs packages. The set `slug` is the sync source and OIDC audience.
50
+ - `Groups`: optional route nesting. Routes are derived from group slugs.
51
+ - `Keys`: global Ed25519 public keys for local or non-GitHub publishing.
52
+ - `Trusted`: global GitHub owners trusted for OIDC publishing.
88
53
 
89
- If you configure `allowedRefs` on a docs set, remember release workflows run on
90
- tag refs like `refs/tags/v0.1.0-canary.1`. The first pass uses exact string
91
- matches, not glob patterns. For release publishing, constrain by repository and
92
- workflow unless you want to list exact tag refs.
54
+ The sync endpoint is `/api/payload-markdown-docs/sync`.
93
55
 
94
- ## 2. Create The Docs Set
56
+ ## Create Admin Records
95
57
 
96
- In Payload Admin, create a docs set with values that match the CLI and server
97
- config:
58
+ Create a docs set:
98
59
 
99
- - `sourceId`: `payload-markdown-docs`
100
- - `sourceRoot`: `docs`
101
- - `routeBase`: `/plugins/payload-markdown-docs`
102
- - `title`: Payload Markdown Docs
103
- - `auth.githubOidc.enabled`: checked
104
- - `auth.githubOidc.allowedRepositories`: `valkyrianlabs/payload-markdown-docs`
105
- - optionally restrict `auth.githubOidc.allowedWorkflows`,
106
- `auth.githubOidc.allowedEnvironments`, or exact `auth.githubOidc.allowedRefs`
107
- - optionally add `auth.ed25519.keys` with `keyId` and `publicKey` for local
108
- machines or non-GitHub CI
60
+ - title: `Payload Markdown Docs`
61
+ - slug: `payload-markdown-docs`
62
+ - branch: `main`
63
+ - optional group: for example `plugins`, which makes the route
64
+ `/plugins/payload-markdown-docs`
109
65
 
110
- The CLI sends `source.id`. The server uses that id to find the docs set and
111
- decide where generated routes live and which credentials may update it. You can
112
- add a new docs source by creating a new docs set in Payload Admin; you should
113
- not need to redeploy the Payload app just to add another docs package.
66
+ Create a trusted GitHub owner:
114
67
 
115
- ## 3. Render Docs In Next
68
+ - owner: `valkyrianlabs`
69
+ - `limitRepos`: off, unless you want to list specific repositories
116
70
 
117
- The plugin writes docs records. Your Next route renders them.
71
+ When `limitRepos` is off, any repository owned by that GitHub owner can publish
72
+ to a matching docs set from the configured branch.
73
+
74
+ ## Render In Next
118
75
 
119
76
  ```tsx
120
77
  import config from '@payload-config'
@@ -142,141 +99,84 @@ export default async function Page({
142
99
  }
143
100
  ```
144
101
 
145
- In a real app, fall back to your normal Pages lookup instead of calling
146
- `notFound()` immediately.
147
-
148
- ## 4. Add Docs Source Files
149
-
150
- Keep docs in `docs/` and commit the AI Markdown Export manifest next to them.
151
- The manifest controls the generated raw Markdown export; it is not a human docs
152
- page and should not appear in human navigation.
153
-
154
- ```text
155
- docs/
156
- index.md
157
- install.md
158
- usage.md
159
- index.ai.yml
160
- ```
161
-
162
- Example `docs/index.ai.yml`:
163
-
164
- ```yaml
165
- version: 1
166
-
167
- title: Payload Markdown Docs
168
- canonical: /plugins/payload-markdown-docs
169
- output: /plugins/payload-markdown-docs.md
170
-
171
- description: >
172
- Consolidated AI-facing documentation export for Payload Markdown Docs.
173
-
174
- preamble: |
175
- This file is intended for AI agents, editor tooling, Codex, ChatGPT,
176
- and offline reference.
177
-
178
- order:
179
- - ./index.md
180
- - ./install.md
181
- - ./usage.md
182
-
183
- exclude:
184
- - ./drafts/**
185
-
186
- orphans: append
187
- headingMode: normalize
188
- ```
189
-
190
- ## 5. Validate Locally
102
+ For header navigation, use the link helper:
191
103
 
192
- Validation does not contact the server:
104
+ ```ts
105
+ import { getPayloadMarkdownDocsLinks } from '@valkyrianlabs/payload-markdown-docs/next'
193
106
 
194
- ```bash
195
- pnpm exec payload-markdown-docs validate ./docs \
196
- --source payload-markdown-docs \
197
- --route-base /plugins/payload-markdown-docs
107
+ const docsLinks = await getPayloadMarkdownDocsLinks({ payload })
108
+ // [{ label: 'Payload Markdown Docs', url: '/plugins/payload-markdown-docs' }]
198
109
  ```
199
110
 
200
- Preview the manifest or plan:
201
-
202
- ```bash
203
- pnpm exec payload-markdown-docs manifest ./docs \
204
- --source payload-markdown-docs \
205
- --route-base /plugins/payload-markdown-docs \
206
- --pretty
207
- ```
111
+ ## Validate Locally
208
112
 
209
113
  ```bash
210
- pnpm exec payload-markdown-docs plan ./docs \
211
- --source payload-markdown-docs \
212
- --route-base /plugins/payload-markdown-docs
114
+ pnpm exec payload-markdown-docs validate ./docs --source payload-markdown-docs
115
+ pnpm exec payload-markdown-docs manifest ./docs --source payload-markdown-docs --pretty
116
+ pnpm exec payload-markdown-docs plan ./docs --source payload-markdown-docs
213
117
  ```
214
118
 
215
- ## 6. Publish From GitHub Actions
119
+ In GitHub Actions, `--source` can be omitted when the docs set slug matches the
120
+ repository name. The CLI infers it from `GITHUB_REPOSITORY`.
216
121
 
217
- GitHub OIDC only works inside GitHub Actions. The workflow needs:
122
+ ## Publish From GitHub Actions
218
123
 
219
124
  ```yaml
220
125
  permissions:
221
126
  contents: read
222
127
  id-token: write
223
- ```
224
128
 
225
- Then push docs to the Payload sync endpoint:
226
-
227
- ```bash
228
- pnpm exec payload-markdown-docs push ./docs \
229
- --endpoint "https://docs.valkyrianlabs.com/api/payload-markdown-docs/sync" \
230
- --source payload-markdown-docs \
231
- --route-base /plugins/payload-markdown-docs \
232
- --repository "$GITHUB_REPOSITORY" \
233
- --branch "$GITHUB_REF_NAME" \
234
- --commit "$GITHUB_SHA" \
235
- --github-oidc \
236
- --oidc-audience payload-markdown-docs \
237
- --sync \
238
- --publish
129
+ steps:
130
+ - uses: actions/checkout@v4
131
+ - uses: pnpm/action-setup@v4
132
+ - uses: actions/setup-node@v4
133
+ with:
134
+ node-version: 22
135
+ cache: pnpm
136
+ - run: pnpm install --frozen-lockfile
137
+ - run: pnpm exec payload-markdown-docs validate ./docs
138
+ - run: |
139
+ pnpm exec payload-markdown-docs push ./docs \
140
+ --endpoint "$DOCS_SYNC_ENDPOINT" \
141
+ --repository "$GITHUB_REPOSITORY" \
142
+ --branch "$GITHUB_REF_NAME" \
143
+ --commit "$GITHUB_SHA" \
144
+ --github-oidc \
145
+ --sync \
146
+ --publish
239
147
  ```
240
148
 
241
- `--sync` only works when the server has `sync.allowWrites: true`.
242
- `--publish` also requires `sync.allowPublish: true` and
243
- `target.enableDrafts: true`.
149
+ `--sync` requires `sync.allowWrites: true`. `--publish` also requires
150
+ `sync.allowPublish: true` and a draft-enabled generated docs collection.
151
+
152
+ ## Local Ed25519 Push
244
153
 
245
- For non-GitHub CI, use Ed25519 keys instead of OIDC:
154
+ Generate a keypair, add the public key to `Docs Globals > Keys`, then push with
155
+ the private key:
246
156
 
247
157
  ```bash
248
158
  pnpm exec payload-markdown-docs keygen --out .docs-sync
249
159
  pnpm exec payload-markdown-docs push ./docs \
250
160
  --endpoint "$DOCS_SYNC_ENDPOINT" \
251
161
  --source payload-markdown-docs \
252
- --key-id github-actions-main \
253
- --private-key-env DOCS_SYNC_PRIVATE_KEY \
254
- --sync \
255
- --publish
162
+ --key-id local-docs \
163
+ --private-key-file .docs-sync/docs-sync-private.pem \
164
+ --sync
256
165
  ```
257
166
 
258
- ## This Repo
259
-
260
- This repo's release workflow publishes the npm package first, then pushes
261
- `./docs` to:
262
-
263
- ```text
264
- https://docs.valkyrianlabs.com/api/payload-markdown-docs/sync
265
- ```
167
+ ## Advanced Security
266
168
 
267
- using:
169
+ You do not need this for normal docs publishing.
268
170
 
269
- - source id: `payload-markdown-docs`
270
- - route base: `/plugins/payload-markdown-docs`
271
- - auth: GitHub OIDC configured on the matching docs set
272
- - mode: sync and publish
171
+ Each docs set has an advanced security section for exact GitHub workflow refs.
172
+ Leave it disabled to allow any workflow from a trusted owner/repository on the
173
+ configured branch. When enabled, add every allowed workflow ref explicitly; an
174
+ empty list rejects all workflow publishing for that docs set.
273
175
 
274
176
  ## More Docs
275
177
 
276
- - [Installation](docs/getting-started/installation.md)
277
178
  - [Quick Start](docs/getting-started/quick-start.md)
278
179
  - [Plugin Config](docs/configuration/plugin-config.md)
279
- - [GitHub OIDC](docs/configuration/github-oidc.md)
280
180
  - [GitHub Actions](docs/workflow/ci-github-actions.md)
281
- - [Route Adapter](docs/frontend/route-adapter.md)
282
- - [Troubleshooting](docs/reference/troubleshooting.md)
181
+ - [CLI](docs/reference/cli.md)
182
+ - [Migration Notes](docs/reference/migration.md)
@@ -1,5 +1,5 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { DEFAULT_DOCS_COLLECTION_SLUG, DEFAULT_DOCS_SETS_COLLECTION_SLUG } from '../constants.js';
2
+ import { DEFAULT_DOCS_COLLECTION_SLUG, DEFAULT_DOCS_GROUPS_COLLECTION_SLUG, DEFAULT_DOCS_SETS_COLLECTION_SLUG } from '../constants.js';
3
3
  import { getDocsSetManagerData } from './docsSetManagerData.js';
4
4
  const getFieldCustom = (field)=>{
5
5
  const custom = 'custom' in field ? field.custom : undefined;
@@ -208,6 +208,7 @@ const Summary = ({ data })=>/*#__PURE__*/ _jsxs("dl", {
208
208
  export const DocsSetManager = async ({ id, field, payload, req })=>{
209
209
  const custom = getFieldCustom(field);
210
210
  const docsCollectionSlug = custom.docsCollectionSlug ?? DEFAULT_DOCS_COLLECTION_SLUG;
211
+ const docsGroupsCollectionSlug = custom.docsGroupsCollectionSlug ?? DEFAULT_DOCS_GROUPS_COLLECTION_SLUG;
211
212
  const docsSetsCollectionSlug = custom.docsSetsCollectionSlug ?? DEFAULT_DOCS_SETS_COLLECTION_SLUG;
212
213
  if (!id) {
213
214
  return /*#__PURE__*/ _jsxs("section", {
@@ -224,6 +225,7 @@ export const DocsSetManager = async ({ id, field, payload, req })=>{
224
225
  const data = await getDocsSetManagerData({
225
226
  adminRoute: req.payload.config.routes.admin,
226
227
  docsCollectionSlug,
228
+ docsGroupsCollectionSlug,
227
229
  docsSetId: String(id),
228
230
  docsSetsCollectionSlug,
229
231
  payload: payload
@@ -247,10 +249,10 @@ export const DocsSetManager = async ({ id, field, payload, req })=>{
247
249
  /*#__PURE__*/ _jsxs("section", {
248
250
  children: [
249
251
  /*#__PURE__*/ _jsx("h3", {
250
- children: "Route Base"
252
+ children: "Effective Route"
251
253
  }),
252
254
  /*#__PURE__*/ _jsx("p", {
253
- children: data.docsSet.routeBase || 'No route base configured'
255
+ children: data.docsSet.routeBase || 'No route available yet'
254
256
  })
255
257
  ]
256
258
  }),
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/admin/DocsSetManager.tsx"],"sourcesContent":["import type { UIFieldServerProps } from 'payload'\nimport type { ReactNode } from 'react'\n\nimport type {\n DocsSetManagerData,\n DocsSetManagerDocItem,\n DocsSetManagerPayloadOperations,\n} from './docsSetManagerTypes.js'\n\nimport {\n DEFAULT_DOCS_COLLECTION_SLUG,\n DEFAULT_DOCS_SETS_COLLECTION_SLUG,\n} from '../constants.js'\nimport { getDocsSetManagerData } from './docsSetManagerData.js'\n\ntype DocsSetManagerFieldCustom = {\n docsCollectionSlug?: string\n docsSetsCollectionSlug?: string\n}\n\nconst getFieldCustom = (\n field: UIFieldServerProps['field'],\n): DocsSetManagerFieldCustom => {\n const custom = 'custom' in field ? field.custom : undefined\n\n if (!custom || typeof custom !== 'object') {\n return {}\n }\n\n return custom as DocsSetManagerFieldCustom\n}\n\nconst formatDate = (value?: string): string => {\n if (!value) {\n return 'Never'\n }\n\n const date = new Date(value)\n\n if (Number.isNaN(date.getTime())) {\n return value\n }\n\n return date.toISOString()\n}\n\nconst StatusLabel = ({ item }: { item: DocsSetManagerDocItem }) => {\n if (item.archived) {\n return <span>archived</span>\n }\n\n if (item.draft) {\n return <span>draft</span>\n }\n\n if (item.published) {\n return <span>published</span>\n }\n\n return <span>synced</span>\n}\n\nconst OverrideSummary = ({ item }: { item: DocsSetManagerDocItem }) => {\n if (item.overrideSummary.length === 0) {\n return <span>none</span>\n }\n\n return <span>{item.overrideSummary.join(', ')}</span>\n}\n\nconst renderDocItem = (item: DocsSetManagerDocItem): ReactNode => {\n if (item.kind === 'folder') {\n return (\n <details key={item.id}>\n <summary>{item.title}</summary>\n <div>\n {item.children?.map((child) => renderDocItem(child))}\n </div>\n </details>\n )\n }\n\n return (\n <details key={item.id}>\n <summary>{item.sourcePath}</summary>\n <dl>\n <div>\n <dt>Route</dt>\n <dd>{item.route || 'Missing route'}</dd>\n </div>\n <div>\n <dt>Title</dt>\n <dd>{item.title}</dd>\n </div>\n <div>\n <dt>Status</dt>\n <dd>\n <StatusLabel item={item} />\n </dd>\n </div>\n <div>\n <dt>Overrides</dt>\n <dd>\n <OverrideSummary item={item} />\n </dd>\n </div>\n </dl>\n {item.adminURL ? <a href={item.adminURL}>Open generated doc</a> : null}\n </details>\n )\n}\n\nconst Summary = ({ data }: { data: DocsSetManagerData }) => (\n <dl>\n <div>\n <dt>Docs</dt>\n <dd>{data.summary.total}</dd>\n </div>\n <div>\n <dt>Archived</dt>\n <dd>{data.summary.archived}</dd>\n </div>\n <div>\n <dt>Drafts</dt>\n <dd>{data.summary.drafts}</dd>\n </div>\n <div>\n <dt>Published</dt>\n <dd>{data.summary.published}</dd>\n </div>\n <div>\n <dt>Hidden from nav</dt>\n <dd>{data.summary.hiddenFromNav}</dd>\n </div>\n <div>\n <dt>With overrides</dt>\n <dd>{data.summary.withOverrides}</dd>\n </div>\n <div>\n <dt>Last sync</dt>\n <dd>{formatDate(data.sync?.lastSyncedAt)}</dd>\n </div>\n <div>\n <dt>Last status</dt>\n <dd>{data.sync?.lastStatus ?? 'unknown'}</dd>\n </div>\n </dl>\n)\n\nexport const DocsSetManager = async ({\n id,\n field,\n payload,\n req,\n}: UIFieldServerProps) => {\n const custom = getFieldCustom(field)\n const docsCollectionSlug = custom.docsCollectionSlug ?? DEFAULT_DOCS_COLLECTION_SLUG\n const docsSetsCollectionSlug =\n custom.docsSetsCollectionSlug ?? DEFAULT_DOCS_SETS_COLLECTION_SLUG\n\n if (!id) {\n return (\n <section>\n <h2>Generated Docs</h2>\n <p>Save this docs set before reviewing generated docs records.</p>\n </section>\n )\n }\n\n const data = await getDocsSetManagerData({\n adminRoute: req.payload.config.routes.admin,\n docsCollectionSlug,\n docsSetId: String(id),\n docsSetsCollectionSlug,\n payload: payload as DocsSetManagerPayloadOperations,\n })\n\n return (\n <section>\n <header>\n <h2>Generated Docs</h2>\n <p>\n Review generated docs records for {data.docsSet.title}. Source docs remain\n Git-backed; per-doc overrides can be edited by opening a generated doc.\n </p>\n </header>\n\n <section>\n <h3>Route Base</h3>\n <p>{data.docsSet.routeBase || 'No route base configured'}</p>\n </section>\n\n <section>\n <h3>Sync Summary</h3>\n <Summary data={data} />\n </section>\n\n {data.warnings.length > 0 ? (\n <section>\n <h3>Warnings</h3>\n <ul>\n {data.warnings.map((warning) => (\n <li key={`${warning.docId ?? 'docs-set'}:${warning.message}`}>\n {warning.sourcePath ? `${warning.sourcePath}: ` : null}\n {warning.message}\n </li>\n ))}\n </ul>\n </section>\n ) : null}\n\n <section>\n <h3>Generated Docs</h3>\n {data.tree.length > 0 ? (\n <div>{data.tree.map((item) => renderDocItem(item))}</div>\n ) : (\n <p>No generated docs records are linked to this docs set yet.</p>\n )}\n </section>\n </section>\n )\n}\n"],"names":["DEFAULT_DOCS_COLLECTION_SLUG","DEFAULT_DOCS_SETS_COLLECTION_SLUG","getDocsSetManagerData","getFieldCustom","field","custom","undefined","formatDate","value","date","Date","Number","isNaN","getTime","toISOString","StatusLabel","item","archived","span","draft","published","OverrideSummary","overrideSummary","length","join","renderDocItem","kind","details","summary","title","div","children","map","child","id","sourcePath","dl","dt","dd","route","adminURL","a","href","Summary","data","total","drafts","hiddenFromNav","withOverrides","sync","lastSyncedAt","lastStatus","DocsSetManager","payload","req","docsCollectionSlug","docsSetsCollectionSlug","section","h2","p","adminRoute","config","routes","admin","docsSetId","String","header","docsSet","h3","routeBase","warnings","ul","warning","li","message","docId","tree"],"mappings":"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"}
1
+ {"version":3,"sources":["../../src/admin/DocsSetManager.tsx"],"sourcesContent":["import type { UIFieldServerProps } from 'payload'\nimport type { ReactNode } from 'react'\n\nimport type {\n DocsSetManagerData,\n DocsSetManagerDocItem,\n DocsSetManagerPayloadOperations,\n} from './docsSetManagerTypes.js'\n\nimport {\n DEFAULT_DOCS_COLLECTION_SLUG,\n DEFAULT_DOCS_GROUPS_COLLECTION_SLUG,\n DEFAULT_DOCS_SETS_COLLECTION_SLUG,\n} from '../constants.js'\nimport { getDocsSetManagerData } from './docsSetManagerData.js'\n\ntype DocsSetManagerFieldCustom = {\n docsCollectionSlug?: string\n docsGroupsCollectionSlug?: string\n docsSetsCollectionSlug?: string\n}\n\nconst getFieldCustom = (\n field: UIFieldServerProps['field'],\n): DocsSetManagerFieldCustom => {\n const custom = 'custom' in field ? field.custom : undefined\n\n if (!custom || typeof custom !== 'object') {\n return {}\n }\n\n return custom as DocsSetManagerFieldCustom\n}\n\nconst formatDate = (value?: string): string => {\n if (!value) {\n return 'Never'\n }\n\n const date = new Date(value)\n\n if (Number.isNaN(date.getTime())) {\n return value\n }\n\n return date.toISOString()\n}\n\nconst StatusLabel = ({ item }: { item: DocsSetManagerDocItem }) => {\n if (item.archived) {\n return <span>archived</span>\n }\n\n if (item.draft) {\n return <span>draft</span>\n }\n\n if (item.published) {\n return <span>published</span>\n }\n\n return <span>synced</span>\n}\n\nconst OverrideSummary = ({ item }: { item: DocsSetManagerDocItem }) => {\n if (item.overrideSummary.length === 0) {\n return <span>none</span>\n }\n\n return <span>{item.overrideSummary.join(', ')}</span>\n}\n\nconst renderDocItem = (item: DocsSetManagerDocItem): ReactNode => {\n if (item.kind === 'folder') {\n return (\n <details key={item.id}>\n <summary>{item.title}</summary>\n <div>\n {item.children?.map((child) => renderDocItem(child))}\n </div>\n </details>\n )\n }\n\n return (\n <details key={item.id}>\n <summary>{item.sourcePath}</summary>\n <dl>\n <div>\n <dt>Route</dt>\n <dd>{item.route || 'Missing route'}</dd>\n </div>\n <div>\n <dt>Title</dt>\n <dd>{item.title}</dd>\n </div>\n <div>\n <dt>Status</dt>\n <dd>\n <StatusLabel item={item} />\n </dd>\n </div>\n <div>\n <dt>Overrides</dt>\n <dd>\n <OverrideSummary item={item} />\n </dd>\n </div>\n </dl>\n {item.adminURL ? <a href={item.adminURL}>Open generated doc</a> : null}\n </details>\n )\n}\n\nconst Summary = ({ data }: { data: DocsSetManagerData }) => (\n <dl>\n <div>\n <dt>Docs</dt>\n <dd>{data.summary.total}</dd>\n </div>\n <div>\n <dt>Archived</dt>\n <dd>{data.summary.archived}</dd>\n </div>\n <div>\n <dt>Drafts</dt>\n <dd>{data.summary.drafts}</dd>\n </div>\n <div>\n <dt>Published</dt>\n <dd>{data.summary.published}</dd>\n </div>\n <div>\n <dt>Hidden from nav</dt>\n <dd>{data.summary.hiddenFromNav}</dd>\n </div>\n <div>\n <dt>With overrides</dt>\n <dd>{data.summary.withOverrides}</dd>\n </div>\n <div>\n <dt>Last sync</dt>\n <dd>{formatDate(data.sync?.lastSyncedAt)}</dd>\n </div>\n <div>\n <dt>Last status</dt>\n <dd>{data.sync?.lastStatus ?? 'unknown'}</dd>\n </div>\n </dl>\n)\n\nexport const DocsSetManager = async ({\n id,\n field,\n payload,\n req,\n}: UIFieldServerProps) => {\n const custom = getFieldCustom(field)\n const docsCollectionSlug = custom.docsCollectionSlug ?? DEFAULT_DOCS_COLLECTION_SLUG\n const docsGroupsCollectionSlug =\n custom.docsGroupsCollectionSlug ?? DEFAULT_DOCS_GROUPS_COLLECTION_SLUG\n const docsSetsCollectionSlug =\n custom.docsSetsCollectionSlug ?? DEFAULT_DOCS_SETS_COLLECTION_SLUG\n\n if (!id) {\n return (\n <section>\n <h2>Generated Docs</h2>\n <p>Save this docs set before reviewing generated docs records.</p>\n </section>\n )\n }\n\n const data = await getDocsSetManagerData({\n adminRoute: req.payload.config.routes.admin,\n docsCollectionSlug,\n docsGroupsCollectionSlug,\n docsSetId: String(id),\n docsSetsCollectionSlug,\n payload: payload as DocsSetManagerPayloadOperations,\n })\n\n return (\n <section>\n <header>\n <h2>Generated Docs</h2>\n <p>\n Review generated docs records for {data.docsSet.title}. Source docs remain\n Git-backed; per-doc overrides can be edited by opening a generated doc.\n </p>\n </header>\n\n <section>\n <h3>Effective Route</h3>\n <p>{data.docsSet.routeBase || 'No route available yet'}</p>\n </section>\n\n <section>\n <h3>Sync Summary</h3>\n <Summary data={data} />\n </section>\n\n {data.warnings.length > 0 ? (\n <section>\n <h3>Warnings</h3>\n <ul>\n {data.warnings.map((warning) => (\n <li key={`${warning.docId ?? 'docs-set'}:${warning.message}`}>\n {warning.sourcePath ? `${warning.sourcePath}: ` : null}\n {warning.message}\n </li>\n ))}\n </ul>\n </section>\n ) : null}\n\n <section>\n <h3>Generated Docs</h3>\n {data.tree.length > 0 ? (\n <div>{data.tree.map((item) => renderDocItem(item))}</div>\n ) : (\n <p>No generated docs records are linked to this docs set yet.</p>\n )}\n </section>\n </section>\n )\n}\n"],"names":["DEFAULT_DOCS_COLLECTION_SLUG","DEFAULT_DOCS_GROUPS_COLLECTION_SLUG","DEFAULT_DOCS_SETS_COLLECTION_SLUG","getDocsSetManagerData","getFieldCustom","field","custom","undefined","formatDate","value","date","Date","Number","isNaN","getTime","toISOString","StatusLabel","item","archived","span","draft","published","OverrideSummary","overrideSummary","length","join","renderDocItem","kind","details","summary","title","div","children","map","child","id","sourcePath","dl","dt","dd","route","adminURL","a","href","Summary","data","total","drafts","hiddenFromNav","withOverrides","sync","lastSyncedAt","lastStatus","DocsSetManager","payload","req","docsCollectionSlug","docsGroupsCollectionSlug","docsSetsCollectionSlug","section","h2","p","adminRoute","config","routes","admin","docsSetId","String","header","docsSet","h3","routeBase","warnings","ul","warning","li","message","docId","tree"],"mappings":"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"}
@@ -1,23 +1,24 @@
1
- import type { DocsSetManagerData, DocsSetManagerPayloadOperations, RawDocsRecord, RawDocsSetRecord } from './docsSetManagerTypes.js';
1
+ import type { DocsSetManagerData, DocsSetManagerPayloadOperations, RawDocsGroupRecord, RawDocsRecord, RawDocsSetRecord } from './docsSetManagerTypes.js';
2
2
  export declare const getGeneratedDocAdminURL: ({ id, adminRoute, docsCollectionSlug, }: {
3
3
  adminRoute?: string;
4
4
  docsCollectionSlug: string;
5
5
  id: string;
6
6
  }) => string;
7
- export declare const buildDocsSetManagerData: ({ adminRoute, docs, docsCollectionSlug, docsSet, }: {
7
+ export declare const buildDocsSetManagerData: ({ adminRoute, docs, docsCollectionSlug, docsGroups, docsSet, }: {
8
8
  adminRoute?: string;
9
9
  docs: RawDocsRecord[];
10
10
  docsCollectionSlug?: string;
11
+ docsGroups?: RawDocsGroupRecord[];
11
12
  docsSet: RawDocsSetRecord;
12
13
  }) => DocsSetManagerData;
13
- export declare const isDocsRecordForDocsSet: ({ doc, docsSetId, sourceId, }: {
14
+ export declare const isDocsRecordForDocsSet: ({ doc, docsSetId, }: {
14
15
  doc: RawDocsRecord;
15
16
  docsSetId: string;
16
- sourceId: string;
17
17
  }) => boolean;
18
- export declare const getDocsSetManagerData: ({ adminRoute, docsCollectionSlug, docsSetId, docsSetsCollectionSlug, overrideAccess, payload, }: {
18
+ export declare const getDocsSetManagerData: ({ adminRoute, docsCollectionSlug, docsGroupsCollectionSlug, docsSetId, docsSetsCollectionSlug, overrideAccess, payload, }: {
19
19
  adminRoute?: string;
20
20
  docsCollectionSlug?: string;
21
+ docsGroupsCollectionSlug?: string;
21
22
  docsSetId: string;
22
23
  docsSetsCollectionSlug?: string;
23
24
  overrideAccess?: boolean;
@@ -1,4 +1,5 @@
1
- import { DEFAULT_DOCS_COLLECTION_SLUG, DEFAULT_DOCS_SETS_COLLECTION_SLUG } from '../constants.js';
1
+ import { DEFAULT_DOCS_COLLECTION_SLUG, DEFAULT_DOCS_GROUPS_COLLECTION_SLUG, DEFAULT_DOCS_SETS_COLLECTION_SLUG } from '../constants.js';
2
+ import { deriveDocsSetRouteBase, joinRouteSegments } from '../routing/index.js';
2
3
  const isRecord = (value)=>typeof value === 'object' && value !== null && !Array.isArray(value);
3
4
  const getRecordId = (doc)=>{
4
5
  if (!isRecord(doc)) {
@@ -35,15 +36,6 @@ const getOverrideSummary = (overrides)=>{
35
36
  if (overrides.hideFromNav === true) {
36
37
  summary.push('Hidden from nav');
37
38
  }
38
- if (hasText(overrides.theme)) {
39
- summary.push('Theme override');
40
- }
41
- if (hasText(overrides.heroEyebrow) || hasText(overrides.heroTitle) || hasText(overrides.heroDescription)) {
42
- summary.push('Hero override');
43
- }
44
- if (hasText(overrides.seoTitle) || hasText(overrides.seoDescription)) {
45
- summary.push('SEO override');
46
- }
47
39
  return summary;
48
40
  };
49
41
  const getDocStatus = (doc)=>{
@@ -66,6 +58,44 @@ const getSourcePathSegments = (sourcePath)=>{
66
58
  }
67
59
  return segments;
68
60
  };
61
+ const getGroupRoutePath = ({ groupId, groupsById, seen = new Set() })=>{
62
+ if (!groupId || seen.has(groupId)) {
63
+ return undefined;
64
+ }
65
+ const group = groupsById.get(groupId);
66
+ if (!group?.slug) {
67
+ return undefined;
68
+ }
69
+ return joinRouteSegments(getGroupRoutePath({
70
+ groupId: getRelationshipId(group.parent),
71
+ groupsById,
72
+ seen: new Set([
73
+ groupId,
74
+ ...seen
75
+ ])
76
+ }), group.slug);
77
+ };
78
+ const getDocsSetRouteBase = ({ docsGroups, docsSet })=>{
79
+ if (!docsSet.slug) {
80
+ return '';
81
+ }
82
+ const groupsById = new Map(docsGroups.flatMap((group)=>{
83
+ const id = getRecordId(group);
84
+ return id ? [
85
+ [
86
+ id,
87
+ group
88
+ ]
89
+ ] : [];
90
+ }));
91
+ return deriveDocsSetRouteBase({
92
+ docsSetSlug: docsSet.slug,
93
+ groupRoutePath: getGroupRoutePath({
94
+ groupId: getRelationshipId(docsSet.group),
95
+ groupsById
96
+ })
97
+ });
98
+ };
69
99
  const titleCaseSegment = (segment)=>segment.split(/[-_]+/).filter(Boolean).map((part)=>`${part.charAt(0).toUpperCase()}${part.slice(1)}`).join(' ');
70
100
  const compareDocItems = (first, second)=>{
71
101
  if (first.order !== second.order) {
@@ -173,7 +203,7 @@ const toDocItem = ({ adminRoute, doc, docsCollectionSlug, index, warnings })=>{
173
203
  title
174
204
  };
175
205
  };
176
- export const buildDocsSetManagerData = ({ adminRoute, docs, docsCollectionSlug = DEFAULT_DOCS_COLLECTION_SLUG, docsSet })=>{
206
+ export const buildDocsSetManagerData = ({ adminRoute, docs, docsCollectionSlug = DEFAULT_DOCS_COLLECTION_SLUG, docsGroups = [], docsSet })=>{
177
207
  const warnings = [];
178
208
  const docsSetId = getRecordId(docsSet) ?? 'unknown';
179
209
  const sortedDocs = docs.map((doc, index)=>toDocItem({
@@ -195,8 +225,11 @@ export const buildDocsSetManagerData = ({ adminRoute, docs, docsCollectionSlug =
195
225
  docs: sortedDocs,
196
226
  docsSet: {
197
227
  id: docsSetId,
198
- routeBase: docsSet.routeBase ?? '',
199
- sourceId: docsSet.sourceId ?? '',
228
+ slug: docsSet.slug ?? '',
229
+ routeBase: getDocsSetRouteBase({
230
+ docsGroups,
231
+ docsSet
232
+ }),
200
233
  title: docsSet.title ?? docsSetId
201
234
  },
202
235
  summary: {
@@ -216,14 +249,11 @@ export const buildDocsSetManagerData = ({ adminRoute, docs, docsCollectionSlug =
216
249
  warnings
217
250
  };
218
251
  };
219
- export const isDocsRecordForDocsSet = ({ doc, docsSetId, sourceId })=>{
252
+ export const isDocsRecordForDocsSet = ({ doc, docsSetId })=>{
220
253
  const docDocsSetId = getRelationshipId(doc.docsSet);
221
- if (docDocsSetId) {
222
- return docDocsSetId === docsSetId;
223
- }
224
- return doc.sync?.sourceId === sourceId;
254
+ return docDocsSetId === docsSetId;
225
255
  };
226
- export const getDocsSetManagerData = async ({ adminRoute, docsCollectionSlug = DEFAULT_DOCS_COLLECTION_SLUG, docsSetId, docsSetsCollectionSlug = DEFAULT_DOCS_SETS_COLLECTION_SLUG, overrideAccess = true, payload })=>{
256
+ export const getDocsSetManagerData = async ({ adminRoute, docsCollectionSlug = DEFAULT_DOCS_COLLECTION_SLUG, docsGroupsCollectionSlug = DEFAULT_DOCS_GROUPS_COLLECTION_SLUG, docsSetId, docsSetsCollectionSlug = DEFAULT_DOCS_SETS_COLLECTION_SLUG, overrideAccess = true, payload })=>{
227
257
  const docsSet = await payload.findByID({
228
258
  id: docsSetId,
229
259
  collection: docsSetsCollectionSlug,
@@ -236,29 +266,26 @@ export const getDocsSetManagerData = async ({ adminRoute, docsCollectionSlug = D
236
266
  limit: 1000,
237
267
  overrideAccess,
238
268
  where: {
239
- or: [
240
- {
241
- docsSet: {
242
- equals: docsSetId
243
- }
244
- },
245
- {
246
- 'sync.sourceId': {
247
- equals: docsSet.sourceId
248
- }
249
- }
250
- ]
269
+ docsSet: {
270
+ equals: docsSetId
271
+ }
251
272
  }
252
273
  });
274
+ const docsGroupsResult = await payload.find({
275
+ collection: docsGroupsCollectionSlug,
276
+ depth: 0,
277
+ limit: 1000,
278
+ overrideAccess
279
+ });
253
280
  const docs = docsResult.docs.filter(isRecord).map((doc)=>doc).filter((doc)=>isDocsRecordForDocsSet({
254
281
  doc,
255
- docsSetId,
256
- sourceId: docsSet.sourceId ?? ''
282
+ docsSetId
257
283
  }));
258
284
  return buildDocsSetManagerData({
259
285
  adminRoute,
260
286
  docs,
261
287
  docsCollectionSlug,
288
+ docsGroups: docsGroupsResult.docs.filter(isRecord).map((group)=>group),
262
289
  docsSet
263
290
  });
264
291
  };