Early Adopter's guide to Umbraco v14 - Workspaces
Tags: umbraco
Published: 2024-02-01 20:17:08


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. 


![Workspace is the main big box](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/fwum3hnxhwu78wn7w51e.png)

> ### 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. 

```ts
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](https://dev.to/kevinjump/early-adopters-guide-to-umbraco-v14-sections-sidebars-and-menus-31i8). we need to tell it the 'entity-type' that the menu item opens. 

for us that is the workspace entity-type. 

```ts
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.

```ts
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.

![Page with workspace element](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/drwr1bfap6h1qssenaq8.png)

## 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 :

```ts
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:

![Workspace content](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/n40e1ei1oy73z2a4a1ku.png)

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: 

```ts
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. 

1. impliment the `UmbWorkspaceContextInterface` 
2. Provide a UMB_WORKSPACE_CONTEXT to itself, 
3. be instanciated somewhere (i have done this in the WorkspaceElement

**1. Impliment (UmbWorkspaceContextInterface)**

```ts
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

```ts
@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'

![Workspace with tabs in a custom section](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/185sy3rs02o047gwh4b4.png)

. Result ! 

I think next time we might step back and make a content app. 

---

> _**Updated:** 2/3/2024 - preview008 renamed getEntityId -> getUnique_