版本控制

Payload 强大的 Versions 功能允许你保留随时间变化的完整历史记录,并可扩展以适应任何内容发布工作流。

启用后,Payload 会自动在你的数据库中创建一个新的 Collection 来存储文档的版本历史。Admin UI 会扩展额外的视图,让你可以浏览文档版本、查看差异(了解文档具体发生了哪些变化以及何时发生变化),并轻松将文档恢复到之前的版本。

Versions 比较文档的旧版本与新版本

使用 Versions 功能,你可以:

  • 维护文档所有更改的审计日志/历史记录,包括监控哪个用户做了哪些更改
  • 在需要回滚更改时,将文档和 globals 恢复到之前的状态
  • 为你的数据构建真正的 Draft Preview 模式
  • 通过 Access Control 管理谁可以查看草稿,谁只能查看已发布的文档
  • 在 collections 和 globals 上启用 Autosave 功能,避免工作丢失
  • 构建强大的发布计划机制,创建文档并在未来指定日期自动公开发布

Versions 功能性能极高且完全可选。它不会改变你的数据结构。所有版本都存储在一个单独的 Collection 中,可以根据需要轻松开启或关闭。

选项

Versions 支持几种不同级别的功能,每种功能都会对文档工作流产生不同的影响。

启用版本控制但禁用草稿模式

如果你启用了版本控制但保持草稿模式禁用状态,Payload 会在每次更新文档时简单地创建一个新版本。这种方式非常适合需要保留文档所有更新历史记录,但始终希望将最新版本视为"已发布"版本的用例。

例如,"启用版本控制但禁用草稿模式"的用例可以应用在用户集合上,你可能想要保留用户所有更改的版本历史(或审计日志)——但对用户的任何更改都应始终被视为"已发布",并且你不需要维护用户的"草稿"版本。

同时启用版本控制和草稿模式

如果你同时启用了版本控制和草稿模式,你将能够控制哪些文档是已发布的,哪些被视为草稿。这让你可以编写访问控制来管理谁可以查看已发布文档,谁可以查看草稿文档。它还允许你保存比最近发布文档更新的版本(草稿),这在你想起草更改甚至可能在发布更改前预览它们时非常有用。了解更多关于草稿模式的信息请点击这里

同时启用版本控制、草稿模式和自动保存

当你同时启用版本控制、草稿模式和autosave功能时,Admin UI 会在你编辑文档时自动将更改保存到新的draft版本中,这确保了你永远不会丢失任何更改。自动保存完全不会影响你已发布的文章——它只会保存你的更改,并让你或你的编辑在准备好时发布它们。了解更多关于自动保存的信息请点击这里

集合配置

配置版本功能是通过在集合配置中添加 versions 键来实现的。将其设置为 true 可启用默认版本设置,或通过将该属性设置为包含以下可用选项的对象来自定义版本功能:

选项描述
maxPerDoc使用此设置控制每个文档保留的版本数量。必须为整数。默认为 100,设置为 0 可保存所有版本。
drafts为此集合启用草稿模式。设置为 true 或传递包含草稿选项的对象来启用。

全局配置

全局版本功能与集合版本功能类似,但支持的配置属性略有不同。

选项描述
max使用此设置控制每个全局保留的版本数量。必须为整数。
drafts为此全局启用草稿模式。设置为 true 或传递包含草稿选项的对象来启用。

数据库影响

启用 versions 后,系统会创建一个新的数据库集合来存储你的 collection 或 global 的版本。该集合的命名基于 collection 或 global 的 slug,并遵循以下模式(其中 slug 会被替换为你的 collection 或 global 的 slug):

_slug_versions

在这个新的 versions 集合中,每个文档都会存储关于版本的元数据属性以及文档的完整副本。例如,一个 Collection 文档的版本数据可能如下所示:

{
  "_id": "61cf752c19cdf1b1af7b61f1", // 该版本的唯一 ID
  "parent": "61ce1354091d5b3ffc20ea6e", // 父文档的 ID
  "autosave": false, // 标记该版本是否通过自动保存创建
  "version": {
    // 你的文档数据放在这里
    // 所有字段都不必是必填的,这个属性可以是部分完成的
  },
  "createdAt": "2021-12-31T21:25:00.992+00:00",
  "updatedAt": "2021-12-31T21:25:00.992+00:00"
}

