Content Type Workspace: Create condition that checks content type uniques. (#20906)

* Created condition for workspace content type unique.

* Changed import.

* Revert import.

* Updated name in the alias example and also import.

* Update src/Umbraco.Web.UI.Client/examples/entity-content-type-condition/index.ts

Co-authored-by: Mads Rasmussen <madsr@hey.com>

* Update src/Umbraco.Web.UI.Client/examples/entity-content-type-condition/workspace-view-unique.element.ts

Co-authored-by: Mads Rasmussen <madsr@hey.com>

* Moved the manifest definition to the manifest file.

* Changed default export.

* Updated example element to render the real GUID.

* Fixed import.

* Replaced CONTENT_WORKSPACE for PROPERTY_STRUCTURE_WORKSPACE context.

* Moved content type unique condition to the content type folder.

* Fixed import.

* final adjustments

---------

Co-authored-by: Mads Rasmussen <madsr@hey.com>
This commit is contained in:
Engiber Lozada
2025-12-01 11:01:09 +01:00
committed by GitHub
parent 050b37ed1a
commit b40ea0df8c
15 changed files with 261 additions and 67 deletions

View File

@@ -0,0 +1,48 @@
import { UMB_CONTENT_WORKSPACE_CONTEXT } from '@umbraco-cms/backoffice/content';
import { html, customElement, state, css } from '@umbraco-cms/backoffice/external/lit';
import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element';
import { UmbTextStyles } from '@umbraco-cms/backoffice/style';
@customElement('example-content-type-alias-condition-workspace-view')
export class ExampleContentTypeAliasConditionWorkspaceViewElement extends UmbLitElement {
@state()
private _contentTypeAliases: string[] = [];
constructor() {
super();
this.consumeContext(UMB_CONTENT_WORKSPACE_CONTEXT, (context) => {
this.observe(context?.structure.contentTypeAliases, (contentTypeAliases) => {
this._contentTypeAliases = contentTypeAliases || [];
});
});
}
override render() {
return html`<uui-box>
<h3>Content Type Alias Condition Example</h3>
<p>
Content Type ${this._contentTypeAliases.length > 1 ? 'aliases' : 'alias'}:
<strong>${this._contentTypeAliases}</strong>
</p>
</uui-box>`;
}
static override styles = [
UmbTextStyles,
css`
:host {
display: block;
margin: var(--uui-size-layout-2);
}
`,
];
}
export { ExampleContentTypeAliasConditionWorkspaceViewElement as element };
declare global {
interface HTMLElementTagNameMap {
'example-content-type-alias-condition-workspace-view': ExampleContentTypeAliasConditionWorkspaceViewElement;
}
}

View File

@@ -0,0 +1,48 @@
import { UMB_CONTENT_WORKSPACE_CONTEXT } from '@umbraco-cms/backoffice/content';
import { html, customElement, state, css } from '@umbraco-cms/backoffice/external/lit';
import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element';
import { UmbTextStyles } from '@umbraco-cms/backoffice/style';
@customElement('example-content-type-unique-condition-workspace-view')
export class ExampleContentTypeUniqueConditionWorkspaceViewElement extends UmbLitElement {
@state()
private _contentTypeUniques: string[] = [];
constructor() {
super();
this.consumeContext(UMB_CONTENT_WORKSPACE_CONTEXT, (context) => {
this.observe(context?.structure.contentTypeUniques, (contentTypeUniques) => {
this._contentTypeUniques = contentTypeUniques || [];
});
});
}
override render() {
return html`<uui-box>
<h3>Content Type Unique Condition Example</h3>
<p>
Content Type ${this._contentTypeUniques.length > 1 ? 'ids' : 'id'}:
<strong>${this._contentTypeUniques}</strong>
</p>
</uui-box>`;
}
static override styles = [
UmbTextStyles,
css`
:host {
display: block;
margin: var(--uui-size-layout-2);
}
`,
];
}
export { ExampleContentTypeUniqueConditionWorkspaceViewElement as element };
declare global {
interface HTMLElementTagNameMap {
'example-content-type-unique-condition-workspace-view': ExampleContentTypeUniqueConditionWorkspaceViewElement;
}
}

View File

@@ -1,22 +1,43 @@
import { UMB_WORKSPACE_CONTENT_TYPE_ALIAS_CONDITION_ALIAS } from '@umbraco-cms/backoffice/content-type';
import {
UMB_WORKSPACE_CONTENT_TYPE_ALIAS_CONDITION_ALIAS,
UMB_WORKSPACE_CONTENT_TYPE_UNIQUE_CONDITION,
} from '@umbraco-cms/backoffice/content-type';
const workspace: UmbExtensionManifest = {
const workspaceViewAlias: UmbExtensionManifest = {
type: 'workspaceView',
alias: 'Example.WorkspaceView.EntityContentTypeCondition',
name: 'Example Workspace View With Entity Content Type Condition',
element: () => import('./workspace-view.element.js'),
alias: 'Example.WorkspaceView.EntityContentTypeAliasCondition',
name: 'Example Workspace View With Entity Content Type Alias Condition',
element: () => import('./content-type-alias-condition-workspace-view.element.js'),
meta: {
icon: 'icon-bus',
label: 'Conditional',
pathname: 'conditional',
label: 'Conditional (Alias)',
pathname: 'conditional-alias',
},
conditions: [
{
alias: UMB_WORKSPACE_CONTENT_TYPE_ALIAS_CONDITION_ALIAS,
//match : 'blogPost'
//match: 'blogPost',
oneOf: ['blogPost', 'mediaType1'],
},
],
};
export const manifests = [workspace];
const workspaceViewUnique: UmbExtensionManifest = {
type: 'workspaceView',
alias: 'Example.WorkspaceView.EntityContentTypeUniqueCondition',
name: 'Example Workspace View With Content Type Unique Condition',
element: () => import('./content-type-unique-condition-workspace-view.element.js'),
meta: {
icon: 'icon-science',
label: 'Conditional (Unique)',
pathname: 'conditional-unique',
},
conditions: [
{
alias: UMB_WORKSPACE_CONTENT_TYPE_UNIQUE_CONDITION,
oneOf: ['721e85d3-0a2d-4f99-be55-61a5c5ed5c14', '1b88975d-60d0-4b84-809a-4a4deff38a66'], // Example uniques
},
],
};
export const manifests = [workspaceViewAlias, workspaceViewUnique];

View File

@@ -1,19 +0,0 @@
import { html, customElement } from '@umbraco-cms/backoffice/external/lit';
import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element';
@customElement('umb-example-entity-content-type-condition')
export class UmbWorkspaceExampleViewElement extends UmbLitElement {
override render() {
return html`<p>
This is a conditional element that is only shown in workspaces based on it's entities content type.
</p>`;
}
}
export default UmbWorkspaceExampleViewElement;
declare global {
interface HTMLElementTagNameMap {
'umb-example-entity-content-type-condition': UmbWorkspaceExampleViewElement;
}
}

View File

@@ -1,4 +1,2 @@
/**
* Workspace Content Type Alias condition alias
*/
export const UMB_WORKSPACE_CONTENT_TYPE_ALIAS_CONDITION_ALIAS = 'Umb.Condition.WorkspaceContentTypeAlias';
export * from './workspace-content-type-alias/constants.js';
export * from './workspace-content-type-unique/constants.js';

View File

@@ -1,3 +1,4 @@
import { manifest as workspaceContentTypeAliasCondition } from './workspace-content-type-alias.condition.js';
import { manifests as workspaceAliasCondition } from './workspace-content-type-alias/manifests.js';
import { manifests as WorkspaceContentTypeUnique } from './workspace-content-type-unique/manifests.js';
export const manifests: Array<UmbExtensionManifest> = [workspaceContentTypeAliasCondition];
export const manifests: Array<UmbExtensionManifest> = [...workspaceAliasCondition, ...WorkspaceContentTypeUnique];

View File

@@ -1,25 +1,2 @@
import type { UMB_WORKSPACE_CONTENT_TYPE_ALIAS_CONDITION_ALIAS } from './constants.js';
import type { UmbConditionConfigBase } from '@umbraco-cms/backoffice/extension-api';
export type UmbWorkspaceContentTypeAliasConditionConfig = UmbConditionConfigBase<
typeof UMB_WORKSPACE_CONTENT_TYPE_ALIAS_CONDITION_ALIAS
> & {
/**
* Define a content type alias in which workspace this extension should be available
* @example
* Depends on implementation, but i.e. "article", "image", "blockPage"
*/
match?: string;
/**
* Define one or more content type aliases in which workspace this extension should be available
* @example
* ["article", "image", "blockPage"]
*/
oneOf?: Array<string>;
};
declare global {
interface UmbExtensionConditionConfigMap {
umbWorkspaceContentTypeAliasConditionConfig: UmbWorkspaceContentTypeAliasConditionConfig;
}
}
export type * from './workspace-content-type-alias/types.js';
export type * from './workspace-content-type-unique/types.js';

View File

@@ -0,0 +1,4 @@
/**
* Workspace Content Type Alias condition alias
*/
export const UMB_WORKSPACE_CONTENT_TYPE_ALIAS_CONDITION_ALIAS = 'Umb.Condition.WorkspaceContentTypeAlias';

View File

@@ -0,0 +1,11 @@
import { UMB_WORKSPACE_CONTENT_TYPE_ALIAS_CONDITION_ALIAS } from './constants.js';
import { UmbWorkspaceContentTypeAliasCondition } from './workspace-content-type-alias.condition.js';
export const manifests: Array<UmbExtensionManifest> = [
{
type: 'condition',
name: 'Workspace Content Type Alias Condition',
alias: UMB_WORKSPACE_CONTENT_TYPE_ALIAS_CONDITION_ALIAS,
api: UmbWorkspaceContentTypeAliasCondition,
},
];

View File

@@ -0,0 +1,25 @@
import type { UMB_WORKSPACE_CONTENT_TYPE_ALIAS_CONDITION_ALIAS } from './constants.js';
import type { UmbConditionConfigBase } from '@umbraco-cms/backoffice/extension-api';
export type UmbWorkspaceContentTypeAliasConditionConfig = UmbConditionConfigBase<
typeof UMB_WORKSPACE_CONTENT_TYPE_ALIAS_CONDITION_ALIAS
> & {
/**
* Define a content type alias in which workspace this extension should be available
* @example
* Depends on implementation, but i.e. "article", "image", "blockPage"
*/
match?: string;
/**
* Define one or more content type aliases in which workspace this extension should be available
* @example
* ["article", "image", "blockPage"]
*/
oneOf?: Array<string>;
};
declare global {
interface UmbExtensionConditionConfigMap {
umbWorkspaceContentTypeAliasConditionConfig: UmbWorkspaceContentTypeAliasConditionConfig;
}
}

View File

@@ -1,8 +1,8 @@
import { UMB_PROPERTY_STRUCTURE_WORKSPACE_CONTEXT } from '../contexts/index.js';
import type { UmbWorkspaceContentTypeAliasConditionConfig } from './types.js';
import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api';
import type { UmbConditionControllerArguments, UmbExtensionCondition } from '@umbraco-cms/backoffice/extension-api';
import { UmbConditionBase } from '@umbraco-cms/backoffice/extension-registry';
import { UMB_PROPERTY_STRUCTURE_WORKSPACE_CONTEXT } from '../../contexts/property-structure-workspace.context-token.js';
const ObserveSymbol = Symbol();
@@ -44,10 +44,3 @@ export class UmbWorkspaceContentTypeAliasCondition
}
}
}
export const manifest: UmbExtensionManifest = {
type: 'condition',
name: 'Workspace Content Type Alias Condition',
alias: 'Umb.Condition.WorkspaceContentTypeAlias',
api: UmbWorkspaceContentTypeAliasCondition,
};

