Condition Config Question -> Now Q's about Stores ...
# package-development
w
Condition Config Question - Custom Config Value not liked in consuming manifest
Trying to create a custom condition that uses some config but I get the error
Object literal may only specify known properties, and 'hasTemplateSet' does not exist in type 'UmbConditionConfigBase<string>'.
https://cdn.discordapp.com/attachments/1226920983437250570/1226921496383979532/image.png?ex=662686af&is=661411af&hm=8a5304adc397a7634e7c33a2617dcd327551ac586ee57fb3eacddafd31f0f647&
My Condition & Its config looks like so
Copy code
typescript
import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api';
import { UmbConditionConfigBase, UmbConditionControllerArguments, UmbExtensionCondition } from "@umbraco-cms/backoffice/extension-api";
import { UMB_DOCUMENT_WORKSPACE_CONTEXT  } from '@umbraco-cms/backoffice/document';
import { UmbConditionBase } from '@umbraco-cms/backoffice/extension-registry';

export type TemplateSetConditionConfig = UmbConditionConfigBase<'AccessibilityReporter.Condition.TemplateSet'> & {
    /**
     * HasTemplateSet
     * Decide if the current document should have a template set or not
     *
     * @example
     * true
     */
    hasTemplateSet: boolean;
};

export class TemplateSetCondition extends UmbConditionBase<TemplateSetConditionConfig> implements UmbExtensionCondition
{
    config: TemplateSetConditionConfig;

    constructor(host: UmbControllerHost, args: UmbConditionControllerArguments<TemplateSetConditionConfig>) {
        super(host, args);
        
        this.consumeContext(UMB_DOCUMENT_WORKSPACE_CONTEXT , (workspaceCtx) => {
            this.observe(workspaceCtx.templateId, (templateId) => {
                console.log('templateId', templateId);

                // No template set === null
                // Tempate set we get a GUID back

                // Config says it passes if template IS set (aka NOT null)
                if(this.config.hasTemplateSet && templateId !== null) {
                    this.permitted = true;
                    return;
                }

                // Config says it passes if template is NOT set (aka IS null)
                if(this.config.hasTemplateSet === false && templateId === null) {
                    this.permitted = true;
                    return;
                }

                this.permitted = false;
            })

        });
    }

}
I've only seen ones from the core use a string with a property called
match
So question is, am I doing something that can't be done, or have I coded something wrong ?!
OK figured something out (if its the right way is another thing) The consuming manifest to use the condition we need to import the Config and cast with
as
Copy code
typescript
conditions: [
    {
        alias: 'Umb.Condition.WorkspaceAlias',
        match: 'Umb.Workspace.Document',
    },
    {
        alias: 'AccessibilityReporter.Condition.TemplateSet',
        hasTemplateSet: true
    } as TemplateSetConditionConfig
],
OK follow up question.... If I make a condition that depends on an API call back to my own Management API controllers to look up a config value from the server (in appSettings for example) Is it OK to just call the controller every time in this condition, or do I need to do something smarter with observables or something and call the API once or something instead ?!
Friendly bump @Jacob Overgaard or @Niels Lyngsø
j
what you are doing with the
as
syntax looks correct, since we dont know the custom properties your condition holds
I would safe-guard against too many calls from conditions since they can be run pretty often, so it depends what your API is serving, maybe you can cache it in a store?
w
Yeh the API will return some config that is basically appSettings
The value could change at runtime, but not sure how I could push from the server
j
You could make a globalContext and query it once and for all there, and then simply consume your context in your condition
your context could even subscribe to a signalr hub to update the value if you wanted
w
oooh interesting....
But I can't put the SignalR hub/endpoint through Swagger AFAIK and not get a generated client for me
j
a globalContext is sort of a hack, though, as the built-in pattern gives you the ability to spin up a repository which holds a store context, and that store should/could listen on the values to update
no yeah, signalr will have to be done outside of swagger
w
OK what is the right way to go about this approach
Otherwise this condition is gonna hammer the Swagger API to get a config value often :S
SignalR -> Store -> Repository -> Condition ?
j
@Warren Buckley Yes, but I would say the Store spins up SignalR and the repository is just static and new'ed up every time it's needed so can't hold state: Condition -> new WarrenRepository() -> this.consumeContext(WARREN_STORE) -> warrenRepository.requestData().asObservable().subscribe(data => this.renderData(data)) Repository (WarrenRepository) : public requestData() { return { asObservable: () => this.store.dataObservable.asObservable() } } Repository (WarrenRepository) -> const { data } = await tryExecuteAndNotify(this, MyResource.getSomeData()) -> store.updateData(data) Store (WARREN_STORE) : public dataObservable = new UmbObjectState() Store (WARREN_STORE) -> new SignalR('/signalr/some_hub')->connect() -> this.dataObservable.setValue(signalRUpdates)
w
I’m sure I’ll have follow up questions as try to give it a go. But thanks Jacob
j
Sure
Notice there are two calls to .setValue -- one for the initial fetch request and one with signalR updates, so the key here is the Observable (UmbObjectState)
w
Don't expect any answers now/weekend. But only got chance to look at this now So with a Store should I use a base class at all, I see there is
UmbStoreBase
There is also
UmbItemStoreBase
But the docs don't depend on anything https://docs.umbraco.com/umbraco-cms/v/14.latest-beta/extending-backoffice/extension-types/store
Do I need to understand RXJs or just heavily lean on your observable API bits ?!
j
the base classes only set up initial data states that fits into the item and details views we are using throughout the workspaces... you can just do your own thing
feel free to use rxjs outright if you want as well
5 Views