Global 版本的存储方式与上面展示的 collection 版本相同,只是不包含 parent 属性,因为每个 Global 都有自己的 versions 集合。这意味着我们知道该集合中的所有版本都对应于该特定的 global。

版本操作

版本功能为 collections 和 globals 都提供了新的操作。它们允许你查找和查询版本、通过 ID 查找单个版本,以及通过 ID 发布(或恢复)版本。Collections 和 Globals 都支持相同的新操作。这些操作主要由 admin UI 使用,但如果你在应用中编写自定义逻辑并希望使用它们,也可以通过 REST、GraphQL 和 Local API 来使用这些操作。

Collection REST 端点:

MethodPath描述
GET/api/{collectionSlug}/versions查询分页版本
GET/api/{collectionSlug}/versions/:id根据 ID 查询特定版本
POST/api/{collectionSlug}/versions/:id根据 ID 恢复版本

Collection GraphQL 查询:

查询名称操作类型
version{collection.label.singular}findVersionByID
versions{collection.label.plural}findVersions

以及变更操作:

查询名称操作类型
restoreVersion{collection.label.singular}restoreVersion

Collection 本地 API 方法:

查询

// 结果将是一个分页的版本集合。
// 更多信息请参阅 /docs/queries/pagination
const result = await payload.findVersions({
  collection: 'posts', // 必填
  depth: 2,
  page: 1,
  limit: 10,
  where: {}, // 可在此处传递 `where` 查询条件
  sort: '-createdAt',
  locale: 'en',
  fallbackLocale: false,
  user: dummyUser,
  overrideAccess: false,
  showHiddenFields: true,
})

根据 ID 查询

// 结果将是一个 Post 文档。
const result = await payload.findVersionByID({
  collection: 'posts', // 必填
  id: '507f1f77bcf86cd799439013', // 必填
  depth: 2,
  locale: 'en',
  fallbackLocale: false,
  user: dummyUser,
  overrideAccess: false,
  showHiddenFields: true,
})

恢复

// 结果将是恢复后的全局文档。
const result = await payload.restoreVersion({
  collection: 'posts', // 必填
  id: '507f1f77bcf86cd799439013', // 必填
  depth: 2,
  user: dummyUser,
  overrideAccess: false,
  showHiddenFields: true,
})

全局 REST 端点:

方法路径描述
GET/api/globals/{globalSlug}/versions查找并查询分页版本
GET/api/globals/{globalSlug}/versions/:id通过 ID 查找特定版本
POST/api/globals/{globalSlug}/versions/:id通过 ID 恢复版本

全局 GraphQL 查询:

查询名称操作
version{global.label}findVersionByID
versions{global.label}findVersions

全局 GraphQL 变更:

查询名称操作
restoreVersion{global.label}restoreVersion

全局本地 API 方法:

查找

// 结果将是分页的版本集合。
// 更多信息请参阅 /docs/queries/pagination。
const result = await payload.findGlobalVersions({
  slug: 'header', // 必填
  depth: 2,
  page: 1,
  limit: 10,
  where: {}, // 在此传递 `where` 查询
  sort: '-createdAt',
  locale: 'en',
  fallbackLocale: false,
  user: dummyUser,
  overrideAccess: false,
  showHiddenFields: true,
})

通过 ID 查找

// 结果将是一个 Post 文档。
const result = await payload.findGlobalVersionByID({
  slug: 'header', // 必填
  id: '507f1f77bcf86cd799439013', // 必填
  depth: 2,
  locale: 'en',
  fallbackLocale: false,
  user: dummyUser,
  overrideAccess: false,
  showHiddenFields: true,
})

恢复版本

// Result will be the restored global document.
const result = await payload.restoreGlobalVersion({
  slug: 'header', // required
  id: '507f1f77bcf86cd799439013', // required
  depth: 2,
  user: dummyUser,
  overrideAccess: false,
  showHiddenFields: true,
})

访问控制

版本功能在 CollectionsGlobals 上都暴露了一个新的 Access Control 函数,允许你控制谁可以查看文档版本,谁不能查看。

函数允许/拒绝访问
readVersions用于控制谁可以读取版本,谁不能读取。将自动限制 Admin UI 中的版本查看权限。

有关如何将访问控制与版本功能结合使用的完整详情,请参阅 Access Control 文档。