View File

@@ -0,0 +1,4 @@
/**
* Workspace Content Type Unique condition
*/
export const UMB_WORKSPACE_CONTENT_TYPE_UNIQUE_CONDITION = 'Umb.Condition.WorkspaceContentTypeUnique';

View File

@@ -0,0 +1,11 @@
import { UMB_WORKSPACE_CONTENT_TYPE_UNIQUE_CONDITION } from './constants.js';
import { UmbWorkspaceContentTypeUniqueCondition } from './workspace-content-type-unique.condition.js';
export const manifests: Array<UmbExtensionManifest> = [
{
type: 'condition',
name: 'Workspace Content Type Unique Condition',
alias: UMB_WORKSPACE_CONTENT_TYPE_UNIQUE_CONDITION,
api: UmbWorkspaceContentTypeUniqueCondition,
},
];

View File

@@ -0,0 +1,25 @@
import type { UMB_WORKSPACE_CONTENT_TYPE_UNIQUE_CONDITION } from './constants.js';
import type { UmbConditionConfigBase } from '@umbraco-cms/backoffice/extension-api';
export type UmbWorkspaceContentTypeUniqueConditionConfig = UmbConditionConfigBase<
typeof UMB_WORKSPACE_CONTENT_TYPE_UNIQUE_CONDITION
> & {
/**
* Define a content type unique (GUID) in which workspace this extension should be available
* @example
* Depends on implementation, but i.e. "d59be02f-1df9-4228-aa1e-01917d806cda"
*/
match?: string;
/**
* Define one or more content type unique (GUIDs) in which workspace this extension should be available
* @example
* ["d59be02f-1df9-4228-aa1e-01917d806cda", "42d7572e-1ba1-458d-a765-95b60040c3ac"]
*/
oneOf?: Array<string>;
};
declare global {
interface UmbExtensionConditionConfigMap {
umbWorkspaceContentTypeUniqueConditionConfig: UmbWorkspaceContentTypeUniqueConditionConfig;
}
}

