@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.
- package/README.md +76 -176
- package/dist/admin/DocsSetManager.js +5 -3
- package/dist/admin/DocsSetManager.js.map +1 -1
- package/dist/admin/docsSetManagerData.d.ts +6 -5
- package/dist/admin/docsSetManagerData.js +60 -33
- package/dist/admin/docsSetManagerData.js.map +1 -1
- package/dist/admin/docsSetManagerTypes.d.ts +12 -9
- package/dist/admin/docsSetManagerTypes.js.map +1 -1
- package/dist/cli/commands/manifest.js +1 -2
- package/dist/cli/commands/manifest.js.map +1 -1
- package/dist/cli/commands/plan.js +1 -2
- package/dist/cli/commands/plan.js.map +1 -1
- package/dist/cli/commands/push.js +2 -5
- package/dist/cli/commands/push.js.map +1 -1
- package/dist/cli/commands/validate.js +11 -6
- package/dist/cli/commands/validate.js.map +1 -1
- package/dist/cli/index.js +5 -14
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/parseArgs.js +0 -3
- package/dist/cli/parseArgs.js.map +1 -1
- package/dist/cli/types.d.ts +0 -3
- package/dist/cli/types.js.map +1 -1
- package/dist/collections/docs.js +0 -24
- package/dist/collections/docs.js.map +1 -1
- package/dist/collections/docsGroups.js +8 -9
- package/dist/collections/docsGroups.js.map +1 -1
- package/dist/collections/docsKeys.d.ts +5 -0
- package/dist/collections/docsKeys.js +44 -0
- package/dist/collections/docsKeys.js.map +1 -0
- package/dist/collections/docsSets.js +47 -202
- package/dist/collections/docsSets.js.map +1 -1
- package/dist/collections/docsTrusted.d.ts +5 -0
- package/dist/collections/docsTrusted.js +60 -0
- package/dist/collections/docsTrusted.js.map +1 -0
- package/dist/collections/index.d.ts +4 -0
- package/dist/collections/index.js +2 -0
- package/dist/collections/index.js.map +1 -1
- package/dist/constants.d.ts +3 -1
- package/dist/constants.js +3 -1
- package/dist/constants.js.map +1 -1
- package/dist/endpoints/sync.d.ts +6 -7
- package/dist/endpoints/sync.js +57 -124
- package/dist/endpoints/sync.js.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/next/PayloadMarkdownDocsPage.js +2 -6
- package/dist/next/PayloadMarkdownDocsPage.js.map +1 -1
- package/dist/next/index.d.ts +2 -0
- package/dist/next/index.js +1 -0
- package/dist/next/index.js.map +1 -1
- package/dist/next/links.d.ts +11 -0
- package/dist/next/links.js +79 -0
- package/dist/next/links.js.map +1 -0
- package/dist/next/markdown.js +91 -19
- package/dist/next/markdown.js.map +1 -1
- package/dist/next/metadata.js +6 -6
- package/dist/next/metadata.js.map +1 -1
- package/dist/next/records.js +13 -23
- package/dist/next/records.js.map +1 -1
- package/dist/next/route.js +141 -49
- package/dist/next/route.js.map +1 -1
- package/dist/next/types.d.ts +0 -14
- package/dist/next/types.js.map +1 -1
- package/dist/payload/docsKeys.d.ts +20 -0
- package/dist/payload/docsKeys.js +29 -0
- package/dist/payload/docsKeys.js.map +1 -0
- package/dist/payload/docsSets.d.ts +32 -6
- package/dist/payload/docsSets.js +146 -83
- package/dist/payload/docsSets.js.map +1 -1
- package/dist/payload/docsTrusted.d.ts +16 -0
- package/dist/payload/docsTrusted.js +49 -0
- package/dist/payload/docsTrusted.js.map +1 -0
- package/dist/payload/index.d.ts +5 -1
- package/dist/payload/index.js +3 -1
- package/dist/payload/index.js.map +1 -1
- package/dist/plugin.js +36 -9
- package/dist/plugin.js.map +1 -1
- package/dist/security/githubOidc.d.ts +18 -5
- package/dist/security/githubOidc.js +44 -16
- package/dist/security/githubOidc.js.map +1 -1
- package/dist/security/index.d.ts +1 -1
- package/dist/security/index.js.map +1 -1
- package/dist/skills/codex/SKILL.md +3 -4
- package/dist/skills/codex/examples/github-actions.md +0 -2
- package/dist/skills/codex/reference/admin.md +0 -6
- package/dist/skills/codex/reference/routing.md +2 -1
- package/dist/skills/codex/reference/sync.md +7 -5
- package/dist/skills/codex/reference/troubleshooting.md +3 -4
- package/dist/skills/codex/reference/workflow.md +0 -1
- package/dist/sync/manifest.d.ts +1 -3
- package/dist/sync/manifest.js +2 -3
- package/dist/sync/manifest.js.map +1 -1
- package/dist/sync/validate.js +1 -2
- package/dist/sync/validate.js.map +1 -1
- package/dist/types.d.ts +7 -50
- package/dist/types.js.map +1 -1
- 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
|
-
|
|
6
|
+
The default workflow is intentionally small:
|
|
7
7
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
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
|
|
20
|
+
Install the same package in any repository that runs the
|
|
35
21
|
`payload-markdown-docs` CLI.
|
|
36
22
|
|
|
37
|
-
##
|
|
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
|
-
|
|
47
|
+
This adds `Docs Globals` admin collections:
|
|
78
48
|
|
|
79
|
-
-
|
|
80
|
-
-
|
|
81
|
-
|
|
82
|
-
-
|
|
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
|
-
|
|
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
|
-
##
|
|
56
|
+
## Create Admin Records
|
|
95
57
|
|
|
96
|
-
|
|
97
|
-
config:
|
|
58
|
+
Create a docs set:
|
|
98
59
|
|
|
99
|
-
- `
|
|
100
|
-
-
|
|
101
|
-
-
|
|
102
|
-
- `
|
|
103
|
-
-
|
|
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
|
-
|
|
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
|
-
|
|
68
|
+
- owner: `valkyrianlabs`
|
|
69
|
+
- `limitRepos`: off, unless you want to list specific repositories
|
|
116
70
|
|
|
117
|
-
|
|
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
|
-
|
|
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
|
-
|
|
104
|
+
```ts
|
|
105
|
+
import { getPayloadMarkdownDocsLinks } from '@valkyrianlabs/payload-markdown-docs/next'
|
|
193
106
|
|
|
194
|
-
|
|
195
|
-
|
|
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
|
-
|
|
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
|
|
211
|
-
|
|
212
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
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`
|
|
242
|
-
|
|
243
|
-
|
|
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
|
-
|
|
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
|
|
253
|
-
--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
|
-
##
|
|
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
|
-
|
|
169
|
+
You do not need this for normal docs publishing.
|
|
268
170
|
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
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
|
-
- [
|
|
282
|
-
- [
|
|
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
|
|
252
|
+
children: "Effective Route"
|
|
251
253
|
}),
|
|
252
254
|
/*#__PURE__*/ _jsx("p", {
|
|
253
|
-
children: data.docsSet.routeBase || 'No route
|
|
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
|
|
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,
|
|
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
|
-
|
|
199
|
-
|
|
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
|
|
252
|
+
export const isDocsRecordForDocsSet = ({ doc, docsSetId })=>{
|
|
220
253
|
const docDocsSetId = getRelationshipId(doc.docsSet);
|
|
221
|
-
|
|
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
|
-
|
|
240
|
-
|
|
241
|
-
|
|
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
|
};
|