关于 umbraco-workspace
帮助开发者构建 Umbraco 工作区,用于编辑内容、媒体、成员等实体。它指导选择默认或可路由工作区,并涵盖上下文、视图、操作和项目配置。
主要功能
- 01指导选择默认或可路由工作区
- 02提供上下文、视图和操作的实现模式
- 03支持多种实体类型的工作区
- 04说明如何将扩展接入 Umbraco 项目
- 05参考最新文档与源码示例
适用场景
- 01为实体类型创建工作区
- 02添加与树导航关联的实体编辑
- 03规划工作区视图和操作
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ umbraco/ umbraco-cms-backoffice-skills --skill umbraco-workspace安装后在 Claude Code 中输入/umbraco-workspace确认已加载。
详细介绍
Umbraco 工作区
它是什么?
工作区是 Umbraco 中针对特定实体类型设计的专用编辑环境。它们创建彼此隔离的区域,用户可在其中使用针对不同类型量身定制的专用界面,编辑内容、媒体、成员和其他实体。工作区会将实体数据的草稿副本与已发布版本分开保存,并支持多种扩展类型,包括上下文、视图、操作和页脚应用。
文档
实施前务必获取最新文档:
- 主要文档:https://docs.umbraco.com/umbraco-cms/extend-your-project/backoffice-extensions/extending-overview/extension-types/workspaces
- 工作区上下文:https://docs.umbraco.com/umbraco-cms/extend-your-project/backoffice-extensions/extending-overview/extension-types/workspaces/workspace-context
- 工作区视图:https://docs.umbraco.com/umbraco-cms/extend-your-project/backoffice-extensions/extending-overview/extension-types/workspaces/workspace-views
- 工作区操作:https://docs.umbraco.com/umbraco-cms/extend-your-project/backoffice-extensions/extending-overview/extension-types/workspaces/workspace-editor-actions
- 基础组件:https://docs.umbraco.com/umbraco-cms/extend-your-project/backoffice-extensions/foundation
- 扩展注册表:https://docs.umbraco.com/umbraco-cms/extend-your-project/backoffice-extensions/extending-overview/extension-registry
关键:工作区类型
kind: 'default' 与 kind: 'routable'
| 特性 | kind: 'default' | kind: 'routable' |
|---|---|---|
| 用例 | 静态页面、根工作区 | 使用唯一 ID 编辑实体 |
| 树集成 | 无选中状态 | 具备正确的选中状态 |
| URL 路由 | 无路由参数 | 支持 edit/:unique |
| 上下文 | 简单 | 具有 unique 可观察对象 |
树项目导航必须始终使用 kind: 'routable',否则:
- 在不同项目之间点击时,树项目的选中状态不会更新
- 无法在相同类型的项目之间导航
- 可能会出现“永远加载”的情况
可路由工作区上下文模式
对于 kind: 'routable' 工作区,必须创建工作区上下文类:
import { UmbWorkspaceRouteManager, UMB_WORKSPACE_CONTEXT } from '@umbraco-cms/backoffice/workspace';
import { UmbObjectState } from '@umbraco-cms/backoffice/observable-api';
import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api';
import { UmbContextBase } from '@umbraco-cms/backoffice/class-api';
import { LitElement, html } from '@umbraco-cms/backoffice/external/lit';
import { customElement } from '@umbraco-cms/backoffice/external/lit';
// Workspace editor element that renders views
@customElement('my-workspace-editor')
class MyWorkspaceEditorElement extends LitElement {
override render() {
return html`<umb-workspace-editor></umb-workspace-editor>`;
}
}
interface MyEntityData {
unique: string;
name?: string;
}
export class MyWorkspaceContext extends UmbContextBase {
public readonly workspaceAlias = 'My.Workspace';
#data = new UmbObjectState<MyEntityData | undefined>(undefined);
readonly data = this.#data.asObservable();
// CRITICAL: Observable unique for workspace views to consume
readonly unique = this.#data.asObservablePart((data) => data?.unique);
readonly name = this.#data.asObservablePart((data) => data?.name);
readonly routes = new UmbWorkspaceRouteManager(this);
constructor(host: UmbControllerHost) {
super(host, UMB_WORKSPACE_CONTEXT);
// Route pattern for tree item navigation
this.routes.setRoutes([
{
path: 'edit/:unique',
component: MyWorkspaceEditorElement,
setup: (_component, info) => {
const unique = info.match.params.unique;
this.load(unique);
},
},
]);
}
async load(unique: string) {
// Load entity data and update state
this.#data.setValue({ unique });
}
getUnique() {
return this.#data.getValue()?.unique;
}
getEntityType() {
return 'my-entity'; // Must match tree item entityType!
}
public override destroy(): void {
this.#data.destroy();
super.destroy();
}
}
export { MyWorkspaceContext as api };
使用上下文的工作区视图
工作区视图会观察上下文的 unique,以响应导航:
import { UMB_WORKSPACE_CONTEXT } from '@umbraco-cms/backoffice/workspace';
override connectedCallback() {
super.connectedCallback();
this.consumeContext(UMB_WORKSPACE_CONTEXT, (context) => {
if (!context) return;
// Observe unique - will fire when navigating between items
this.observe((context as any).unique, (unique: string | null) => {
if (unique) {
this._loadData(unique);
}
});
});
}
参考示例
Umbraco 源代码包含可正常运行的示例:
工作区上下文计数器:/Umbraco-CMS/src/Umbraco.Web.UI.Client/examples/workspace-context-counter/
此示例演示了一个包含上下文、视图和页脚应用的工作区,并包含单元测试。
工作区上下文初始名称:/Umbraco-CMS/src/Umbraco.Web.UI.Client/examples/workspace-context-initial-name/
此示例展示了工作区上下文的初始化模式。
工作区视图提示:/Umbraco-CMS/src/Umbraco.Web.UI.Client/examples/workspace-view-hint/
此示例演示了工作区视图提示和元数据。
相关基础技能
如果在实现工作区时需要解释以下基础概念,请参考这些技能:
-
Context API:实现工作区上下文、使用上下文,或解释工作区扩展间的通信时
- 参考技能:
umbraco-context-api
- 参考技能:
-
状态管理:实现草稿状态、可观察对象、响应式更新或工作区数据管理时
- 参考技能:
umbraco-state-management
- 参考技能:
-
Umbraco Element:实现工作区视图元素、解释 UmbElementMixin 或创建工作区组件时
- 参考技能:
umbraco-umbraco-element
- 参考技能:
-
控制器:实现工作区操作、控制器、副作用或操作逻辑时
- 参考技能:
umbraco-controllers
- 参考技能:
-
树:工作区关联到树导航时
- 参考技能:
umbraco-tree
- 参考技能:
工作流
- 获取文档 - 使用 WebFetch 访问上方文档 URL,获取最新的代码示例和模式
- 提问 - 实体类型是什么?需要哪些视图?有哪些操作?这是否关联到树?
- 选择类型 - 树形导航使用
kind: 'routable',静态页面使用kind: 'default' - 生成文件 - 根据获取的文档创建清单、工作区上下文、视图和操作
- 添加项目引用 - 扩展必须由主 Umbraco 项目引用才能正常工作:
- 在当前工作目录中搜索
.csproj文件 - 如果恰好找到一个 Umbraco 实例,则向其添加引用
- 如果找到多个 Umbraco 实例,则询问用户要使用哪一个
- 如果找不到 Umbraco 实例,则询问用户路径
- 在当前工作目录中搜索
- 说明 - 展示创建的内容以及测试方法
最小清单示例
export const manifests: UmbExtensionManifest[] = [
// Routable workspace for tree integration
{
type: 'workspace',
kind: 'routable',
alias: 'My.Workspace',
name: 'My Workspace',
api: () => import('./my-workspace.context.js'),
meta: {
entityType: 'my-entity', // Must match tree item entityType!
},
},
// Workspace view
{
type: 'workspaceView',
alias: 'My.WorkspaceView',
name: 'My Workspace View',
element: () => import('./my-workspace-view.element.js'),
weight: 100,
meta: {
label: 'Details',
pathname: 'details',
icon: 'icon-info',
},
conditions: [
{
alias: 'Umb.Condition.WorkspaceAlias',
match: 'My.Workspace',
},
],
},
];
生成代码前务必获取最新文档 - API 和模式可能已经发生变化。