So now, if you have been following along, we have all sort of cool things, we have a dashboard that talks to the server back end, with contexts, repositories, stores and resources, a custom section with a menu and a menu item, and well the beginnings of quite a useless time package.
Today we are going to plumb in our menu item to something, a workspace. In umbraco v14 land a workspace is essentially everything in the big main box.
Whats a workspace?
Anything that isn't the menu bar or the sidebar happens in a workspace. So there is a document workspace for content, a media one for media, and so on. Its not that there is 'one' big workspace for all documents, but when you open a content item, everything in the box is in the workspace.
Creating a workspace.
You can probibly guess by now a workspace is created via a manifest config.
var workspaceManifest : ManifestWorkspace = {
type: 'workspace',
alias: 'time.workspace',
name: 'time workspace',
element: ()=> import('./workspace.element'),
meta: {
entityType: 'time-workspace'
}
};
What is worth noting here is that we are going to import a "workspace elemet" this will be the lit element that renders the page.
the entity-type is not the element type that renders the page, rather it is a 'type name' of the workspace. this is the value that is used to link the workspace to the menu (or tree).
Linking the workspace to a menu item.
going back to the menu item we created in the last post. we need to tell it the 'entity-type' that the menu item opens.
for us that is the workspace entity-type.
const menuItemManifest : ManifestMenuItem = {
type: 'menuItem',
alias: 'time.menu,item',
name: 'time menu item',
meta: {
label: 'Time Zones',
icon: 'icon-alarm-clock',
entityType: 'time-workspace',
menus: [
'time.menu'
]
}
}
We have matched the entity-type in the workspace with the one on the menu item, when you click the menu item, the workspace loads!
Workspace element.
So we jumped the gun a little there because we just linked to an element type we haven't written yet.
the root workspace element, is the thing that will be the parent to everything we do in the workspace. its allmost like its the lit-app for the workspace.
import { UmbElementMixin }
from "@umbraco-cms/backoffice/element-api";
import { LitElement, html, customElement }
from "@umbraco-cms/backoffice/external/lit";
@customElement('time-workspace-root')
export class TimeWorkspaceElement extends
UmbElementMixin(LitElement) {
render() {
return html`
<umb-workspace-editor
headline="Time"
alias="time.workspace.root"
.enforceNoFooter=${true}>
</umb-workspace-editor>
`
}
}
export default TimeWorkspaceElement;
the <umb-workspace-editor>
component gives us the nice header bar (and footer if you don't turn it off), so you can give your page the 'umbraco' look and feel.
Workspace content,
Now at this point you can put content between the <umb-workspace-editor>
and it will render on the page.
if we replace our workspace element's render method with this :
render() {
return html`
<umb-workspace-editor
headline="Time"
alias="time.workspace"
.enforceNoFooter=${true}>
<uui-box headline='my workspace content'>
<p>Some content goes here</p>
</uui-box>
</umb-workspace-editor>
`;
}
That will render some content like so:
but you can be a bit more fancy, and have options.
Workspace views.
Workspace views, are individual views, that can be reached via the icons in the top right hand corner of a workspace.
these are where 'content apps' have gone to
when we are not making a custom section, we can define a view in an existin workspace (like the document workspace) and it will appear like a content app.!
workspace views have a manifest definition:
var workspaceViews : Array<ManifestWorkspaceView> = [
{
type: 'workspaceView',
alias: 'time.workspace.default',
name: 'default view',
js: () => import('./views/defaultWorkspace.element.js'),
weight: 300,
meta: {
icon: 'icon-alarm-clock',
pathname: 'overview',
label: 'time'
},
conditions: [
{
alias: 'Umb.Condition.WorkspaceAlias',
match: workspace.alias
},
],
},
];
although obviously if you are using views you would have more than one
🚨Potential pain point alert🚨
the trick to views.... and i spent a long time figuring this one out, is that you need to have an active workspace context, before the<umb-workspace-editor>
will render the icons in the view.
Workspace context.
In order for views to work a workspace context has to do three things.
- impliment the
UmbWorkspaceContextInterface
- Provide a UMB_WORKSPACE_CONTEXT to itself,
- be instanciated somewhere (i have done this in the WorkspaceElement
1. Impliment (UmbWorkspaceContextInterface)
export class TimeWorkspaceContext
extends UmbBaseController
implements UmbWorkspaceContextInterface {
public readonly workspaceAlias: string = 'time.workspace';
constructor(host:UmbControllerHostElement) {
super(host);
this.provideContext(UMB_WORKSPACE_CONTEXT, this);
this.provideContext(TIME_WORKSPACE_CONTEXT, this);
}
getEntityType(): string {
return 'time-workspace';
}
getUnique(): string | undefined {
return undefined;
}
}
2. Provide UMB_WORKSPACE_CONTEXT
The note here which is missed is UMB_WORKSPACE_CONTEXT
- i think this is like adding the context to a collection or workspace contexts across the app, and when the <umb-workspace-editor>
tag comes to find workspaces it does so by getting hold of your context. 🤷
3. be instanciated somewhere
For this i have added it to the top of my workspace element
@customElement('time-workspace-root')
export class TimeWorkspaceElement extends UmbElementMixin(LitElement) {
#workspaceContext = new TimeWorkspaceContext(this);
...
Now all that is in place, and i am less some hair. we get a workspace with 'tabs'
. Result !
I think next time we might step back and make a content app.
Updated: 2/3/2024 - preview008 renamed getEntityId -> getUnique
Top comments (1)
This is gold, thank you for this guide, its going to spare me hours of research. I have a question though. Is it possible to use a normal .html file as a dashboard "view"? It seems that everything needs to be a lit element now.