View File

@@ -0,0 +1,47 @@
import type { UmbWorkspaceContentTypeUniqueConditionConfig } from './types.js';
import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api';
import type { UmbConditionControllerArguments, UmbExtensionCondition } from '@umbraco-cms/backoffice/extension-api';
import { UmbConditionBase } from '@umbraco-cms/backoffice/extension-registry';
import { UMB_PROPERTY_STRUCTURE_WORKSPACE_CONTEXT } from '../../contexts/property-structure-workspace.context-token.js';
const ObserveSymbol = Symbol();
/**
* Condition to apply workspace extension based on a content type unique (GUID)
*/
export class UmbWorkspaceContentTypeUniqueCondition
extends UmbConditionBase<UmbWorkspaceContentTypeUniqueConditionConfig>
implements UmbExtensionCondition
{
constructor(
host: UmbControllerHost,
args: UmbConditionControllerArguments<UmbWorkspaceContentTypeUniqueConditionConfig>,
) {
super(host, args);
let permissionCheck: ((contentTypeUniques: string[]) => boolean) | undefined = undefined;
if (this.config.match) {
permissionCheck = (contentTypeUniques: string[]) => contentTypeUniques.includes(this.config.match!);
} else if (this.config.oneOf) {
permissionCheck = (contentTypeUniques: string[]) =>
contentTypeUniques.some((item) => this.config.oneOf!.includes(item));
}
if (permissionCheck !== undefined) {
this.consumeContext(UMB_PROPERTY_STRUCTURE_WORKSPACE_CONTEXT, (context) => {
this.observe(
context?.structure.contentTypeUniques,
(contentTypeUniques) => {
const result = contentTypeUniques ? permissionCheck!(contentTypeUniques) : false;
this.permitted = result;
},
ObserveSymbol,
);
});
} else {
throw new Error(
'Condition `Umb.Condition.WorkspaceContentTypeUnique` could not be initialized properly. Either "match" or "oneOf" must be defined',
);
}
}
}