EntityAction Setup
Registering the EntityAction:
To create a custom EntityAction, you’ll need to register it by creating some TypeScript files:
manifest.ts
//import the entity type for Member
import { UMB_MEMBER_ENTITY_TYPE } from "@umbraco-cms/backoffice/member";
import { ManifestEntityAction } from "@umbraco-cms/backoffice/extension-registry";
//import our entity action definition
import { MemberEntityAction } from "./member.entity.action";
const entityAction: ManifestEntityAction = {
type: 'entityAction',
kind: 'default',
alias: 'member.entity.action',
name: 'member action',
weight: -100,
forEntityTypes: [
UMB_MEMBER_ENTITY_TYPE //only appear for the Member entity
],
api: MemberEntityAction,
meta: {
icon: 'icon-message',
label: 'Resend Validation',
},
conditions: [{
alias: "Umb.Condition.SectionAlias",
match: "Umb.Section.Members"
}]
}
export const manifests = [entityAction];
Customizing EntityActions:
- You can attach a class to the EntityAction as part of the extension manifest.
- This class will be instantiated when the action is triggered.
- It has access to the host element, repository alias, and unique identifier (key) of the entity.
- You can provide either a
getHrefmethod (for a link) or anexecutemethod (for custom logic).
MemberEntityAction definition:
- Here we attach the UmbMemberDetailRepository to instantiate hen action is triggered.
- In the provided
executemethod, we open our custom modal. - We also add an onSubmit method handler to call our api with the unique identifier (key) of the entity.
member.entity.action.ts
import { UmbControllerHostElement } from "@umbraco-cms/backoffice/controller-api";
import { UmbEntityActionArgs, UmbEntityActionBase } from "@umbraco-cms/backoffice/entity-action";
import { UMB_MODAL_MANAGER_CONTEXT, UmbModalManagerContext } from "@umbraco-cms/backoffice/modal";
import { MEMBER_CUSTOM_MODAL } from "../../modal/modal-token.ts";
import { UmbMemberDetailRepository } from '@umbraco-cms/backoffice/member';
export class MemberEntityAction extends UmbEntityActionBase<UmbMemberDetailRepository> {
#modalManagerContext?: UmbModalManagerContext;
constructor(host: UmbControllerHostElement, args: UmbEntityActionArgs<UmbMemberDetailRepository>)
{
super(host, args)
// Fetch/consume the contexts & assign to the private fields
this.consumeContext(UMB_MODAL_MANAGER_CONTEXT, (instance) => {
this.#modalManagerContext = instance;
});
}
async execute() {
//The modal does NOT return any data when closed (it does not submit)
const modal = this.#modalManagerContext?.open(this, MEMBER_CUSTOM_MODAL, {
data: {
headline:'Resend Validation',
content: 'Do you want to resend the validation Email?'
}
});
await modal?.onSubmit().then(() => {
const headers: Headers = new Headers()
headers.set('Content-Type', 'application/json')
headers.set('Accept', 'application/json')
const request: RequestInfo = new Request('/sendvalidation/' + this.args.unique?.toString(), {
method: 'GET',
headers: headers,
})
// Send the request and print the response
return fetch(request)
.then(res => {
console.log("got response:", res)
})
}).catch(() => {
return;
});
}
}
Modal Dialog Setup
- In much the same way as we did for the EntityAction, we need to create a few files to define the modal.
manifest.ts - this the declaration for the modal dialog
import { ManifestModal } from "@umbraco-cms/backoffice/extension-registry";
const modals: Array<ManifestModal> = [
{
type: 'modal',
alias: 'member.custom.modal',
name: 'Member custom modal',
js: () => import('./modal-element.js')
}
];
export const manifests = [...modals];
modal-element.ts - code that renders the dialog ui and registers methods to return data or cancel
import { customElement, html, state } from "@umbraco-cms/backoffice/external/lit";
import { UmbModalBaseElement } from "@umbraco-cms/backoffice/modal";
import { MemberCustomModalData, MemberCustomModalValue } from "./modal-token";
@customElement('member-custom-modal')
export class MemberCustomModalElement extends
UmbModalBaseElement<MemberCustomModalData, MemberCustomModalValue>
{
constructor() {
super();
}
connectedCallback(): void {
super.connectedCallback();
}
@state()
content: string = '';
#handleConfirm() {
this.modalContext?.submit();
}
#handleCancel() {
this.modalContext?.reject();
}
render() {
return html`
<umb-body-layout headline=${this.data?.headline ?? 'Custom dialog'}>
<uui-box>
<h3>${this.data?.content}</h3>
</uui-box>
<uui-box>
<uui-button
id="submit"
color='positive'
look="primary"
label="Submit"
@click=${this.#handleConfirm}></uui-button>
</uui-box>
<div slot="actions">
<uui-button id="cancel" label="Cancel" @click="${this.#handleCancel}">Cancel</uui-button>
</div>
</umb-body-layout>
`;
}
}
export default MemberCustomModalElement;
modal-token.ts (modal definition)
import { UmbModalToken } from "@umbraco-cms/backoffice/modal";
export interface MemberCustomModalData {
headline: string;
content: string;
}
export interface MemberCustomModalValue {
content: string
}
export const MEMBER_CUSTOM_MODAL = new UmbModalToken<MemberCustomModalData, MemberCustomModalValue>(
"member.custom.modal",
{
modal: {
type: 'sidebar',
size: 'medium'
}
}
);
Register the new manifests
Finally we register the new manifests in our index.ts
import { UmbEntryPointOnInit } from '@umbraco-cms/backoffice/extension-api';
import { ManifestTypes } from '@umbraco-cms/backoffice/extension-registry';
// load up the manifests here.
import { manifests as entityActionManifests } from './actions/entity/manifest.ts';
import { manifests as modalManifests } from './modal/manifest.ts';
const manifests: Array<ManifestTypes> = [
...entityActionManifests,
...modalManifests
];
export const onInit: UmbEntryPointOnInit = (_host, extensionRegistry) => {
// register them here.
extensionRegistry.registerMany(manifests);
};
It took a lot of help and hints from people on the Discord channel, lots of googling and reading various blog posts and Umbraco documentation. I finally came up with the code above, it works, but may not be entirely the correct approach ![]()
This guide walks through building a real Tiptap extension for the Umbraco backoffice — a DateTime inserter that lets editors insert the current date, time, or both into a Rich Text Editor (RTE) field from a toolbar dropdown menu
building a custom collection view for Umbraco 17 that displays documents as beautiful cards with images, using the new extension system and Lit Element web components.
In this post, I'll show you how to build a flexible, on-the-fly watermarking system using SixLabors.ImageSharp.Web that doesn't require modifying your original images.