Is it possible to pass either a custom message or some other metadata as part of the workspace.requestSubmit call from TypeScript in my custom workspace action? I’d like to pass something into my custom event handler so I can process some logic, but the requestSubmit method only appears to accept zero parameters. e.g.
What is it you are trying to achieve in your custom workspace and server-side notification exactly? If you’re fighting against what Umbraco allows you to do then it may be you’re trying to do something the wrong way. It may help if you can provide a bit more context?
The short answer is that requestSubmit() doesn’t support passing data through to server-side notifications the two sides don’t have a direct channel for that.
The approach I’d suggest depends on what you’re actually trying to do, but a clean way to handle this is to make a call to your own Management API endpoint before calling requestSubmit(), store whatever state you need there (e.g. in a scoped/singleton service), and then read it in the notification handler.
Something like this on the TypeScript side:
override async execute() {
// Call your own endpoint first to register intent/metadata
await fetch('/umbraco/api/my-custom/set-context', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ message: 'my custom value' })
});
await this.#workspace?.requestSubmit();
}
And a simple in-memory store on the C# side:
// Registered as Scoped
public class WorkspaceSubmitContext
{
public string? CustomMessage { get; set; }
}
public void Handle(ContentSavedNotification notification)
{
var message = _submitContext.CustomMessage;
// do your thing
}
That said — as Justin asked — it’s worth stepping back and thinking about whether what you’re trying to do needs to go through ContentSavedNotification at all. A lot of custom workspace action logic can live entirely in the TypeScript side (call your own API, do the work there, then submit), which is often simpler and easier to reason about than trying to piggyback data onto Umbraco’s own save pipeline.
What’s the broader use case? There might be a more straightforward path. also id suggest upgrading ur umbraco to latest LTS v17
Thanks for responding. I’ve migrated a site from v13 which has a custom approvals process that was reliant on the sendtopublish permission which has been removed, therefore I’ve had to use the save handler as a fallback. What I want to know is whether the user clicked the save button or my custom “send for approval” button at the point it hits the save handler. For now as a workaround I’ve used a cookie which is read then removed on the server. It’s not an elegant solution but it does the job.
Ah, that makes sense now. The approval workflow context explains it. The cookie approach will work but you’re right that it’s a bit fragile. It’ll get messy with concurrent saves across different tabs, and it relies on the timing of the read/remove.
Given what you’re actually trying to detect (which button triggered the save) I’d lean away from the save pipeline altogether. The cleaner pattern in v16 is to have your “Send for approval” action do its own work via a dedicated Management API endpoint rather than piggybacking on the standard submit. So instead of calling requestSubmit() and then trying to work out intent server-side, your action calls your own endpoint that does the approval logic explicitly, and the normal save button just does a normal save. The intent is then encoded in which endpoint got called, not in side-channel state you have to correlate after the fact.
If you need the content saved as part of the approval action, you can still trigger the save from your endpoint, or have the action save first and call your approval endpoint once that completes. Either way you get a clear ordered sequence rather than two things racing through the same notification.
You could also add your own INotification executed as part of your dedicated ManagementApi controller..
So that you make your own button action emit your new notification handler with cancelation options etc..
But depends on your use case as to whether that is required.