Copied to clipboard

Flag this post as spam?

This post will be reported to the moderators as potential spam to be looked at


  • Benjamin Stigsen 3 posts 93 karma points
    Aug 14, 2024 @ 13:07
    Benjamin Stigsen
    0

    Limit workspace to document type

    Having tried many options while scouring the Umbraco documentation and source code, it has not been clear to me how one would limit where a workspace is shown, based on the template type.

    This is basically what I'm trying to do, it can be seen that the "Status" workspace is only shown on a specific page.

    page without workspace page with the "status" workspace

    Ideally, what I tried to do first should be possible. I have the umbraco-package.json, which contains something like the following:

    {
      "name": "Workspace Extension",
      "extensions": [
        {
          "type": "backofficeEntryPoint",
          "alias": "My.EntryPoint",
          "js": "/App_Plugins/Status/status.js"
        }
      ]
    }
    

    And then I have a workspace.ts which looks like so:

    import { ManifestWorkspaceView, umbExtensionsRegistry } from '@umbraco-cms/backoffice/extension-registry';
    
    const workspaceView: ManifestWorkspaceView = {
        alias: 'My.WorkspaceView',
        name: 'My Workspace View',
        type: 'workspaceView',
        js: () => import('./main.ts'),
        meta: {
            icon: 'icon-bars',
            label: 'Status',
            pathname: '/my-workspace-view'
        },
        conditions: [
            {
                alias: 'Umb.Condition.WorkspaceAlias',
                match: 'Umb.Workspace.Document',
            }
        ],
    }
    
    umbExtensionsRegistry.register(workspaceView);
    export const manifests = [workspaceView];
    

    Now, the code above works, I can change the title and so on, but then comes the fun part. Registering my own condition. To do this I used some code from https://blog.hackmakedo.com/tag/umbraco-14/page/3/, but that didn't really work out. So I used the official Umbraco documentation https://docs.umbraco.com/umbraco-cms/extending/extending-overview/extension-types/condition

    import { UmbControllerBase } from '@umbraco-cms/backoffice/class-api';
    import {
      ManifestCondition,
      UmbConditionConfigBase,
      UmbConditionControllerArguments,
      UmbExtensionCondition,
    } from '@umbraco-cms/backoffice/extension-api';
    // import { UMB_SECTION_CONTEXT } from '@umbraco-cms/backoffice/section';
    
    export type MyConditionConfig = UmbConditionConfigBase & {
      match: string;
    };
    
    export class MyExtensionCondition extends UmbControllerBase implements UmbExtensionCondition {
      config!: MyConditionConfig;
      permitted = false;
    
      constructor(args: UmbConditionControllerArguments<MyConditionConfig>) {
        console.log('calling super with host', args.host);
        super(args.host);
    
        console.log('Hello World!');
        // This condition aproves after 10 seconds
        setTimeout(() => {
          this.permitted = true;
          args.onChange();
        }, 10000);
      }
    }
    
    export const manifest: ManifestCondition = {
      type: 'condition',
      name: 'My Condition',
      alias: 'My.Condition.TenSecondDelay',
      api: MyExtensionCondition,
    };
    

    So my workspace.ts ends up looking like:

    import { ManifestWorkspaceView, umbExtensionsRegistry } from '@umbraco-cms/backoffice/extension-registry';
    import { manifest, MyConditionConfig } from './condition.ts';
    
    const workspaceView: ManifestWorkspaceView = {
        alias: 'My.WorkspaceView',
        name: 'My Workspace View',
        type: 'workspaceView',
        js: () => import('./main.ts'),
        weight: 190,
        meta: {
            icon: 'icon-bars',
            label: 'Status',
            pathname: '/my-workspace-view'
        },
        conditions: [
          {
            alias: 'Umb.Condition.WorkspaceAlias',
            match: 'Umb.Workspace.Document',
          },
          {
            alias: 'My.Condition.TenSecondDelay',
            match: 'test'
          } as MyConditionConfig
        ],
    }
    
    umbExtensionsRegistry.registerMany([workspaceView, manifest]);
    export const manifests = [workspaceView, manifest];
    

    Now the match and cast might not be correct, that doesn't really matter though, because there's a problem in condition.ts it throws an error in the constructor, when calling super().

    export class MyExtensionCondition extends UmbControllerBase implements UmbExtensionCondition {
      // ...
      constructor(args: UmbConditionControllerArguments<MyConditionConfig>) {
        console.log('calling super with host', args.host);
        super(args.host);
    
        console.log('Hello World!');
        // ....
    }
    

    Then it prints:

    calling super with host undefined
    Uncaught (in promise) TypeError: this._host is undefined
    

    And it never reaches the rest of the method.

    Ideally, to limit where the workspace is shown, a simple regular condition should be available. I'd like to use the document template type, or to check whether it's a child of a content node, based on an alias or ID. But my superior, colleagues and I are all at a loss of what to do.

  • Benjamin Stigsen 3 posts 93 karma points
    Aug 21, 2024 @ 13:12
    Benjamin Stigsen
    100

    I had to change a bunch of things, which weren't in accordance with the documentation. I've created a pull request here: https://github.com/umbraco/UmbracoDocs/pull/6361

    Instead of importing UmbControllerBase I had to import UmbConditionBase, along with a bunch of other changes.

    My code ended up looking like the following:

    import {
      ManifestCondition,
      UmbConditionConfigBase,
      UmbConditionControllerArguments,
      UmbExtensionCondition
    } from '@umbraco-cms/backoffice/extension-api';
    import { UmbConditionBase } from '@umbraco-cms/backoffice/extension-registry';
    import { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api';
    
    export type MyConditionConfig = UmbConditionConfigBase & {
      match: string;
    };
    
    export class MyExtensionCondition extends UmbConditionBase<MyConditionConfig> implements UmbExtensionCondition {
      constructor(host: UmbControllerHost, args: UmbConditionControllerArguments<MyConditionConfig>) {
        super(host, args);
    
        // enable extension after 10 seconds
        setTimeout(() => {
          this.permitted = true;
          args.onChange();
        }, 10000);
      }
    }
    
    export const manifest: ManifestCondition = {
     type: 'condition',
     name: 'My Condition',
     alias: 'My.Condition.CustomName',
     api: MyExtensionCondition,
    };
    

    Then my config file ended up looking like so:

    {
     type: 'workspaceAction',
     name: 'example-workspace-action',
     alias: 'My.Example.WorkspaceAction',
     elementName: 'my-workspace-action-element',
     conditions: [
      {
        alias: 'Umb.Condition.SectionAlias',
        match: 'My.Example.Workspace'
      },
      {
        alias: 'My.Condition.CustomName'
      }
     ]
    }
    

    After 10 seconds the workspace becomes visible. So now I am able to create other custom checks, to set the permission for the Workspace to be shown. Such as using match together with a specific document type ID.


    Here is my actual code to make the workspace visible for a certain document type:

    import { UMB_DOCUMENT_WORKSPACE_CONTEXT } from '@umbraco-cms/backoffice/document';
    
    // ...
    
    export type MyConditionDocumentTypeConfig = UmbConditionConfigBase & {
      match: string;
    };
    
    export class MyExtensionCondition extends UmbConditionBase<MyConditionDocumentTypeConfig> implements UmbExtensionCondition {
      constructor(host: UmbControllerHost, args: UmbConditionControllerArguments<MyConditionDocumentTypeConfig>) {
        super(host, args);
    
        this.consumeContext(UMB_DOCUMENT_WORKSPACE_CONTEXT, (context) => {
          // ideally i'd like to use the document type alias instead
          this.permitted = (args.config.match === context.getContentTypeId());
        })
      }
    }
    
    export const manifest: ManifestCondition = {
      type: 'condition',
      name: 'My Condition',
      alias: 'My.Condition.DocumentType',
      api: MyExtensionCondition,
    };
    

    Now the conditions look like so:

    conditions: [
      {
        alias: 'Umb.Condition.WorkspaceAlias',
        match: 'Umb.Workspace.Document',
      },
      {
        alias: 'My.Condition.DocumentType',
        match: '8aa42-3e9a-very-long-id'
      } as MyConditionDocumentTypeConfig
    ],
    
  • Rick Butterfield 3 posts 74 karma points MVP 2x c-trib
    Sep 02, 2024 @ 13:40
    Rick Butterfield
    0

    Hi, there is actually a workspace condition that should let you do exactly this based on the content type alias in Umb.Condition.WorkspaceContentTypeAlias

    You can see an example of it in the backoffice source code.

    EDIT: This has been added since the v14.2 release, which means it'll be in v14.3 at the earliest (Thursday 3rd October release date I think)

  • Benjamin Stigsen 3 posts 93 karma points
    Sep 05, 2024 @ 06:51
    Benjamin Stigsen
    0

    Ah yeah, you had me worried for a second that I missed something really obvious. During my search for this functionality I stumbled upon a GitHub discussion which links to some Discord messages, related to exactly that.

    https://github.com/umbraco/Umbraco-CMS/discussions/16683

    I should probably have saved it and included it in my initial post.

    Looking forward to the new condition though, it would definitely have saved me some time.

Please Sign in or register to post replies

Write your reply to:

Draft