umbraco-workspace
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseUmbraco Workspace
Umbraco 工作区
What is it?
什么是工作区?
Workspaces are dedicated editing environments designed for specific entity types in Umbraco. They create isolated areas where users can edit content, media, members, and other entities with specialized interfaces tailored to each type. Workspaces maintain draft copies of entity data separate from published versions and support multiple extension types including contexts, views, actions, and footer apps.
Workspaces是Umbraco中为特定实体类型设计的专用编辑环境。它们创建了隔离的区域,用户可以通过为每种类型量身定制的专用界面编辑内容、媒体、成员及其他实体。工作区会保留与已发布版本分离的实体数据草稿副本,并支持多种扩展类型,包括上下文、视图、操作和页脚应用。
Documentation
文档
Always fetch the latest docs before implementing:
- Main docs: https://docs.umbraco.com/umbraco-cms/customizing/extending-overview/extension-types/workspaces
- Workspace Context: https://docs.umbraco.com/umbraco-cms/customizing/extending-overview/extension-types/workspaces/workspace-context
- Workspace Views: https://docs.umbraco.com/umbraco-cms/customizing/extending-overview/extension-types/workspaces/workspace-views
- Workspace Actions: https://docs.umbraco.com/umbraco-cms/customizing/extending-overview/extension-types/workspaces/workspace-editor-actions
- Foundation: https://docs.umbraco.com/umbraco-cms/customizing/foundation
- Extension Registry: https://docs.umbraco.com/umbraco-cms/customizing/extending-overview/extension-registry
在实现前请务必获取最新文档:
- 主文档:https://docs.umbraco.com/umbraco-cms/customizing/extending-overview/extension-types/workspaces
- 工作区上下文:https://docs.umbraco.com/umbraco-cms/customizing/extending-overview/extension-types/workspaces/workspace-context
- 工作区视图:https://docs.umbraco.com/umbraco-cms/customizing/extending-overview/extension-types/workspaces/workspace-views
- 工作区操作:https://docs.umbraco.com/umbraco-cms/customizing/extending-overview/extension-types/workspaces/workspace-editor-actions
- 基础框架:https://docs.umbraco.com/umbraco-cms/customizing/foundation
- 扩展注册表:https://docs.umbraco.com/umbraco-cms/customizing/extending-overview/extension-registry
CRITICAL: Workspace Kinds
重要提示:工作区类型
kind: 'default'
vs kind: 'routable'
kind: 'default'kind: 'routable'kind: 'default'
vs kind: 'routable'
kind: 'default'kind: 'routable'| Feature | | |
|---|---|---|
| Use case | Static pages, root workspaces | Entity editing with unique IDs |
| Tree integration | No selection state | Proper selection state |
| URL routing | No route params | Supports |
| Context | Simple | Has |
For tree item navigation, ALWAYS use - otherwise:
kind: 'routable'- Tree item selection won't update when clicking between items
- Navigation between same-type items won't work
- "Forever loading" can occur
| 特性 | | |
|---|---|---|
| 使用场景 | 静态页面、根工作区 | 带唯一ID的实体编辑 |
| 树形结构集成 | 无选中状态 | 支持正确的选中状态 |
| URL路由 | 无路由参数 | 支持 |
| 上下文 | 简单类型 | 包含 |
若关联树形结构导航,请务必使用 - 否则会出现以下问题:
kind: 'routable'- 点击不同树形项时,选中状态不会更新
- 同类型项之间的导航无法正常工作
- 可能出现“持续加载”的情况
Routable Workspace Context Pattern
可路由工作区上下文模式
For workspaces, you MUST create a workspace context class:
kind: 'routable'typescript
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 };对于 类型的工作区,必须创建工作区上下文类:
kind: 'routable'typescript
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';
// 渲染视图的工作区编辑器元素
@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();
// 重要:供工作区视图使用的unique可观察对象
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);
// 树形项导航的路由规则
this.routes.setRoutes([
{
path: 'edit/:unique',
component: MyWorkspaceEditorElement,
setup: (_component, info) => {
const unique = info.match.params.unique;
this.load(unique);
},
},
]);
}
async load(unique: string) {
// 加载实体数据并更新状态
this.#data.setValue({ unique });
}
getUnique() {
return this.#data.getValue()?.unique;
}
getEntityType() {
return 'my-entity'; // 必须与树形项的entityType匹配!
}
public override destroy(): void {
this.#data.destroy();
super.destroy();
}
}
export { MyWorkspaceContext as api };Workspace View Consuming Context
消费上下文的工作区视图
Workspace views observe the context's to react to navigation:
uniquetypescript
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);
}
});
});
}工作区视图通过监听上下文的 属性来响应导航:
uniquetypescript
import { UMB_WORKSPACE_CONTEXT } from '@umbraco-cms/backoffice/workspace';
override connectedCallback() {
super.connectedCallback();
this.consumeContext(UMB_WORKSPACE_CONTEXT, (context) => {
if (!context) return;
// 监听unique属性 - 在切换项时触发
this.observe((context as any).unique, (unique: string | null) => {
if (unique) {
this._loadData(unique);
}
});
});
}Reference Examples
参考示例
The Umbraco source includes working examples:
Workspace Context Counter:
/Umbraco-CMS/src/Umbraco.Web.UI.Client/examples/workspace-context-counter/This example demonstrates a workspace with context, views, and footer apps. Includes unit tests.
Workspace Context Initial Name:
/Umbraco-CMS/src/Umbraco.Web.UI.Client/examples/workspace-context-initial-name/This example shows workspace context initialization patterns.
Workspace View Hint:
/Umbraco-CMS/src/Umbraco.Web.UI.Client/examples/workspace-view-hint/This example demonstrates workspace view hints and metadata.
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/该示例展示了工作区视图的提示信息和元数据。
Related Foundation Skills
相关基础技能
If you need to explain these foundational concepts when implementing workspaces, reference these skills:
-
Context API: When implementing workspace contexts, context consumption, or explaining workspace extension communication
- Reference skill:
umbraco-context-api
- Reference skill:
-
State Management: When implementing draft state, observables, reactive updates, or workspace data management
- Reference skill:
umbraco-state-management
- Reference skill:
-
Umbraco Element: When implementing workspace view elements, explaining UmbElementMixin, or creating workspace components
- Reference skill:
umbraco-umbraco-element
- Reference skill:
-
Controllers: When implementing workspace actions, controllers, side effects, or action logic
- Reference skill:
umbraco-controllers
- Reference skill:
-
Trees: When workspace is linked to tree navigation
- Reference skill:
umbraco-tree
- Reference skill:
在实现工作区时,如果需要解释以下基础概念,可以参考这些技能:
-
Context API:实现工作区上下文、上下文消费,或解释工作区扩展通信时
- 参考技能:
umbraco-context-api
- 参考技能:
-
状态管理:实现草稿状态、可观察对象、响应式更新,或工作区数据管理时
- 参考技能:
umbraco-state-management
- 参考技能:
-
Umbraco Element:实现工作区视图元素、解释UmbElementMixin,或创建工作区组件时
- 参考技能:
umbraco-umbraco-element
- 参考技能:
-
控制器:实现工作区操作、控制器、副作用,或操作逻辑时
- 参考技能:
umbraco-controllers
- 参考技能:
-
树形结构:工作区关联树形导航时
- 参考技能:
umbraco-tree
- 参考技能:
Workflow
工作流程
- Fetch docs - Use WebFetch on the documentation URLs above to get current code examples and patterns
- Ask questions - What entity type? What views needed? What actions? Is this linked to a tree?
- Choose kind - Use for tree navigation,
kind: 'routable'for static pageskind: 'default' - Generate files - Create manifest + workspace context + views + actions based on the fetched docs
- Add project reference - The extension must be referenced by the main Umbraco project to work:
- Search for files in the current working directory
.csproj - If exactly one Umbraco instance is found, add the reference to it
- If multiple Umbraco instances are found, ask the user which one to use
- If no Umbraco instance is found, ask the user for the path
- Search for
- Explain - Show what was created and how to test
- 获取文档 - 使用WebFetch访问上述文档链接,获取最新的代码示例和模式
- 确认需求 - 明确实体类型、所需视图、操作,以及是否关联树形结构
- 选择类型 - 关联树形导航时使用 ,静态页面使用
kind: 'routable'kind: 'default' - 生成文件 - 根据获取的文档创建清单、工作区上下文、视图和操作
- 添加项目引用 - 扩展必须被主Umbraco项目引用才能生效:
- 在当前工作目录中搜索 文件
.csproj - 如果找到唯一的Umbraco实例,自动添加引用
- 如果找到多个Umbraco实例,请询问用户选择哪一个
- 如果未找到Umbraco实例,请询问用户提供路径
- 在当前工作目录中搜索
- 说明解释 - 展示创建的内容及测试方法
Minimal Manifest Example
最小化清单示例
typescript
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',
},
],
},
];Always fetch fresh docs before generating code - the API and patterns may have changed.
typescript
export const manifests: UmbExtensionManifest[] = [
// 关联树形结构的可路由工作区
{
type: 'workspace',
kind: 'routable',
alias: 'My.Workspace',
name: 'My Workspace',
api: () => import('./my-workspace.context.js'),
meta: {
entityType: 'my-entity', // 必须与树形项的entityType匹配!
},
},
// 工作区视图
{
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和模式可能已发生变更。