>('blocks'),
(blockTypes) => {
this._blockTypes = blockTypes ?? [];
+ this.#itemsManager.setUniques(blockTypes.map((block) => block.contentElementTypeKey));
},
'observeBlockType',
);
@@ -103,7 +129,7 @@ export class UmbPropertyEditorUIBlockGridAreaTypePermissionElement
this._value,
(permission) => permission,
(permission, index) => {
- const showCategoryHeader = this._blockGroups.length && this._blockTypes.length;
+ const showCategoryHeader = this._blockGroups.length > 0 && this._blockTypesWithElementName.length > 0;
return html`
block.contentElementTypeKey,
+ this._blockTypesWithElementName,
+ (block) => block.type.contentElementTypeKey,
(block) =>
html`
- ${block.label}
+ .value=${block.type.contentElementTypeKey}
+ ?selected=${area.elementTypeKey === block.type.contentElementTypeKey}>
+ ${block.name}
`,
);
}
diff --git a/src/Umbraco.Web.UI.Client/src/packages/block/block-grid/property-editors/block-grid-areas-config/property-editor-ui-block-grid-areas-config.element.ts b/src/Umbraco.Web.UI.Client/src/packages/block/block-grid/property-editors/block-grid-areas-config/property-editor-ui-block-grid-areas-config.element.ts
index 3f102682ed..380ea33f83 100644
--- a/src/Umbraco.Web.UI.Client/src/packages/block/block-grid/property-editors/block-grid-areas-config/property-editor-ui-block-grid-areas-config.element.ts
+++ b/src/Umbraco.Web.UI.Client/src/packages/block/block-grid/property-editors/block-grid-areas-config/property-editor-ui-block-grid-areas-config.element.ts
@@ -6,11 +6,7 @@ import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element';
import { html, customElement, property, state, repeat } from '@umbraco-cms/backoffice/external/lit';
import type { UmbPropertyEditorUiElement } from '@umbraco-cms/backoffice/extension-registry';
import { UMB_PROPERTY_DATASET_CONTEXT } from '@umbraco-cms/backoffice/property';
-import {
- UmbPropertyValueChangeEvent,
- type UmbPropertyEditorConfigCollection,
-} from '@umbraco-cms/backoffice/property-editor';
-import { UmbId } from '@umbraco-cms/backoffice/id';
+import type { UmbPropertyEditorConfigCollection } from '@umbraco-cms/backoffice/property-editor';
import { UmbModalRouteRegistrationController } from '@umbraco-cms/backoffice/router';
import { incrementString } from '@umbraco-cms/backoffice/utils';
@@ -61,7 +57,17 @@ export class UmbPropertyEditorUIBlockGridAreasConfigElement
new UmbModalRouteRegistrationController(this, UMB_BLOCK_GRID_AREA_TYPE_WORKSPACE_MODAL)
.addAdditionalPath('block-grid-area-type')
.onSetup(() => {
- return { data: { entityType: 'block-grid-area-type', preset: {} }, modal: { size: 'large' } };
+ if (!this._areaGridColumns) return false;
+ const halfGridColumns = this._areaGridColumns * 0.5;
+ const columnSpan = halfGridColumns === Math.round(halfGridColumns) ? halfGridColumns : this._areaGridColumns;
+
+ return {
+ data: {
+ entityType: 'block-grid-area-type',
+ preset: { columnSpan, alias: this.#generateUniqueAreaAlias('area') },
+ },
+ modal: { size: 'large' },
+ };
})
.observeRouteBuilder((routeBuilder) => {
this._workspacePath = routeBuilder({});
@@ -104,29 +110,6 @@ export class UmbPropertyEditorUIBlockGridAreasConfigElement
return alias;
}
- #addNewArea() {
- if (!this._areaGridColumns) return;
- const halfGridColumns = this._areaGridColumns * 0.5;
- const columnSpan = halfGridColumns === Math.round(halfGridColumns) ? halfGridColumns : this._areaGridColumns;
-
- this._value = [
- ...this._value,
- {
- key: UmbId.new(),
- alias: this.#generateUniqueAreaAlias('area'),
- columnSpan: columnSpan,
- rowSpan: 1,
- minAllowed: 0,
- maxAllowed: undefined,
- specifiedAllowance: [],
- },
- ];
- this.requestUpdate('_value');
- this.dispatchEvent(new UmbPropertyValueChangeEvent());
-
- //TODO: open area edit workspace
- }
-
override render() {
return this._areaGridColumns
? html`${this._styleElement}
@@ -144,7 +127,11 @@ export class UmbPropertyEditorUIBlockGridAreasConfigElement
.key=${area.key}>`,
)}
- `
+ `
: '';
}
}
diff --git a/src/Umbraco.Web.UI.Client/src/packages/block/block-grid/property-editors/block-grid-layout-stylesheet/property-editor-ui-block-grid-layout-stylesheet.element.ts b/src/Umbraco.Web.UI.Client/src/packages/block/block-grid/property-editors/block-grid-layout-stylesheet/property-editor-ui-block-grid-layout-stylesheet.element.ts
index 7d16db32d8..e1103cdf7c 100644
--- a/src/Umbraco.Web.UI.Client/src/packages/block/block-grid/property-editors/block-grid-layout-stylesheet/property-editor-ui-block-grid-layout-stylesheet.element.ts
+++ b/src/Umbraco.Web.UI.Client/src/packages/block/block-grid/property-editors/block-grid-layout-stylesheet/property-editor-ui-block-grid-layout-stylesheet.element.ts
@@ -79,7 +79,9 @@ export class UmbPropertyEditorUIBlockGridLayoutStylesheetElement
.min=${this._limitMin}
.max=${this._limitMax}>
- Link to default layout stylesheet
+ Link to default layout stylesheet
`;
}
diff --git a/src/Umbraco.Web.UI.Client/src/packages/block/block-type/workspace/block-type-workspace.context.ts b/src/Umbraco.Web.UI.Client/src/packages/block/block-type/workspace/block-type-workspace.context.ts
index 7585986cb5..74b2b8bfcb 100644
--- a/src/Umbraco.Web.UI.Client/src/packages/block/block-type/workspace/block-type-workspace.context.ts
+++ b/src/Umbraco.Web.UI.Client/src/packages/block/block-type/workspace/block-type-workspace.context.ts
@@ -112,7 +112,6 @@ export class UmbBlockTypeWorkspaceContext
+ label=${this.localize.term('general_choose')}>
`;
}
diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/content-type/modals/composition-picker/composition-picker-modal.element.ts b/src/Umbraco.Web.UI.Client/src/packages/core/content-type/modals/composition-picker/composition-picker-modal.element.ts
index eb9739e8c0..24da1d9032 100644
--- a/src/Umbraco.Web.UI.Client/src/packages/core/content-type/modals/composition-picker/composition-picker-modal.element.ts
+++ b/src/Umbraco.Web.UI.Client/src/packages/core/content-type/modals/composition-picker/composition-picker-modal.element.ts
@@ -90,17 +90,18 @@ export class UmbCompositionPickerModalElement extends UmbModalBaseElement<
await this.#init;
if (!this.#compositionRepository) return;
- const isElement = this.data?.isElement;
- const currentPropertyAliases = this.data?.currentPropertyAliases;
+ // Notice isElement is not available on all types that can be composed.
+ const isElement = this.data?.isElement ?? undefined;
+ const currentPropertyAliases = this.data?.currentPropertyAliases ?? [];
const { data } = await this.#compositionRepository.availableCompositions({
unique: this.#unique,
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
// TODO: isElement is not available on all types that can be composed.
- isElement: isElement ?? false,
+ isElement: isElement,
currentCompositeUniques: this._selection,
- currentPropertyAliases: currentPropertyAliases ?? [],
+ currentPropertyAliases: currentPropertyAliases,
});
if (!data) return;
@@ -129,11 +130,13 @@ export class UmbCompositionPickerModalElement extends UmbModalBaseElement<
${!this._references.length
- ? html``
+ ? html`
+
+ `
: nothing}
@@ -141,7 +144,8 @@ export class UmbCompositionPickerModalElement extends UmbModalBaseElement<
}
#renderHasReference() {
- return html`
+ return html`
+
This Content Type is used in a composition, and therefore cannot be composed itself.
@@ -154,19 +158,22 @@ export class UmbCompositionPickerModalElement extends UmbModalBaseElement<
${repeat(
this._references,
(item) => item.unique,
- (item) =>
- html` html`
+
+ name=${this.localize.string(item.name)}>
- `,
+
+ `,
)}
- `;
+
+ `;
}
#renderAvailableCompositions() {
if (this._compatibleCompositions) {
- return html`
+ return html`
+
Inherit tabs and properties from an existing Document Type. New tabs will be
added to the current
Document Type or merged if a tab with an identical name exists.
@@ -184,11 +191,14 @@ export class UmbCompositionPickerModalElement extends UmbModalBaseElement<
: nothing}
${this.#renderCompositionsItems(folder.compositions)}`,
)}
- `;
+
+ `;
} else {
- return html`
- There are no Content Types available to use as a composition
- `;
+ return html`
+
+ There are no Content Types available to use as a composition
+
+ `;
}
}
@@ -196,15 +206,16 @@ export class UmbCompositionPickerModalElement extends UmbModalBaseElement<
return repeat(
compositionsList,
(compositions) => compositions.unique,
- (compositions) =>
- html` html`
+ this.#onSelectionAdd(compositions.unique)}
@deselected=${() => this.#onSelectionRemove(compositions.unique)}
?selected=${this._selection.find((unique) => unique === compositions.unique)}>
- `,
+
+ `,
);
}
diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/content-type/structure/content-type-container-structure-helper.class.ts b/src/Umbraco.Web.UI.Client/src/packages/core/content-type/structure/content-type-container-structure-helper.class.ts
index 07b2268a71..32912b50e8 100644
--- a/src/Umbraco.Web.UI.Client/src/packages/core/content-type/structure/content-type-container-structure-helper.class.ts
+++ b/src/Umbraco.Web.UI.Client/src/packages/core/content-type/structure/content-type-container-structure-helper.class.ts
@@ -1,7 +1,7 @@
import type { UmbContentTypeModel, UmbPropertyContainerTypes, UmbPropertyTypeContainerModel } from '../types.js';
import type { UmbContentTypeStructureManager } from './content-type-structure-manager.class.js';
import { UmbControllerBase } from '@umbraco-cms/backoffice/class-api';
-import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api';
+import type { UmbController, UmbControllerHost } from '@umbraco-cms/backoffice/controller-api';
import { UmbArrayState } from '@umbraco-cms/backoffice/observable-api';
/**
@@ -17,6 +17,8 @@ export class UmbContentTypeContainerStructureHelper;
+ #containerObservers: Array = [];
+
// State containing the all containers defined in the data:
#childContainers = new UmbArrayState([], (x) => x.id);
readonly containers = this.#childContainers.asObservable();
@@ -150,30 +152,31 @@ export class UmbContentTypeContainerStructureHelper {
- // We want to remove hasProperties of groups that does not exist anymore.:
- // this.#removeHasPropertiesOfGroup()
this.#hasProperties.setValue([]);
this.#childContainers.setValue([]);
+ this.#containerObservers.forEach((x) => x.destroy());
+ this.#containerObservers = [];
containers.forEach((container) => {
this.#observeHasPropertiesOf(container.id);
- this.observe(
- this.#structure!.containersOfParentId(container.id, this.#childType!),
- (containers) => {
- // get the direct owner containers of this container id:
- this.#ownerChildContainers =
- this.#structure!.getOwnerContainers(this.#childType!, this.#containerId!) ?? [];
- // TODO: Maybe check for dif before setting it? Cause currently we are setting it every time one of the containers change. [NL]
+ this.#containerObservers.push(
+ this.observe(
+ this.#structure!.containersOfParentId(container.id, this.#childType!),
+ (containers) => {
+ // get the direct owner containers of this container id: [NL]
+ this.#ownerChildContainers =
+ this.#structure!.getOwnerContainers(this.#childType!, this.#containerId!) ?? [];
- // Remove existing containers that are not the parent of the new containers:
- this.#childContainers.filter(
- (x) => x.parent?.id !== container.id || containers.some((y) => y.id === x.id),
- );
+ // Remove existing containers that are not the parent of the new containers: [NL]
+ this.#childContainers.filter(
+ (x) => x.parent?.id !== container.id || containers.some((y) => y.id === x.id),
+ );
- this.#childContainers.append(containers);
- },
- '_observeGroupsOf_' + container.id,
+ this.#childContainers.append(containers);
+ },
+ '_observeGroupsOf_' + container.id,
+ ),
);
});
},
diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/content-type/structure/content-type-property-structure-helper.class.ts b/src/Umbraco.Web.UI.Client/src/packages/core/content-type/structure/content-type-property-structure-helper.class.ts
index 55be7cf04d..14753917ba 100644
--- a/src/Umbraco.Web.UI.Client/src/packages/core/content-type/structure/content-type-property-structure-helper.class.ts
+++ b/src/Umbraco.Web.UI.Client/src/packages/core/content-type/structure/content-type-property-structure-helper.class.ts
@@ -21,7 +21,7 @@ export class UmbContentTypePropertyStructureHelper;
- private _containerId?: string | null;
+ #containerId?: string | null;
// State which holds all the properties of the current container, this is a composition of all properties from the containers that matches our target [NL]
#propertyStructure = new UmbArrayState([], (x) => x.id);
@@ -59,12 +59,12 @@ export class UmbContentTypePropertyStructureHelper;
#observeContainers() {
- if (!this.#structure || this._containerId === undefined) return;
+ if (!this.#structure || this.#containerId === undefined) return;
- if (this._containerId === null) {
+ if (this.#containerId === null) {
this.observe(
this.#structure.propertyStructuresOf(null),
(properties) => {
@@ -87,7 +87,7 @@ export class UmbContentTypePropertyStructureHelper {
if (container) {
this._containerName = container.name ?? '';
diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/content-type/structure/content-type-structure-manager.class.ts b/src/Umbraco.Web.UI.Client/src/packages/core/content-type/structure/content-type-structure-manager.class.ts
index 3c811652d4..8fe26a1460 100644
--- a/src/Umbraco.Web.UI.Client/src/packages/core/content-type/structure/content-type-structure-manager.class.ts
+++ b/src/Umbraco.Web.UI.Client/src/packages/core/content-type/structure/content-type-structure-manager.class.ts
@@ -42,10 +42,13 @@ export class UmbContentTypeStructureManager<
readonly ownerContentType = this.#contentTypes.asObservablePart((x) =>
x.find((y) => y.unique === this.#ownerContentTypeUnique),
);
-
- private readonly _contentTypeContainers = this.#contentTypes.asObservablePart((x) =>
- x.flatMap((x) => x.containers ?? []),
+ readonly ownerContentTypeCompositions = this.#contentTypes.asObservablePart(
+ (x) => x.find((y) => y.unique === this.#ownerContentTypeUnique)?.compositions,
);
+
+ readonly #contentTypeContainers = this.#contentTypes.asObservablePart(() => {
+ return this.#contentTypes.getValue().flatMap((x) => x.containers ?? []);
+ });
readonly contentTypeUniques = this.#contentTypes.asObservablePart((x) => x.map((y) => y.unique));
readonly contentTypeAliases = this.#contentTypes.asObservablePart((x) => x.map((y) => y.alias));
@@ -61,12 +64,12 @@ export class UmbContentTypeStructureManager<
super(host);
this.#repository = typeRepository;
- this.observe(this.contentTypes, (contentTypes) => {
- contentTypes.forEach((contentType) => {
- this._loadContentTypeCompositions(contentType);
- });
+ // Observe owner content type compositions, as we only allow one level of compositions at this moment. [NL]
+ // But, we could support more, we would just need to flatMap all compositions and make sure the entries are unique and then base the observation on that. [NL]
+ this.observe(this.ownerContentTypeCompositions, (ownerContentTypeCompositions) => {
+ this._loadContentTypeCompositions(ownerContentTypeCompositions);
});
- this.observe(this._contentTypeContainers, (contentTypeContainers) => {
+ this.observe(this.#contentTypeContainers, (contentTypeContainers) => {
this.#containers.setValue(contentTypeContainers);
});
}
@@ -136,8 +139,24 @@ export class UmbContentTypeStructureManager<
this._observeContentType(data);
}
- private async _loadContentTypeCompositions(contentType: T) {
- contentType.compositions?.forEach((composition) => {
+ private async _loadContentTypeCompositions(ownerContentTypeCompositions: T['compositions'] | undefined) {
+ if (!ownerContentTypeCompositions) {
+ // Owner content type was undefined, so we can not load compositions. But at this point we neither offload existing compositions, this is most likely not a case that needs to be handled.
+ return;
+ }
+
+ const ownerUnique = this.getOwnerContentTypeUnique();
+ // Remove content types that does not exist as compositions anymore:
+ this.#contentTypes.getValue().forEach((x) => {
+ if (
+ x.unique !== ownerUnique &&
+ !ownerContentTypeCompositions.find((comp) => comp.contentType.unique === x.unique)
+ ) {
+ this.#contentTypeObservers.find((y) => y.controllerAlias === 'observeContentType_' + x.unique)?.destroy();
+ this.#contentTypes.removeOne(x.unique);
+ }
+ });
+ ownerContentTypeCompositions.forEach((composition) => {
this._ensureType(composition.contentType.unique);
});
}
@@ -164,23 +183,19 @@ export class UmbContentTypeStructureManager<
// Notice we do not store the content type in the store here, cause it will happen shortly after when the observations gets its first initial callback. [NL]
- // Load inherited and composed types:
- //this._loadContentTypeCompositions(data);// Should not be necessary as this will be done when appended to the contentTypes state. [NL]
-
const ctrl = this.observe(
// Then lets start observation of the content type:
await this.#repository.byUnique(data.unique),
(docType) => {
if (docType) {
- // TODO: Handle if there was changes made to the owner document type in this context. [NL]
- /*
- possible easy solutions could be to notify user wether they want to update(Discard the changes to accept the new ones). [NL]
- */
this.#contentTypes.appendOne(docType);
+ } else {
+ // Remove the content type from the store, if it does not exist anymore.
+ this.#contentTypes.removeOne(data.unique);
}
- // TODO: Do we need to handle the undefined case? [NL]
},
'observeContentType_' + data.unique,
+ // Controller Alias is used to stop observation when no longer needed. [NL]
);
this.#contentTypeObservers.push(ctrl);
diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/content-type/workspace/views/design/content-type-design-editor.element.ts b/src/Umbraco.Web.UI.Client/src/packages/core/content-type/workspace/views/design/content-type-design-editor.element.ts
index 109077161d..34e5c02eeb 100644
--- a/src/Umbraco.Web.UI.Client/src/packages/core/content-type/workspace/views/design/content-type-design-editor.element.ts
+++ b/src/Umbraco.Web.UI.Client/src/packages/core/content-type/workspace/views/design/content-type-design-editor.element.ts
@@ -416,14 +416,16 @@ export class UmbContentTypeDesignEditorElement extends UmbLitElement implements
return html`
${this._compositionRepositoryAlias
- ? html`
-
- ${this.localize.term('contentTypeEditor_compositions')}
- `
+ ? html`
+
+
+ ${this.localize.term('contentTypeEditor_compositions')}
+
+ `
: ''}
diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/content/workspace/views/edit/content-editor-tab.element.ts b/src/Umbraco.Web.UI.Client/src/packages/core/content/workspace/views/edit/content-editor-tab.element.ts
index 1fb52834a2..bb8a5a451f 100644
--- a/src/Umbraco.Web.UI.Client/src/packages/core/content/workspace/views/edit/content-editor-tab.element.ts
+++ b/src/Umbraco.Web.UI.Client/src/packages/core/content/workspace/views/edit/content-editor-tab.element.ts
@@ -63,7 +63,7 @@ export class UmbContentWorkspaceViewEditTabElement extends UmbLitElement {
this._groups,
(group) => group.id,
(group) =>
- html`
+ html`
diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/content/workspace/views/edit/content-editor.element.ts b/src/Umbraco.Web.UI.Client/src/packages/core/content/workspace/views/edit/content-editor.element.ts
index f37657e16d..87db2c05b8 100644
--- a/src/Umbraco.Web.UI.Client/src/packages/core/content/workspace/views/edit/content-editor.element.ts
+++ b/src/Umbraco.Web.UI.Client/src/packages/core/content/workspace/views/edit/content-editor.element.ts
@@ -138,7 +138,7 @@ export class UmbContentWorkspaceViewEditElement extends UmbLitElement implements
(tab) => {
const path = this._routerPath + '/tab/' + encodeFolderName(tab.name || '');
return html`${tab.name}${this.localize.string(tab.name)}`;
},
)}
diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/culture/repository/culture.repository.ts b/src/Umbraco.Web.UI.Client/src/packages/core/culture/repository/culture.repository.ts
index 042e39713a..0d9ec60291 100644
--- a/src/Umbraco.Web.UI.Client/src/packages/core/culture/repository/culture.repository.ts
+++ b/src/Umbraco.Web.UI.Client/src/packages/core/culture/repository/culture.repository.ts
@@ -18,3 +18,5 @@ export class UmbCultureRepository extends UmbControllerBase implements UmbApi {
override destroy() {}
}
+
+export { UmbCultureRepository as api };
diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/culture/repository/manifests.ts b/src/Umbraco.Web.UI.Client/src/packages/core/culture/repository/manifests.ts
index 5e3e1ac52a..2862e1e2ba 100644
--- a/src/Umbraco.Web.UI.Client/src/packages/core/culture/repository/manifests.ts
+++ b/src/Umbraco.Web.UI.Client/src/packages/core/culture/repository/manifests.ts
@@ -1,4 +1,3 @@
-import { UmbCultureRepository } from './culture.repository.js';
import type { ManifestRepository, ManifestTypes } from '@umbraco-cms/backoffice/extension-registry';
export const UMB_CULTURE_REPOSITORY_ALIAS = 'Umb.Repository.Culture';
@@ -7,7 +6,7 @@ const repository: ManifestRepository = {
type: 'repository',
alias: UMB_CULTURE_REPOSITORY_ALIAS,
name: 'Cultures Repository',
- api: UmbCultureRepository,
+ api: () => import('./culture.repository.js'),
};
export const manifests: Array = [repository];
diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/extension-registry/conditions/manifests.ts b/src/Umbraco.Web.UI.Client/src/packages/core/extension-registry/conditions/manifests.ts
index 7b63b02b4e..48b22385bb 100644
--- a/src/Umbraco.Web.UI.Client/src/packages/core/extension-registry/conditions/manifests.ts
+++ b/src/Umbraco.Web.UI.Client/src/packages/core/extension-registry/conditions/manifests.ts
@@ -1,10 +1,12 @@
import type { ManifestTypes } from '../models/index.js';
import { manifest as menuAliasConditionManifest } from './menu-alias.condition.js';
+import { manifest as multipleAppLanguagesConditionManifest } from './multiple-app-languages.condition.js';
import { manifest as sectionAliasConditionManifest } from './section-alias.condition.js';
import { manifest as switchConditionManifest } from './switch.condition.js';
export const manifests: Array = [
menuAliasConditionManifest,
+ multipleAppLanguagesConditionManifest,
sectionAliasConditionManifest,
switchConditionManifest,
];
diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/extension-registry/conditions/menu-alias.condition.ts b/src/Umbraco.Web.UI.Client/src/packages/core/extension-registry/conditions/menu-alias.condition.ts
index f03bcd1173..5d08fb2b73 100644
--- a/src/Umbraco.Web.UI.Client/src/packages/core/extension-registry/conditions/menu-alias.condition.ts
+++ b/src/Umbraco.Web.UI.Client/src/packages/core/extension-registry/conditions/menu-alias.condition.ts
@@ -17,9 +17,13 @@ export class UmbMenuAliasCondition extends UmbConditionBase {
- this.observe(context.alias, (MenuAlias) => {
- this.permitted = MenuAlias === this.config.match;
- });
+ this.observe(
+ context.alias,
+ (MenuAlias) => {
+ this.permitted = MenuAlias === this.config.match;
+ },
+ 'observeAlias',
+ );
});
}
}
diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/extension-registry/conditions/multiple-app-languages.condition.ts b/src/Umbraco.Web.UI.Client/src/packages/core/extension-registry/conditions/multiple-app-languages.condition.ts
new file mode 100644
index 0000000000..361cbbcb38
--- /dev/null
+++ b/src/Umbraco.Web.UI.Client/src/packages/core/extension-registry/conditions/multiple-app-languages.condition.ts
@@ -0,0 +1,37 @@
+import { UmbConditionBase } from './condition-base.controller.js';
+import { UMB_APP_LANGUAGE_CONTEXT } from '@umbraco-cms/backoffice/language';
+import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api';
+import type {
+ ManifestCondition,
+ UmbConditionConfigBase,
+ UmbConditionControllerArguments,
+ UmbExtensionCondition,
+} from '@umbraco-cms/backoffice/extension-api';
+
+export type UmbMultipleAppLanguageConditionConfig = UmbConditionConfigBase;
+
+export class UmbMultipleAppLanguageCondition
+ extends UmbConditionBase
+ implements UmbExtensionCondition
+{
+ constructor(host: UmbControllerHost, args: UmbConditionControllerArguments) {
+ super(host, args);
+
+ this.consumeContext(UMB_APP_LANGUAGE_CONTEXT, (context) => {
+ this.observe(
+ context.moreThanOneLanguage,
+ (moreThanOneLanguage) => {
+ this.permitted = moreThanOneLanguage;
+ },
+ 'observeLanguages',
+ );
+ });
+ }
+}
+
+export const manifest: ManifestCondition = {
+ type: 'condition',
+ name: 'Multiple App Languages Condition',
+ alias: 'Umb.Condition.MultipleAppLanguages',
+ api: UmbMultipleAppLanguageCondition,
+};
diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/extension-registry/conditions/section-alias.condition.ts b/src/Umbraco.Web.UI.Client/src/packages/core/extension-registry/conditions/section-alias.condition.ts
index dc163ed815..b4fd34b93c 100644
--- a/src/Umbraco.Web.UI.Client/src/packages/core/extension-registry/conditions/section-alias.condition.ts
+++ b/src/Umbraco.Web.UI.Client/src/packages/core/extension-registry/conditions/section-alias.condition.ts
@@ -24,9 +24,13 @@ export class UmbSectionAliasCondition
if (permissionCheck !== undefined) {
this.consumeContext(UMB_SECTION_CONTEXT, (context) => {
- this.observe(context.alias, (sectionAlias) => {
- this.permitted = sectionAlias ? permissionCheck!(sectionAlias) : false;
- });
+ this.observe(
+ context.alias,
+ (sectionAlias) => {
+ this.permitted = sectionAlias ? permissionCheck!(sectionAlias) : false;
+ },
+ 'observeAlias',
+ );
});
}
}
diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/extension-registry/conditions/types.ts b/src/Umbraco.Web.UI.Client/src/packages/core/extension-registry/conditions/types.ts
index 0481a6cb5f..f1e92fbe34 100644
--- a/src/Umbraco.Web.UI.Client/src/packages/core/extension-registry/conditions/types.ts
+++ b/src/Umbraco.Web.UI.Client/src/packages/core/extension-registry/conditions/types.ts
@@ -3,6 +3,7 @@ import type { CollectionBulkActionPermissionConditionConfig } from '../../collec
import type { UmbSectionUserPermissionConditionConfig } from '../../section/conditions/index.js';
import type { SectionAliasConditionConfig } from './section-alias.condition.js';
import type { SwitchConditionConfig } from './switch.condition.js';
+import type { UmbMultipleAppLanguageConditionConfig } from './multiple-app-languages.condition.js';
import type {
WorkspaceAliasConditionConfig,
WorkspaceEntityTypeConditionConfig,
@@ -29,8 +30,9 @@ export type ConditionTypes =
| CollectionBulkActionPermissionConditionConfig
| SectionAliasConditionConfig
| SwitchConditionConfig
+ | UmbConditionConfigBase
| UmbDocumentUserPermissionConditionConfig
+ | UmbMultipleAppLanguageConditionConfig
| UmbSectionUserPermissionConditionConfig
| WorkspaceAliasConditionConfig
- | WorkspaceEntityTypeConditionConfig
- | UmbConditionConfigBase;
+ | WorkspaceEntityTypeConditionConfig;
diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/lit-element/directives/focus.lit-directive.ts b/src/Umbraco.Web.UI.Client/src/packages/core/lit-element/directives/focus.lit-directive.ts
index 5d237844ea..f4e7032fd8 100644
--- a/src/Umbraco.Web.UI.Client/src/packages/core/lit-element/directives/focus.lit-directive.ts
+++ b/src/Umbraco.Web.UI.Client/src/packages/core/lit-element/directives/focus.lit-directive.ts
@@ -1,30 +1,76 @@
import { AsyncDirective, directive, nothing, type ElementPart } from '@umbraco-cms/backoffice/external/lit';
+/**
+ *
+ * test if a element has focus
+ * this also returns true if the focused element is a child of the target.
+ * @param current
+ * @param target
+ * @returns bool
+ */
+function hasFocus(current: any, target: HTMLElement): boolean {
+ if (current === target) {
+ return true;
+ }
+ if (current.shadowRoot) {
+ const node = current.shadowRoot.activeElement;
+ if (node) {
+ return hasFocus(node, target);
+ }
+ }
+ return false;
+}
/**
* The `focus` directive sets focus on the given element once its connected to the DOM.
*/
class UmbFocusDirective extends AsyncDirective {
- private _el?: HTMLElement;
+ static #next?: HTMLElement;
+ #el?: HTMLElement;
+ #timeout?: number;
override render() {
return nothing;
}
override update(part: ElementPart) {
- if (this._el !== part.element) {
- // This does feel wrong that we need to wait one render. [NL]
- // Because even if our elements focus method is implemented so it can be called initially, my research shows that calling the focus method at this point is too early, thought the element is connected to the DOM and the focus method is available. [NL]
- // This smells a bit like the DOMPart of which the directive is in is not connected to the main DOM yet, and therefor cant receive focus. [NL]
- // Which is why we need to await one render: [NL]
- requestAnimationFrame(() => {
- (this._el = part.element as HTMLElement).focus();
- });
+ if (this.#el !== part.element) {
+ UmbFocusDirective.#next = this.#el = part.element as HTMLElement;
+ this.#setFocus();
}
return nothing;
}
+ /**
+ * This method tries to set focus, if it did not succeed, it will try again.
+ * It always tests against the latest element, because the directive can be used multiple times in the same render.
+ * This is NOT needed because the elements focus method isn't ready to be called, but due to something with rendering of the DOM.
+ * But I'm not completely sure at this movement why the browser does not accept the focus call.
+ * But I have tested that everything is in place for it to be good, so something else must have an effect,
+ * setting the focus somewhere else, maybe a re-appending of some sort?
+ * cause Lit does not re-render the element but also notice reconnect callback on the directive is not triggered either. [NL]
+ */
+ #setFocus = () => {
+ // Make sure we clear the timeout, so we don't get multiple timeouts running.
+ if (this.#timeout) {
+ clearTimeout(this.#timeout);
+ this.#timeout = undefined;
+ }
+ // If this is the next element to focus, then try to focus it.
+ if (this.#el && this.#el === UmbFocusDirective.#next) {
+ this.#el.focus();
+ if (hasFocus(document.activeElement, this.#el) === false) {
+ this.#timeout = setTimeout(this.#setFocus, 100) as unknown as number;
+ } else {
+ UmbFocusDirective.#next = undefined;
+ }
+ }
+ };
+
override disconnected() {
- this._el = undefined;
+ if (this.#el === UmbFocusDirective.#next) {
+ UmbFocusDirective.#next = undefined;
+ }
+ this.#el = undefined;
}
//override reconnected() {}
diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/localization/registry/localization.registry.ts b/src/Umbraco.Web.UI.Client/src/packages/core/localization/registry/localization.registry.ts
index f2b5e98a4e..cc755ebd24 100644
--- a/src/Umbraco.Web.UI.Client/src/packages/core/localization/registry/localization.registry.ts
+++ b/src/Umbraco.Web.UI.Client/src/packages/core/localization/registry/localization.registry.ts
@@ -1,8 +1,9 @@
-import type {
- UmbLocalizationSetBase,
- UmbLocalizationDictionary,
- UmbLocalizationFlatDictionary,
-} from '@umbraco-cms/backoffice/localization-api';
+import {
+ type UmbLocalizationSetBase,
+ type UmbLocalizationDictionary,
+ type UmbLocalizationFlatDictionary,
+ UMB_DEFAULT_LOCALIZATION_CULTURE
+} from "@umbraco-cms/backoffice/localization-api";
import { umbLocalizationManager } from '@umbraco-cms/backoffice/localization-api';
import type { ManifestLocalization, UmbBackofficeExtensionRegistry } from '@umbraco-cms/backoffice/extension-registry';
import { umbExtensionsRegistry } from '@umbraco-cms/backoffice/extension-registry';
@@ -21,7 +22,7 @@ function addOrUpdateDictionary(
}
export class UmbLocalizationRegistry {
- #currentLanguage = new UmbStringState(document.documentElement.lang ?? 'en-us');
+ #currentLanguage = new UmbStringState(document.documentElement.lang !== '' ? document.documentElement.lang : UMB_DEFAULT_LOCALIZATION_CULTURE);
readonly currentLanguage = this.#currentLanguage.asObservable();
#loadedExtAliases: Array = [];
diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/modal/common/embedded-media/repository/manifests.ts b/src/Umbraco.Web.UI.Client/src/packages/core/modal/common/embedded-media/repository/manifests.ts
index 580f3e1026..dbce95b73d 100644
--- a/src/Umbraco.Web.UI.Client/src/packages/core/modal/common/embedded-media/repository/manifests.ts
+++ b/src/Umbraco.Web.UI.Client/src/packages/core/modal/common/embedded-media/repository/manifests.ts
@@ -1,4 +1,3 @@
-import { UmbOEmbedRepository } from './oembed.repository.js';
import type { ManifestRepository, ManifestTypes } from '@umbraco-cms/backoffice/extension-registry';
export const UMB_OEMBED_REPOSITORY_ALIAS = 'Umb.Repository.OEmbed';
@@ -7,7 +6,7 @@ const repository: ManifestRepository = {
type: 'repository',
alias: UMB_OEMBED_REPOSITORY_ALIAS,
name: 'OEmbed Repository',
- api: UmbOEmbedRepository,
+ api: () => import('./oembed.repository.js'),
};
export const manifests: Array = [repository];
diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/modal/common/embedded-media/repository/oembed.repository.ts b/src/Umbraco.Web.UI.Client/src/packages/core/modal/common/embedded-media/repository/oembed.repository.ts
index 344c067453..983232efe2 100644
--- a/src/Umbraco.Web.UI.Client/src/packages/core/modal/common/embedded-media/repository/oembed.repository.ts
+++ b/src/Umbraco.Web.UI.Client/src/packages/core/modal/common/embedded-media/repository/oembed.repository.ts
@@ -18,3 +18,5 @@ export class UmbOEmbedRepository extends UmbControllerBase implements UmbApi {
return { error };
}
}
+
+export { UmbOEmbedRepository as api };
diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/modal/common/item-picker/item-picker-modal.element.ts b/src/Umbraco.Web.UI.Client/src/packages/core/modal/common/item-picker/item-picker-modal.element.ts
index 20f8747a4f..0f5fa9b803 100644
--- a/src/Umbraco.Web.UI.Client/src/packages/core/modal/common/item-picker/item-picker-modal.element.ts
+++ b/src/Umbraco.Web.UI.Client/src/packages/core/modal/common/item-picker/item-picker-modal.element.ts
@@ -51,7 +51,7 @@ export class UmbItemPickerModalElement extends UmbModalBaseElement
+
item.value,
(item) => html`
this.#submit(item)}>
diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/workspace/components/workspace-split-view/workspace-split-view-variant-selector.element.ts b/src/Umbraco.Web.UI.Client/src/packages/core/workspace/components/workspace-split-view/workspace-split-view-variant-selector.element.ts
index 2fd9078243..c4bfbf0cab 100644
--- a/src/Umbraco.Web.UI.Client/src/packages/core/workspace/components/workspace-split-view/workspace-split-view-variant-selector.element.ts
+++ b/src/Umbraco.Web.UI.Client/src/packages/core/workspace/components/workspace-split-view/workspace-split-view-variant-selector.element.ts
@@ -212,7 +212,7 @@ export class UmbWorkspaceSplitViewVariantSelectorElement extends UmbLitElement {
return html`
`,
)
- : html`No configuration
`;
+ : html`There is no configuration for this property editor.`;
}
static override styles = [UmbTextStyles];
diff --git a/src/Umbraco.Web.UI.Client/src/packages/data-type/workspace/data-type-workspace.context.ts b/src/Umbraco.Web.UI.Client/src/packages/data-type/workspace/data-type-workspace.context.ts
index 4442f73ec6..49aa80140f 100644
--- a/src/Umbraco.Web.UI.Client/src/packages/data-type/workspace/data-type-workspace.context.ts
+++ b/src/Umbraco.Web.UI.Client/src/packages/data-type/workspace/data-type-workspace.context.ts
@@ -30,6 +30,24 @@ import {
} from '@umbraco-cms/backoffice/entity-action';
type EntityType = UmbDataTypeDetailModel;
+
+/**
+ * @class UmbDataTypeWorkspaceContext
+ * @description - Context for handling data type workspace
+ * There is two overall code flows to be aware about:
+ *
+ * propertyEditorUiAlias is observed
+ * loads propertyEditorUi manifest
+ * then the propertyEditorSchemaAlias is set to what the UI is configured for.
+ *
+ * propertyEditorSchemaAlias is observed
+ * loads the propertyEditorSchema manifest
+ * if no UI is defined then the propertyEditorSchema manifest default ui is set for the propertyEditorUiAlias.
+ *
+ * This supports two cases:
+ * - when editing an existing data type that only has a schema alias set, then it gets the UI set.
+ * - a new property editor ui is picked for a data-type, uses the data-type configuration to set the schema, if such is configured for the Property Editor UI. (The user picks the UI via the UI, the schema comes from the UI that the user picked, we store both on the data-type)
+ */
export class UmbDataTypeWorkspaceContext
extends UmbSubmittableWorkspaceContextBase
implements UmbInvariantDatasetWorkspaceContext, UmbRoutableWorkspaceContext
@@ -72,8 +90,6 @@ export class UmbDataTypeWorkspaceContext
#settingsDefaultData?: Array;
- #propertyEditorUISettingsSchemaAlias?: string;
-
#propertyEditorUiIcon = new UmbStringState(null);
readonly propertyEditorUiIcon = this.#propertyEditorUiIcon.asObservable();
@@ -82,6 +98,8 @@ export class UmbDataTypeWorkspaceContext
constructor(host: UmbControllerHost) {
super(host, 'Umb.Workspace.DataType');
+
+ this.#observePropertyEditorSchemaAlias();
this.#observePropertyEditorUIAlias();
this.routes.setRoutes([
@@ -121,7 +139,7 @@ export class UmbDataTypeWorkspaceContext
this.#propertyEditorUISettingsDefaultData = [];
this.#settingsDefaultData = undefined;
- this._mergeConfigProperties();
+ this.#mergeConfigProperties();
}
// Hold the last set property editor ui alias, so we know when it changes, so we can reset values. [NL]
@@ -131,30 +149,13 @@ export class UmbDataTypeWorkspaceContext
this.observe(
this.propertyEditorUiAlias,
async (propertyEditorUiAlias) => {
- const previousPropertyEditorUIAlias = this.#lastPropertyEditorUIAlias;
- this.#lastPropertyEditorUIAlias = propertyEditorUiAlias;
+ this.#propertyEditorUISettingsProperties = [];
+ this.#propertyEditorUISettingsDefaultData = [];
+
// we only want to react on the change if the alias is set or null. When it is undefined something is still loading
if (propertyEditorUiAlias === undefined) return;
- // if the property editor ui alias is not set, we use the default alias from the schema
- if (propertyEditorUiAlias === null) {
- await this.#observePropertyEditorSchemaAlias();
- if (this.#propertyEditorSchemaConfigDefaultUIAlias !== null) {
- this.setPropertyEditorUiAlias(this.#propertyEditorSchemaConfigDefaultUIAlias);
- }
- } else {
- await this.#setPropertyEditorUIConfig(propertyEditorUiAlias);
- this.setPropertyEditorSchemaAlias(this.#propertyEditorUISettingsSchemaAlias!);
- await this.#observePropertyEditorSchemaAlias();
- }
-
- if (
- this.getIsNew() ||
- (previousPropertyEditorUIAlias && previousPropertyEditorUIAlias !== propertyEditorUiAlias)
- ) {
- this.#transferConfigDefaultData();
- }
- this._mergeConfigProperties();
+ this.#observePropertyEditorUIManifest(propertyEditorUiAlias);
},
'editorUiAlias',
);
@@ -164,13 +165,19 @@ export class UmbDataTypeWorkspaceContext
return this.observe(
this.propertyEditorSchemaAlias,
(propertyEditorSchemaAlias) => {
- this.#setPropertyEditorSchemaConfig(propertyEditorSchemaAlias);
+ this.#propertyEditorSchemaSettingsProperties = [];
+ this.#propertyEditorSchemaSettingsDefaultData = [];
+ this.#observePropertyEditorSchemaManifest(propertyEditorSchemaAlias);
},
'schemaAlias',
- ).asPromise();
+ );
}
- #setPropertyEditorSchemaConfig(propertyEditorSchemaAlias?: string) {
+ #observePropertyEditorSchemaManifest(propertyEditorSchemaAlias?: string) {
+ if (!propertyEditorSchemaAlias) {
+ this.removeUmbControllerByAlias('schema');
+ return;
+ }
this.observe(
propertyEditorSchemaAlias
? umbExtensionsRegistry.byTypeAndAlias('propertyEditorSchema', propertyEditorSchemaAlias)
@@ -183,36 +190,56 @@ export class UmbDataTypeWorkspaceContext
}));
this.#propertyEditorSchemaSettingsDefaultData = manifest?.meta.settings?.defaultData || [];
this.#propertyEditorSchemaConfigDefaultUIAlias = manifest?.meta.defaultPropertyEditorUiAlias || null;
+ if (this.#propertyEditorSchemaConfigDefaultUIAlias && this.getPropertyEditorUiAlias() === null) {
+ // Fallback to the default property editor ui for this property editor schema.
+ this.setPropertyEditorUiAlias(this.#propertyEditorSchemaConfigDefaultUIAlias);
+ }
+ this.#mergeConfigProperties();
},
'schema',
);
}
- #setPropertyEditorUIConfig(propertyEditorUIAlias: string) {
- return this.observe(
+ #observePropertyEditorUIManifest(propertyEditorUIAlias: string | null) {
+ if (!propertyEditorUIAlias) {
+ this.removeUmbControllerByAlias('editorUi');
+ return;
+ }
+ this.observe(
umbExtensionsRegistry.byTypeAndAlias('propertyEditorUi', propertyEditorUIAlias),
(manifest) => {
this.#propertyEditorUiIcon.setValue(manifest?.meta.icon || null);
this.#propertyEditorUiName.setValue(manifest?.name || null);
- this.#propertyEditorUISettingsSchemaAlias = manifest?.meta.propertyEditorSchemaAlias;
// Maps properties to have a weight, so they can be sorted, notice UI properties have a +1000 weight compared to schema properties.
this.#propertyEditorUISettingsProperties = (manifest?.meta.settings?.properties ?? []).map((x, i) => ({
...x,
weight: x.weight ?? 1000 + i,
}));
this.#propertyEditorUISettingsDefaultData = manifest?.meta.settings?.defaultData || [];
+ this.setPropertyEditorSchemaAlias(manifest?.meta.propertyEditorSchemaAlias);
+ this.#mergeConfigProperties();
},
'editorUi',
- ).asPromise();
+ );
}
- private _mergeConfigProperties() {
+ #mergeConfigProperties() {
if (this.#propertyEditorSchemaSettingsProperties && this.#propertyEditorUISettingsProperties) {
// Reset the value to this array, and then afterwards append:
this.#properties.setValue(this.#propertyEditorSchemaSettingsProperties);
// Append the UI settings properties to the schema properties, so they can override the schema properties:
this.#properties.append(this.#propertyEditorUISettingsProperties);
+
+ // If new or if the alias was changed then set default values. This 'complexity' to prevent setting default data when initialized [NL]
+ const previousPropertyEditorUIAlias = this.#lastPropertyEditorUIAlias;
+ this.#lastPropertyEditorUIAlias = this.getPropertyEditorUiAlias();
+ if (
+ this.getIsNew() ||
+ (previousPropertyEditorUIAlias && previousPropertyEditorUIAlias !== this.#lastPropertyEditorUIAlias)
+ ) {
+ this.#transferConfigDefaultData();
+ }
}
}
@@ -301,9 +328,15 @@ export class UmbDataTypeWorkspaceContext
this.#currentData.update({ name });
}
+ getPropertyEditorSchemaAlias() {
+ return this.#currentData.getValue()?.editorAlias;
+ }
setPropertyEditorSchemaAlias(alias?: string) {
this.#currentData.update({ editorAlias: alias });
}
+ getPropertyEditorUiAlias() {
+ return this.#currentData.getValue()?.editorUiAlias;
+ }
setPropertyEditorUiAlias(alias?: string) {
this.#currentData.update({ editorUiAlias: alias });
}
diff --git a/src/Umbraco.Web.UI.Client/src/packages/data-type/workspace/views/info/data-type-workspace-view-info-reference.element.ts b/src/Umbraco.Web.UI.Client/src/packages/data-type/workspace/views/info/data-type-workspace-view-info-reference.element.ts
index 310b633c3d..29f19e05fd 100644
--- a/src/Umbraco.Web.UI.Client/src/packages/data-type/workspace/views/info/data-type-workspace-view-info-reference.element.ts
+++ b/src/Umbraco.Web.UI.Client/src/packages/data-type/workspace/views/info/data-type-workspace-view-info-reference.element.ts
@@ -87,7 +87,9 @@ export class UmbDataTypeWorkspaceViewInfoReferenceElement extends UmbLitElement
(item) => html`
-
+
diff --git a/src/Umbraco.Web.UI.Client/src/packages/documents/document-types/components/input-document-type/input-document-type.element.ts b/src/Umbraco.Web.UI.Client/src/packages/documents/document-types/components/input-document-type/input-document-type.element.ts
index ce3702cb23..a0a7d6a13c 100644
--- a/src/Umbraco.Web.UI.Client/src/packages/documents/document-types/components/input-document-type/input-document-type.element.ts
+++ b/src/Umbraco.Web.UI.Client/src/packages/documents/document-types/components/input-document-type/input-document-type.element.ts
@@ -204,7 +204,7 @@ export class UmbInputDocumentTypeElement extends UmbFormControlMixin
+
${this.#renderIcon(item)}
diff --git a/src/Umbraco.Web.UI.Client/src/packages/documents/document-types/property-editors/document-type-picker/property-editor-ui-document-type-picker.element.ts b/src/Umbraco.Web.UI.Client/src/packages/documents/document-types/property-editors/document-type-picker/property-editor-ui-document-type-picker.element.ts
index b73d7b9998..e1604bb787 100644
--- a/src/Umbraco.Web.UI.Client/src/packages/documents/document-types/property-editors/document-type-picker/property-editor-ui-document-type-picker.element.ts
+++ b/src/Umbraco.Web.UI.Client/src/packages/documents/document-types/property-editors/document-type-picker/property-editor-ui-document-type-picker.element.ts
@@ -45,7 +45,7 @@ export class UmbPropertyEditorUIDocumentTypePickerElement extends UmbLitElement
.min=${this.min}
.max=${this.max}
.value=${this.value}
- ?elementTypesOnly=${this.onlyElementTypes}
+ .elementTypesOnly=${this.onlyElementTypes ?? false}
?showOpenButton=${this.showOpenButton}
@change=${this.#onChange}>
diff --git a/src/Umbraco.Web.UI.Client/src/packages/documents/document-types/repository/composition/index.ts b/src/Umbraco.Web.UI.Client/src/packages/documents/document-types/repository/composition/index.ts
index 99c179ec94..8a9f7eae16 100644
--- a/src/Umbraco.Web.UI.Client/src/packages/documents/document-types/repository/composition/index.ts
+++ b/src/Umbraco.Web.UI.Client/src/packages/documents/document-types/repository/composition/index.ts
@@ -1,2 +1 @@
-export { UmbDocumentTypeCompositionRepository } from './document-type-composition.repository.js';
export { UMB_DOCUMENT_TYPE_COMPOSITION_REPOSITORY_ALIAS } from './manifests.js';
diff --git a/src/Umbraco.Web.UI.Client/src/packages/documents/document-types/repository/composition/manifests.ts b/src/Umbraco.Web.UI.Client/src/packages/documents/document-types/repository/composition/manifests.ts
index 1732701de6..b01f3b0be9 100644
--- a/src/Umbraco.Web.UI.Client/src/packages/documents/document-types/repository/composition/manifests.ts
+++ b/src/Umbraco.Web.UI.Client/src/packages/documents/document-types/repository/composition/manifests.ts
@@ -2,11 +2,11 @@ import type { ManifestRepository, ManifestTypes } from '@umbraco-cms/backoffice/
export const UMB_DOCUMENT_TYPE_COMPOSITION_REPOSITORY_ALIAS = 'Umb.Repository.DocumentType.Composition';
-const queryRepository: ManifestRepository = {
+const compositionRepository: ManifestRepository = {
type: 'repository',
alias: UMB_DOCUMENT_TYPE_COMPOSITION_REPOSITORY_ALIAS,
name: 'Document Type Composition Repository',
api: () => import('./document-type-composition.repository.js'),
};
-export const manifests: Array = [queryRepository];
+export const manifests: Array = [compositionRepository];
diff --git a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/entity-actions/create/document-create-options-modal.element.ts b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/entity-actions/create/document-create-options-modal.element.ts
index c6e010236a..3f6751d76b 100644
--- a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/entity-actions/create/document-create-options-modal.element.ts
+++ b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/entity-actions/create/document-create-options-modal.element.ts
@@ -133,60 +133,65 @@ export class UmbDocumentCreateOptionsModalElement extends UmbModalBaseElement<
}
#renderDocumentTypes() {
- return html`
- ${when(
- this._allowedDocumentTypes.length === 0,
- () => html`
-
- There are no allowed Document Types available for creating content here. You must enable these in
- Document Types within the Settings section, by editing the
- Allowed child node types under Permissions.
-
- this._rejectModal()}
- href=${`/section/settings/workspace/document-type/edit/${this.data?.documentType?.unique}/view/structure`}
- label=${this.localize.term('create_noDocumentTypesEditPermissions')}>
- `,
- () =>
- repeat(
- this._allowedDocumentTypes,
- (documentType) => documentType.unique,
- (documentType) =>
- html` this.#onSelectDocumentType(documentType.unique)}>
-
- `,
- ),
- )}
- `;
+ return html`
+
+ ${when(
+ this._allowedDocumentTypes.length === 0,
+ () => html`
+
+ There are no allowed Document Types available for creating content here. You must enable these in
+ Document Types within the Settings section, by editing the
+ Allowed child node types under Permissions.
+
+ this._rejectModal()}>
+ `,
+ () =>
+ repeat(
+ this._allowedDocumentTypes,
+ (documentType) => documentType.unique,
+ (documentType) => html`
+ this.#onSelectDocumentType(documentType.unique)}>
+
+
+ `,
+ ),
+ )}
+
+ `;
}
#renderBlueprints() {
- return html`
- this.#onNavigate(this.#documentTypeUnique)}>
-
-
- ${repeat(
- this._availableBlueprints,
- (blueprint) => blueprint.unique,
- (blueprint) =>
- html` this.#onNavigate(this.#documentTypeUnique, blueprint.unique)}>
-
- `,
- )} `;
+ return html`
+
+ this.#onNavigate(this.#documentTypeUnique)}>
+
+
+ ${repeat(
+ this._availableBlueprints,
+ (blueprint) => blueprint.unique,
+ (blueprint) =>
+ html` this.#onNavigate(this.#documentTypeUnique, blueprint.unique)}>
+
+ `,
+ )}
+
+ `;
}
static override styles = [
diff --git a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/workspace/views/info/document-workspace-view-info.element.ts b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/workspace/views/info/document-workspace-view-info.element.ts
index 0a650e22e4..13344c29a1 100644
--- a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/workspace/views/info/document-workspace-view-info.element.ts
+++ b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/workspace/views/info/document-workspace-view-info.element.ts
@@ -252,7 +252,7 @@ export class UmbDocumentWorkspaceViewInfoElement extends UmbLitElement {
+ name=${ifDefined(this.localize.string(this._documentTypeName ?? ''))}>
diff --git a/src/Umbraco.Web.UI.Client/src/packages/health-check/views/health-check-group-box-overview.element.ts b/src/Umbraco.Web.UI.Client/src/packages/health-check/views/health-check-group-box-overview.element.ts
index 42d8679729..3dadc4cee6 100644
--- a/src/Umbraco.Web.UI.Client/src/packages/health-check/views/health-check-group-box-overview.element.ts
+++ b/src/Umbraco.Web.UI.Client/src/packages/health-check/views/health-check-group-box-overview.element.ts
@@ -64,25 +64,25 @@ export class UmbHealthCheckGroupBoxOverviewElement extends UmbLitElement {
_renderCheckResults(resultObject: any) {
return html`${resultObject.success > 0
? html`
-
+
${resultObject.success}
`
: nothing}
${resultObject.warning > 0
? html`
-
+
${resultObject.warning}
`
: nothing}
${resultObject.error > 0
? html`
-
+
${resultObject.error}
`
: nothing}
${resultObject.info > 0
? html`
-
+
${resultObject.info}
`
: nothing} `;
diff --git a/src/Umbraco.Web.UI.Client/src/packages/health-check/views/health-check-group.element.ts b/src/Umbraco.Web.UI.Client/src/packages/health-check/views/health-check-group.element.ts
index 787edc26c6..084d41a1a9 100644
--- a/src/Umbraco.Web.UI.Client/src/packages/health-check/views/health-check-group.element.ts
+++ b/src/Umbraco.Web.UI.Client/src/packages/health-check/views/health-check-group.element.ts
@@ -129,7 +129,7 @@ export class UmbDashboardHealthCheckGroupElement extends UmbLitElement {
case StatusResultTypeModel.SUCCESS:
return html``;
case StatusResultTypeModel.WARNING:
- return html``;
+ return html``;
case StatusResultTypeModel.ERROR:
return html``;
case StatusResultTypeModel.INFO:
diff --git a/src/Umbraco.Web.UI.Client/src/packages/language/app-language-select/manifests.ts b/src/Umbraco.Web.UI.Client/src/packages/language/app-language-select/manifests.ts
index b29b0dde84..e67c16493d 100644
--- a/src/Umbraco.Web.UI.Client/src/packages/language/app-language-select/manifests.ts
+++ b/src/Umbraco.Web.UI.Client/src/packages/language/app-language-select/manifests.ts
@@ -12,6 +12,9 @@ const entityActions: Array = [
alias: 'Umb.Condition.SectionAlias',
match: 'Umb.Section.Content',
},
+ {
+ alias: 'Umb.Condition.MultipleAppLanguages',
+ },
],
},
];
diff --git a/src/Umbraco.Web.UI.Client/src/packages/language/global-contexts/app-language.context.ts b/src/Umbraco.Web.UI.Client/src/packages/language/global-contexts/app-language.context.ts
index 1383eee7c8..6a0d4b7d8b 100644
--- a/src/Umbraco.Web.UI.Client/src/packages/language/global-contexts/app-language.context.ts
+++ b/src/Umbraco.Web.UI.Client/src/packages/language/global-contexts/app-language.context.ts
@@ -12,6 +12,7 @@ import { UMB_AUTH_CONTEXT } from '@umbraco-cms/backoffice/auth';
export class UmbAppLanguageContext extends UmbContextBase implements UmbApi {
#languageCollectionRepository: UmbLanguageCollectionRepository;
#languages = new UmbArrayState([], (x) => x.unique);
+ moreThanOneLanguage = this.#languages.asObservablePart((x) => x.length > 1);
#appLanguage = new UmbObjectState(undefined);
appLanguage = this.#appLanguage.asObservable();
diff --git a/src/Umbraco.Web.UI.Client/src/packages/language/workspace/language/constants.ts b/src/Umbraco.Web.UI.Client/src/packages/language/workspace/language/constants.ts
new file mode 100644
index 0000000000..43f9eb4861
--- /dev/null
+++ b/src/Umbraco.Web.UI.Client/src/packages/language/workspace/language/constants.ts
@@ -0,0 +1 @@
+export const UMB_LANGUAGE_WORKSPACE_ALIAS = 'Umb.Workspace.Language';
diff --git a/src/Umbraco.Web.UI.Client/src/packages/language/workspace/language/language-workspace.context.ts b/src/Umbraco.Web.UI.Client/src/packages/language/workspace/language/language-workspace.context.ts
index 87d2816bd5..934b5700d8 100644
--- a/src/Umbraco.Web.UI.Client/src/packages/language/workspace/language/language-workspace.context.ts
+++ b/src/Umbraco.Web.UI.Client/src/packages/language/workspace/language/language-workspace.context.ts
@@ -1,6 +1,7 @@
import { UmbLanguageDetailRepository } from '../../repository/index.js';
import type { UmbLanguageDetailModel } from '../../types.js';
import { UmbLanguageWorkspaceEditorElement } from './language-workspace-editor.element.js';
+import { UMB_LANGUAGE_WORKSPACE_ALIAS } from './constants.js';
import {
type UmbSubmittableWorkspaceContext,
UmbSubmittableWorkspaceContextBase,
@@ -27,7 +28,7 @@ export class UmbLanguageWorkspaceContext
readonly validationErrors = this.#validationErrors.asObservable();
constructor(host: UmbControllerHost) {
- super(host, 'Umb.Workspace.Language');
+ super(host, UMB_LANGUAGE_WORKSPACE_ALIAS);
this.routes.setRoutes([
{
diff --git a/src/Umbraco.Web.UI.Client/src/packages/language/workspace/language/manifests.ts b/src/Umbraco.Web.UI.Client/src/packages/language/workspace/language/manifests.ts
index 6abbf9bf69..ce98f96aaa 100644
--- a/src/Umbraco.Web.UI.Client/src/packages/language/workspace/language/manifests.ts
+++ b/src/Umbraco.Web.UI.Client/src/packages/language/workspace/language/manifests.ts
@@ -1,3 +1,4 @@
+import { UMB_LANGUAGE_WORKSPACE_ALIAS } from './constants.js';
import { UmbSubmitWorkspaceAction } from '@umbraco-cms/backoffice/workspace';
import type {
ManifestWorkspaces,
@@ -9,7 +10,7 @@ import type {
const workspace: ManifestWorkspaces = {
type: 'workspace',
kind: 'routable',
- alias: 'Umb.Workspace.Language',
+ alias: UMB_LANGUAGE_WORKSPACE_ALIAS,
name: 'Language Workspace',
api: () => import('./language-workspace.context.js'),
meta: {
diff --git a/src/Umbraco.Web.UI.Client/src/packages/media/media-types/components/input-media-type/input-media-type.element.ts b/src/Umbraco.Web.UI.Client/src/packages/media/media-types/components/input-media-type/input-media-type.element.ts
index 5c2173cdd9..9b7c64f927 100644
--- a/src/Umbraco.Web.UI.Client/src/packages/media/media-types/components/input-media-type/input-media-type.element.ts
+++ b/src/Umbraco.Web.UI.Client/src/packages/media/media-types/components/input-media-type/input-media-type.element.ts
@@ -174,7 +174,7 @@ export class UmbInputMediaTypeElement extends UmbFormControlMixin
+
${this.#renderIcon(item)}
diff --git a/src/Umbraco.Web.UI.Client/src/packages/media/media-types/index.ts b/src/Umbraco.Web.UI.Client/src/packages/media/media-types/index.ts
index 39c2b4ea8b..4fdc741116 100644
--- a/src/Umbraco.Web.UI.Client/src/packages/media/media-types/index.ts
+++ b/src/Umbraco.Web.UI.Client/src/packages/media/media-types/index.ts
@@ -1,12 +1,11 @@
import './components/index.js';
export * from './components/index.js';
-export * from './workspace/index.js';
-
+export * from './entity.js';
export * from './repository/index.js';
export * from './tree/types.js';
-export * from './utils.ts/index.js';
export * from './types.js';
-export * from './entity.js';
+export * from './utils.ts/index.js';
+export * from './workspace/index.js';
export { UMB_MEDIA_TYPE_PICKER_MODAL } from './tree/index.js';
diff --git a/src/Umbraco.Web.UI.Client/src/packages/media/media-types/repository/composition/index.ts b/src/Umbraco.Web.UI.Client/src/packages/media/media-types/repository/composition/index.ts
new file mode 100644
index 0000000000..e9c3158173
--- /dev/null
+++ b/src/Umbraco.Web.UI.Client/src/packages/media/media-types/repository/composition/index.ts
@@ -0,0 +1 @@
+export { UMB_MEDIA_TYPE_COMPOSITION_REPOSITORY_ALIAS } from './manifests.js';
diff --git a/src/Umbraco.Web.UI.Client/src/packages/media/media-types/repository/composition/manifests.ts b/src/Umbraco.Web.UI.Client/src/packages/media/media-types/repository/composition/manifests.ts
new file mode 100644
index 0000000000..16ad5b903c
--- /dev/null
+++ b/src/Umbraco.Web.UI.Client/src/packages/media/media-types/repository/composition/manifests.ts
@@ -0,0 +1,12 @@
+import type { ManifestRepository, ManifestTypes } from '@umbraco-cms/backoffice/extension-registry';
+
+export const UMB_MEDIA_TYPE_COMPOSITION_REPOSITORY_ALIAS = 'Umb.Repository.MediaType.Composition';
+
+const compositionRepository: ManifestRepository = {
+ type: 'repository',
+ alias: UMB_MEDIA_TYPE_COMPOSITION_REPOSITORY_ALIAS,
+ name: 'Media Type Composition Repository',
+ api: () => import('./media-type-composition.repository.js'),
+};
+
+export const manifests: Array = [compositionRepository];
diff --git a/src/Umbraco.Web.UI.Client/src/packages/media/media-types/repository/composition/media-type-composition.repository.ts b/src/Umbraco.Web.UI.Client/src/packages/media/media-types/repository/composition/media-type-composition.repository.ts
new file mode 100644
index 0000000000..a73570e069
--- /dev/null
+++ b/src/Umbraco.Web.UI.Client/src/packages/media/media-types/repository/composition/media-type-composition.repository.ts
@@ -0,0 +1,36 @@
+import { UmbMediaTypeCompositionServerDataSource } from './media-type-composition.server.data-source.js';
+import type { UmbContentTypeCompositionRepository } from '@umbraco-cms/backoffice/content-type';
+import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api';
+import type {
+ UmbMediaTypeAvailableCompositionRequestModel,
+ UmbMediaTypeCompositionCompatibleModel,
+ UmbMediaTypeCompositionReferenceModel,
+} from '@umbraco-cms/backoffice/media-type';
+import { UmbRepositoryBase } from '@umbraco-cms/backoffice/repository';
+
+export class UmbMediaTypeCompositionRepository
+ extends UmbRepositoryBase
+ implements
+ UmbContentTypeCompositionRepository<
+ UmbMediaTypeCompositionReferenceModel,
+ UmbMediaTypeCompositionCompatibleModel,
+ UmbMediaTypeAvailableCompositionRequestModel
+ >
+{
+ #compositionSource: UmbMediaTypeCompositionServerDataSource;
+
+ constructor(host: UmbControllerHost) {
+ super(host);
+ this.#compositionSource = new UmbMediaTypeCompositionServerDataSource(this);
+ }
+
+ async getReferences(unique: string) {
+ return this.#compositionSource.getReferences(unique);
+ }
+
+ async availableCompositions(args: UmbMediaTypeAvailableCompositionRequestModel) {
+ return this.#compositionSource.availableCompositions(args);
+ }
+}
+
+export { UmbMediaTypeCompositionRepository as api };
diff --git a/src/Umbraco.Web.UI.Client/src/packages/media/media-types/repository/composition/media-type-composition.server.data-source.ts b/src/Umbraco.Web.UI.Client/src/packages/media/media-types/repository/composition/media-type-composition.server.data-source.ts
new file mode 100644
index 0000000000..81e1e7d28b
--- /dev/null
+++ b/src/Umbraco.Web.UI.Client/src/packages/media/media-types/repository/composition/media-type-composition.server.data-source.ts
@@ -0,0 +1,86 @@
+import type {
+ UmbMediaTypeCompositionCompatibleModel,
+ UmbMediaTypeCompositionReferenceModel,
+ UmbMediaTypeAvailableCompositionRequestModel,
+} from '../../types.js';
+import { type MediaTypeCompositionRequestModel, MediaTypeService } from '@umbraco-cms/backoffice/external/backend-api';
+import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api';
+import { tryExecuteAndNotify } from '@umbraco-cms/backoffice/resources';
+import type { UmbContentTypeCompositionDataSource } from '@umbraco-cms/backoffice/content-type';
+
+/**
+ * A data source for the Media Type Composition that fetches data from the server
+ * @export
+ * @class UmbMediaTypeCompositionServerDataSource
+ */
+export class UmbMediaTypeCompositionServerDataSource
+ implements
+ UmbContentTypeCompositionDataSource<
+ UmbMediaTypeCompositionReferenceModel,
+ UmbMediaTypeCompositionCompatibleModel,
+ UmbMediaTypeAvailableCompositionRequestModel
+ >
+{
+ #host: UmbControllerHost;
+
+ /**
+ * Creates an instance of UmbMediaTypeCompositionServerDataSource.
+ * @param {UmbControllerHost} host
+ * @memberof UmbMediaTypeCompositionServerDataSource
+ */
+ constructor(host: UmbControllerHost) {
+ this.#host = host;
+ }
+ /**
+ * Fetches the compatible compositions for a Media type from the server
+ * @param {string} unique
+ * @return {*}
+ * @memberof UmbMediaTypeCompositionServerDataSource
+ */
+ async getReferences(unique: string) {
+ const response = await tryExecuteAndNotify(
+ this.#host,
+ MediaTypeService.getMediaTypeByIdCompositionReferences({ id: unique }),
+ );
+ const error = response.error;
+ const data: Array | undefined = response.data?.map((reference) => {
+ return {
+ unique: reference.id,
+ icon: reference.icon,
+ name: reference.name,
+ };
+ });
+
+ return { data, error };
+ }
+ /**
+ * Updates the compositions for a media type on the server
+ * @param {MediaTypeCompositionRequestModel} requestBody
+ * @return {*}
+ * @memberof UmbMediaTypeCompositionServerDataSource
+ */
+ async availableCompositions(args: UmbMediaTypeAvailableCompositionRequestModel) {
+ const requestBody: MediaTypeCompositionRequestModel = {
+ id: args.unique,
+ currentCompositeIds: args.currentCompositeUniques,
+ currentPropertyAliases: args.currentPropertyAliases,
+ };
+
+ const response = await tryExecuteAndNotify(
+ this.#host,
+ MediaTypeService.postMediaTypeAvailableCompositions({ requestBody }),
+ );
+ const error = response.error;
+ const data: Array | undefined = response.data?.map((composition) => {
+ return {
+ unique: composition.id,
+ name: composition.name,
+ icon: composition.icon,
+ folderPath: composition.folderPath,
+ isCompatible: composition.isCompatible,
+ };
+ });
+
+ return { data, error };
+ }
+}
diff --git a/src/Umbraco.Web.UI.Client/src/packages/media/media-types/repository/index.ts b/src/Umbraco.Web.UI.Client/src/packages/media/media-types/repository/index.ts
index e84c58d982..e3bd416604 100644
--- a/src/Umbraco.Web.UI.Client/src/packages/media/media-types/repository/index.ts
+++ b/src/Umbraco.Web.UI.Client/src/packages/media/media-types/repository/index.ts
@@ -1,3 +1,4 @@
-export * from './item/index.js';
+export * from './composition/index.js';
export * from './detail/index.js';
+export * from './item/index.js';
export * from './structure/index.js';
diff --git a/src/Umbraco.Web.UI.Client/src/packages/media/media-types/repository/manifests.ts b/src/Umbraco.Web.UI.Client/src/packages/media/media-types/repository/manifests.ts
index 37dcb889ef..ce74b2570d 100644
--- a/src/Umbraco.Web.UI.Client/src/packages/media/media-types/repository/manifests.ts
+++ b/src/Umbraco.Web.UI.Client/src/packages/media/media-types/repository/manifests.ts
@@ -1,5 +1,6 @@
import { manifests as detailManifests } from './detail/manifests.js';
import { manifests as itemManifests } from './item/manifests.js';
+import { manifests as compositionManifests } from './composition/manifests.js';
import type { ManifestTypes } from '@umbraco-cms/backoffice/extension-registry';
-export const manifests: Array = [...detailManifests, ...itemManifests];
+export const manifests: Array = [...detailManifests, ...itemManifests, ...compositionManifests];
diff --git a/src/Umbraco.Web.UI.Client/src/packages/media/media-types/types.ts b/src/Umbraco.Web.UI.Client/src/packages/media/media-types/types.ts
index 828514db06..17acb2e86e 100644
--- a/src/Umbraco.Web.UI.Client/src/packages/media/media-types/types.ts
+++ b/src/Umbraco.Web.UI.Client/src/packages/media/media-types/types.ts
@@ -1,6 +1,17 @@
import type { UmbMediaTypeEntityType } from './entity.js';
-import type { UmbContentTypeModel } from '@umbraco-cms/backoffice/content-type';
+import type {
+ UmbContentTypeAvailableCompositionRequestModel,
+ UmbContentTypeCompositionCompatibleModel,
+ UmbContentTypeCompositionReferenceModel,
+ UmbContentTypeModel,
+} from '@umbraco-cms/backoffice/content-type';
export interface UmbMediaTypeDetailModel extends UmbContentTypeModel {
entityType: UmbMediaTypeEntityType;
}
+
+export interface UmbMediaTypeAvailableCompositionRequestModel extends UmbContentTypeAvailableCompositionRequestModel {}
+
+export interface UmbMediaTypeCompositionCompatibleModel extends UmbContentTypeCompositionCompatibleModel {}
+
+export interface UmbMediaTypeCompositionReferenceModel extends UmbContentTypeCompositionReferenceModel {}
diff --git a/src/Umbraco.Web.UI.Client/src/packages/media/media-types/workspace/manifests.ts b/src/Umbraco.Web.UI.Client/src/packages/media/media-types/workspace/manifests.ts
index a0cb73a866..01293d0d96 100644
--- a/src/Umbraco.Web.UI.Client/src/packages/media/media-types/workspace/manifests.ts
+++ b/src/Umbraco.Web.UI.Client/src/packages/media/media-types/workspace/manifests.ts
@@ -1,3 +1,4 @@
+import { UMB_MEDIA_TYPE_COMPOSITION_REPOSITORY_ALIAS } from '../repository/index.js';
import { UMB_MEDIA_TYPE_WORKSPACE_ALIAS } from './constants.js';
import type {
ManifestWorkspaces,
@@ -29,6 +30,7 @@ const workspaceViews: Array = [
label: '#general_design',
pathname: 'design',
icon: 'icon-document-dashed-line',
+ compositionRepositoryAlias: UMB_MEDIA_TYPE_COMPOSITION_REPOSITORY_ALIAS,
},
conditions: [
{
diff --git a/src/Umbraco.Web.UI.Client/src/packages/media/media/entity-actions/create/media-create-options-modal.element.ts b/src/Umbraco.Web.UI.Client/src/packages/media/media/entity-actions/create/media-create-options-modal.element.ts
index 2773d3c991..8de7a5fef3 100644
--- a/src/Umbraco.Web.UI.Client/src/packages/media/media/entity-actions/create/media-create-options-modal.element.ts
+++ b/src/Umbraco.Web.UI.Client/src/packages/media/media/entity-actions/create/media-create-options-modal.element.ts
@@ -89,7 +89,8 @@ export class UmbMediaCreateOptionsModalElement extends UmbModalBaseElement<
}
#renderNotAllowed() {
- return html`
+ return html`
+
There are no allowed Media Types available for creating media here. You must enable these in
Media Types within the Settings section, by editing the
Allowed child node types under Permissions. this._rejectModal()}
href=${`/section/settings/workspace/media-type/edit/${this.data?.mediaType?.unique}/view/structure`}
- label=${this.localize.term('create_noMediaTypesEditPermissions')}>`;
+ label=${this.localize.term('create_noMediaTypesEditPermissions')}>
+ `;
}
#renderAllowedMediaTypes() {
return repeat(
this._allowedMediaTypes,
(mediaType) => mediaType.unique,
- (mediaType) =>
- html`
html`
+ this.#onNavigate(mediaType)}>
${mediaType.icon ? html`` : nothing}
- `,
+
+ `,
);
}
diff --git a/src/Umbraco.Web.UI.Client/src/packages/members/member-type/components/input-member-type/input-member-type.element.ts b/src/Umbraco.Web.UI.Client/src/packages/members/member-type/components/input-member-type/input-member-type.element.ts
index 02d36f5921..d66e61df7e 100644
--- a/src/Umbraco.Web.UI.Client/src/packages/members/member-type/components/input-member-type/input-member-type.element.ts
+++ b/src/Umbraco.Web.UI.Client/src/packages/members/member-type/components/input-member-type/input-member-type.element.ts
@@ -137,7 +137,7 @@ export class UmbInputMemberTypeElement extends UmbFormControlMixin
+
${when(item.icon, () => html``)}
import('./member-type-composition.repository.js'),
+};
+
+export const manifests: Array = [compositionRepository];
diff --git a/src/Umbraco.Web.UI.Client/src/packages/members/member-type/repository/composition/member-type-composition.repository.ts b/src/Umbraco.Web.UI.Client/src/packages/members/member-type/repository/composition/member-type-composition.repository.ts
new file mode 100644
index 0000000000..a64e0a3ef8
--- /dev/null
+++ b/src/Umbraco.Web.UI.Client/src/packages/members/member-type/repository/composition/member-type-composition.repository.ts
@@ -0,0 +1,36 @@
+import { UmbMemberTypeCompositionServerDataSource } from './member-type-composition.server.data-source.js';
+import type { UmbContentTypeCompositionRepository } from '@umbraco-cms/backoffice/content-type';
+import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api';
+import type {
+ UmbMemberTypeAvailableCompositionRequestModel,
+ UmbMemberTypeCompositionCompatibleModel,
+ UmbMemberTypeCompositionReferenceModel,
+} from '@umbraco-cms/backoffice/member-type';
+import { UmbRepositoryBase } from '@umbraco-cms/backoffice/repository';
+
+export class UmbMemberTypeCompositionRepository
+ extends UmbRepositoryBase
+ implements
+ UmbContentTypeCompositionRepository<
+ UmbMemberTypeCompositionReferenceModel,
+ UmbMemberTypeCompositionCompatibleModel,
+ UmbMemberTypeAvailableCompositionRequestModel
+ >
+{
+ #compositionSource: UmbMemberTypeCompositionServerDataSource;
+
+ constructor(host: UmbControllerHost) {
+ super(host);
+ this.#compositionSource = new UmbMemberTypeCompositionServerDataSource(this);
+ }
+
+ async getReferences(unique: string) {
+ return this.#compositionSource.getReferences(unique);
+ }
+
+ async availableCompositions(args: UmbMemberTypeAvailableCompositionRequestModel) {
+ return this.#compositionSource.availableCompositions(args);
+ }
+}
+
+export { UmbMemberTypeCompositionRepository as api };
diff --git a/src/Umbraco.Web.UI.Client/src/packages/members/member-type/repository/composition/member-type-composition.server.data-source.ts b/src/Umbraco.Web.UI.Client/src/packages/members/member-type/repository/composition/member-type-composition.server.data-source.ts
new file mode 100644
index 0000000000..dc38ede4a2
--- /dev/null
+++ b/src/Umbraco.Web.UI.Client/src/packages/members/member-type/repository/composition/member-type-composition.server.data-source.ts
@@ -0,0 +1,89 @@
+import type {
+ UmbMemberTypeCompositionCompatibleModel,
+ UmbMemberTypeCompositionReferenceModel,
+ UmbMemberTypeAvailableCompositionRequestModel,
+} from '../../types.js';
+import {
+ type MemberTypeCompositionRequestModel,
+ MemberTypeService,
+} from '@umbraco-cms/backoffice/external/backend-api';
+import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api';
+import { tryExecuteAndNotify } from '@umbraco-cms/backoffice/resources';
+import type { UmbContentTypeCompositionDataSource } from '@umbraco-cms/backoffice/content-type';
+
+/**
+ * A data source for the Member Type Composition that fetches data from the server
+ * @export
+ * @class UmbMemberTypeCompositionServerDataSource
+ */
+export class UmbMemberTypeCompositionServerDataSource
+ implements
+ UmbContentTypeCompositionDataSource<
+ UmbMemberTypeCompositionReferenceModel,
+ UmbMemberTypeCompositionCompatibleModel,
+ UmbMemberTypeAvailableCompositionRequestModel
+ >
+{
+ #host: UmbControllerHost;
+
+ /**
+ * Creates an instance of UmbMemberTypeCompositionServerDataSource.
+ * @param {UmbControllerHost} host
+ * @memberof UmbMemberTypeCompositionServerDataSource
+ */
+ constructor(host: UmbControllerHost) {
+ this.#host = host;
+ }
+ /**
+ * Fetches the compatible compositions for a document type from the server
+ * @param {string} unique
+ * @return {*}
+ * @memberof UmbMemberTypeCompositionServerDataSource
+ */
+ async getReferences(unique: string) {
+ const response = await tryExecuteAndNotify(
+ this.#host,
+ MemberTypeService.getMemberTypeByIdCompositionReferences({ id: unique }),
+ );
+ const error = response.error;
+ const data: Array | undefined = response.data?.map((reference) => {
+ return {
+ unique: reference.id,
+ icon: reference.icon,
+ name: reference.name,
+ };
+ });
+
+ return { data, error };
+ }
+ /**
+ * Updates the compositions for a document type on the server
+ * @param {MemberTypeCompositionRequestModel} requestBody
+ * @return {*}
+ * @memberof UmbMemberTypeCompositionServerDataSource
+ */
+ async availableCompositions(args: UmbMemberTypeAvailableCompositionRequestModel) {
+ const requestBody: MemberTypeCompositionRequestModel = {
+ id: args.unique,
+ currentCompositeIds: args.currentCompositeUniques,
+ currentPropertyAliases: args.currentPropertyAliases,
+ };
+
+ const response = await tryExecuteAndNotify(
+ this.#host,
+ MemberTypeService.postMemberTypeAvailableCompositions({ requestBody }),
+ );
+ const error = response.error;
+ const data: Array | undefined = response.data?.map((composition) => {
+ return {
+ unique: composition.id,
+ name: composition.name,
+ icon: composition.icon,
+ folderPath: composition.folderPath,
+ isCompatible: composition.isCompatible,
+ };
+ });
+
+ return { data, error };
+ }
+}
diff --git a/src/Umbraco.Web.UI.Client/src/packages/members/member-type/repository/index.ts b/src/Umbraco.Web.UI.Client/src/packages/members/member-type/repository/index.ts
index f396068800..5a07494cdb 100644
--- a/src/Umbraco.Web.UI.Client/src/packages/members/member-type/repository/index.ts
+++ b/src/Umbraco.Web.UI.Client/src/packages/members/member-type/repository/index.ts
@@ -1,2 +1,3 @@
export { UmbMemberTypeDetailRepository, UMB_MEMBER_TYPE_DETAIL_REPOSITORY_ALIAS } from './detail/index.js';
export { UmbMemberTypeItemRepository, UMB_MEMBER_TYPE_ITEM_REPOSITORY_ALIAS } from './item/index.js';
+export { UMB_MEMBER_TYPE_COMPOSITION_REPOSITORY_ALIAS } from './composition/index.js';
diff --git a/src/Umbraco.Web.UI.Client/src/packages/members/member-type/repository/manifests.ts b/src/Umbraco.Web.UI.Client/src/packages/members/member-type/repository/manifests.ts
index 37dcb889ef..ce74b2570d 100644
--- a/src/Umbraco.Web.UI.Client/src/packages/members/member-type/repository/manifests.ts
+++ b/src/Umbraco.Web.UI.Client/src/packages/members/member-type/repository/manifests.ts
@@ -1,5 +1,6 @@
import { manifests as detailManifests } from './detail/manifests.js';
import { manifests as itemManifests } from './item/manifests.js';
+import { manifests as compositionManifests } from './composition/manifests.js';
import type { ManifestTypes } from '@umbraco-cms/backoffice/extension-registry';
-export const manifests: Array = [...detailManifests, ...itemManifests];
+export const manifests: Array = [...detailManifests, ...itemManifests, ...compositionManifests];
diff --git a/src/Umbraco.Web.UI.Client/src/packages/members/member-type/types.ts b/src/Umbraco.Web.UI.Client/src/packages/members/member-type/types.ts
index 41bb9c2f08..c17ebcebe6 100644
--- a/src/Umbraco.Web.UI.Client/src/packages/members/member-type/types.ts
+++ b/src/Umbraco.Web.UI.Client/src/packages/members/member-type/types.ts
@@ -1,6 +1,17 @@
import type { UmbMemberTypeEntityType } from './entity.js';
-import type { UmbContentTypeModel } from '@umbraco-cms/backoffice/content-type';
+import type {
+ UmbContentTypeAvailableCompositionRequestModel,
+ UmbContentTypeCompositionCompatibleModel,
+ UmbContentTypeCompositionReferenceModel,
+ UmbContentTypeModel,
+} from '@umbraco-cms/backoffice/content-type';
export interface UmbMemberTypeDetailModel extends UmbContentTypeModel {
entityType: UmbMemberTypeEntityType;
}
+
+export interface UmbMemberTypeAvailableCompositionRequestModel extends UmbContentTypeAvailableCompositionRequestModel {}
+
+export interface UmbMemberTypeCompositionCompatibleModel extends UmbContentTypeCompositionCompatibleModel {}
+
+export interface UmbMemberTypeCompositionReferenceModel extends UmbContentTypeCompositionReferenceModel {}
diff --git a/src/Umbraco.Web.UI.Client/src/packages/members/member-type/workspace/manifests.ts b/src/Umbraco.Web.UI.Client/src/packages/members/member-type/workspace/manifests.ts
index ac2e37d3da..fbac4d07c2 100644
--- a/src/Umbraco.Web.UI.Client/src/packages/members/member-type/workspace/manifests.ts
+++ b/src/Umbraco.Web.UI.Client/src/packages/members/member-type/workspace/manifests.ts
@@ -1,7 +1,8 @@
+import { UMB_MEMBER_TYPE_COMPOSITION_REPOSITORY_ALIAS } from '../repository/index.js';
import type {
ManifestWorkspaces,
ManifestWorkspaceActions,
- ManifestWorkspaceView,
+ ManifestWorkspaceViews,
ManifestTypes,
} from '@umbraco-cms/backoffice/extension-registry';
import { UmbSubmitWorkspaceAction } from '@umbraco-cms/backoffice/workspace';
@@ -19,7 +20,7 @@ const workspace: ManifestWorkspaces = {
},
};
-const workspaceViews: Array = [
+const workspaceViews: Array = [
{
type: 'workspaceView',
kind: 'contentTypeDesignEditor',
@@ -29,6 +30,7 @@ const workspaceViews: Array = [
label: '#general_design',
pathname: 'design',
icon: 'icon-member-dashed-line',
+ compositionRepositoryAlias: UMB_MEMBER_TYPE_COMPOSITION_REPOSITORY_ALIAS,
},
conditions: [
{
diff --git a/src/Umbraco.Web.UI.Client/src/packages/templating/modals/templating-page-field-builder/components/template-field-dropdown-list/template-field-dropdown-list.element.ts b/src/Umbraco.Web.UI.Client/src/packages/templating/modals/templating-page-field-builder/components/template-field-dropdown-list/template-field-dropdown-list.element.ts
index 5ced56e80c..ef744bf99c 100644
--- a/src/Umbraco.Web.UI.Client/src/packages/templating/modals/templating-page-field-builder/components/template-field-dropdown-list/template-field-dropdown-list.element.ts
+++ b/src/Umbraco.Web.UI.Client/src/packages/templating/modals/templating-page-field-builder/components/template-field-dropdown-list/template-field-dropdown-list.element.ts
@@ -152,7 +152,7 @@ export class UmbTemplateFieldDropdownListElement extends UmbLitElement {
- ${this.localize.term('formSettings_systemFields')}
+ ${this.localize.term('template_systemFields')}
${this.localize.term('content_documentType')}
@@ -174,7 +174,8 @@ export class UmbTemplateFieldDropdownListElement extends UmbLitElement {
#renderAliasDropdown() {
if (this._type !== FieldType.SYSTEM && !this._unique) return;
- return html`${this._uniqueName}
+ return html`
+ ${this.localize.string(this._uniqueName ?? '')}
${repeat(
@@ -184,7 +185,8 @@ export class UmbTemplateFieldDropdownListElement extends UmbLitElement {
html`${field.alias}`,
)}
- `;
+
+ `;
}
static override styles = [
diff --git a/src/Umbraco.Web.UI.Client/src/packages/tiny-mce/package.json b/src/Umbraco.Web.UI.Client/src/packages/tiny-mce/package.json
new file mode 100644
index 0000000000..6362dc5347
--- /dev/null
+++ b/src/Umbraco.Web.UI.Client/src/packages/tiny-mce/package.json
@@ -0,0 +1,8 @@
+{
+ "name": "@umbraco-backoffice/tiny-mce",
+ "private": true,
+ "type": "module",
+ "scripts": {
+ "build": "vite build"
+ }
+}
diff --git a/src/Umbraco.Web.UI.Client/src/packages/tiny-mce/vite.config.ts b/src/Umbraco.Web.UI.Client/src/packages/tiny-mce/vite.config.ts
new file mode 100644
index 0000000000..d0c457d1e9
--- /dev/null
+++ b/src/Umbraco.Web.UI.Client/src/packages/tiny-mce/vite.config.ts
@@ -0,0 +1,12 @@
+import { defineConfig } from 'vite';
+import { rmSync } from 'fs';
+import { getDefaultConfig } from '../../vite-config-base';
+
+const dist = '../../../dist-cms/packages/tiny-mce';
+
+// delete the unbundled dist folder
+rmSync(dist, { recursive: true, force: true });
+
+export default defineConfig({
+ ...getDefaultConfig({ dist }),
+});
diff --git a/src/Umbraco.Web.UI.Client/src/packages/webhook/collection/views/table/column-layouts/boolean/webhook-table-boolean-column-layout.element.ts b/src/Umbraco.Web.UI.Client/src/packages/webhook/collection/views/table/column-layouts/boolean/webhook-table-boolean-column-layout.element.ts
index 21f972c729..e16d4f4bb7 100644
--- a/src/Umbraco.Web.UI.Client/src/packages/webhook/collection/views/table/column-layouts/boolean/webhook-table-boolean-column-layout.element.ts
+++ b/src/Umbraco.Web.UI.Client/src/packages/webhook/collection/views/table/column-layouts/boolean/webhook-table-boolean-column-layout.element.ts
@@ -1,4 +1,4 @@
-import { html, nothing, customElement, property } from '@umbraco-cms/backoffice/external/lit';
+import { html, customElement, property } from '@umbraco-cms/backoffice/external/lit';
import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element';
@customElement('umb-webhook-table-boolean-column-layout')
@@ -7,7 +7,7 @@ export class UmbWebhookTableBooleanColumnLayoutElement extends UmbLitElement {
value = false;
override render() {
- return this.value ? html`` : nothing;
+ return html``;
}
}
diff --git a/src/Umbraco.Web.UI.Client/src/packages/webhook/collection/views/table/column-layouts/content-type/webhook-table-name-column-layout.element.ts b/src/Umbraco.Web.UI.Client/src/packages/webhook/collection/views/table/column-layouts/content-type/webhook-table-name-column-layout.element.ts
index 032ca105a4..116bd06841 100644
--- a/src/Umbraco.Web.UI.Client/src/packages/webhook/collection/views/table/column-layouts/content-type/webhook-table-name-column-layout.element.ts
+++ b/src/Umbraco.Web.UI.Client/src/packages/webhook/collection/views/table/column-layouts/content-type/webhook-table-name-column-layout.element.ts
@@ -32,7 +32,7 @@ export class UmbWebhookTableContentTypeColumnLayoutElement extends UmbLitElement
if (this.value?.contentTypeName && this.#repository) {
const { data } = await this.#repository.requestItems(this.value.contentTypes);
- this._contentTypes = data?.map((item) => item.name).join(', ') ?? '';
+ this._contentTypes = data?.map((item) => this.localize.string(item.name)).join(', ') ?? '';
}
}
diff --git a/src/Umbraco.Web.UI.Client/src/packages/webhook/collection/views/table/webhook-table-collection-view.element.ts b/src/Umbraco.Web.UI.Client/src/packages/webhook/collection/views/table/webhook-table-collection-view.element.ts
index 5ac9a83cf8..4128f4e9d2 100644
--- a/src/Umbraco.Web.UI.Client/src/packages/webhook/collection/views/table/webhook-table-collection-view.element.ts
+++ b/src/Umbraco.Web.UI.Client/src/packages/webhook/collection/views/table/webhook-table-collection-view.element.ts
@@ -1,10 +1,9 @@
import type { UmbWebhookDetailModel } from '../../../types.js';
import type { UmbDefaultCollectionContext } from '@umbraco-cms/backoffice/collection';
+import { css, customElement, html, state } from '@umbraco-cms/backoffice/external/lit';
+import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element';
import { UMB_COLLECTION_CONTEXT } from '@umbraco-cms/backoffice/collection';
import type { UmbTableColumn, UmbTableConfig, UmbTableItem } from '@umbraco-cms/backoffice/components';
-import { css, html, customElement, state } from '@umbraco-cms/backoffice/external/lit';
-import { UmbTextStyles } from '@umbraco-cms/backoffice/style';
-import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element';
import './column-layouts/boolean/webhook-table-boolean-column-layout.element.js';
import './column-layouts/name/webhook-table-name-column-layout.element.js';
@@ -21,25 +20,25 @@ export class UmbWebhookTableCollectionViewElement extends UmbLitElement {
@state()
private _tableColumns: Array = [
{
- name: 'Name',
+ name: this.localize.term('general_name'),
alias: 'name',
elementName: 'umb-webhook-table-name-column-layout',
},
{
- name: 'Enabled',
+ name: this.localize.term('webhooks_enabled'),
alias: 'enabled',
elementName: 'umb-webhook-table-boolean-column-layout',
},
{
- name: 'URL',
+ name: this.localize.term('webhooks_url'),
alias: 'url',
},
{
- name: 'Events',
+ name: this.localize.term('webhooks_events'),
alias: 'events',
},
{
- name: 'Types',
+ name: this.localize.term('webhooks_types'),
alias: 'types',
elementName: 'umb-webhook-table-content-type-column-layout',
},
@@ -112,7 +111,6 @@ export class UmbWebhookTableCollectionViewElement extends UmbLitElement {
}
static override styles = [
- UmbTextStyles,
css`
:host {
display: flex;
diff --git a/src/Umbraco.Web.UI.Client/src/packages/webhook/components/input-webhook-events.element.ts b/src/Umbraco.Web.UI.Client/src/packages/webhook/components/input-webhook-events.element.ts
index 901dc34e41..f17bea9008 100644
--- a/src/Umbraco.Web.UI.Client/src/packages/webhook/components/input-webhook-events.element.ts
+++ b/src/Umbraco.Web.UI.Client/src/packages/webhook/components/input-webhook-events.element.ts
@@ -47,23 +47,29 @@ export class UmbInputWebhookEventsElement extends UmbLitElement {
if (!this.events.length) return nothing;
return html`
- ${repeat(
- this.events,
- (item) => item.alias,
- (item) => html`
- ${item.eventName}
- this.#removeEvent(item.alias)}>
- `,
- )}
+
+ ${repeat(
+ this.events,
+ (item) => item.alias,
+ (item) => html`
+
+
+
+ this.#removeEvent(item.alias)}>
+
+
+ `,
+ )}
+
`;
}
override render() {
return html`${this.#renderEvents()}
`;
@@ -72,15 +78,8 @@ export class UmbInputWebhookEventsElement extends UmbLitElement {
static override styles = [
UmbTextStyles,
css`
- :host {
- display: grid;
- grid-template-columns: 1fr auto;
- gap: var(--uui-size-space-2) var(--uui-size-space-2);
- align-items: center;
- }
-
- #choose {
- grid-column: -1 / 1;
+ #btn-add {
+ display: block;
}
`,
];
diff --git a/src/Umbraco.Web.UI.Client/src/packages/webhook/components/input-webhook-headers.element.ts b/src/Umbraco.Web.UI.Client/src/packages/webhook/components/input-webhook-headers.element.ts
index 6819cd267a..68bc822494 100644
--- a/src/Umbraco.Web.UI.Client/src/packages/webhook/components/input-webhook-headers.element.ts
+++ b/src/Umbraco.Web.UI.Client/src/packages/webhook/components/input-webhook-headers.element.ts
@@ -14,7 +14,7 @@ export class UmbInputWebhookHeadersElement extends UmbLitElement {
private _headers: Array<{ name: string; value: string }> = [];
@state()
- private _headerNames: string[] = ['Accept', 'Content-Type', 'User-Agent', 'Content-Length'];
+ private _headerNames: string[] = ['Accept', 'Content-Length', 'Content-Type', 'User-Agent'];
get #filterHeaderNames() {
return this._headerNames.filter((name) => !this._headers.find((header) => header.name === name));
@@ -78,7 +78,7 @@ export class UmbInputWebhookHeadersElement extends UmbLitElement {
.value=${header.value}
@input=${(e: InputEvent) => this.#onInput(e, 'value', index)}
list="valueList" />
- this.#removeHeader(index)} label="Remove">
+ this.#removeHeader(index)} label=${this.localize.term('general_remove')}>
`;
}
@@ -105,8 +105,8 @@ export class UmbInputWebhookHeadersElement extends UmbLitElement {
if (!this._headers.length) return nothing;
return html`
- KEY
- VALUE
+ Name
+ Value
${repeat(
this._headers,
diff --git a/src/Umbraco.Web.UI.Client/src/packages/webhook/components/webhook-events-modal/webhook-events-modal.element.ts b/src/Umbraco.Web.UI.Client/src/packages/webhook/components/webhook-events-modal/webhook-events-modal.element.ts
index d6b2fb13f5..7df91e91c6 100644
--- a/src/Umbraco.Web.UI.Client/src/packages/webhook/components/webhook-events-modal/webhook-events-modal.element.ts
+++ b/src/Umbraco.Web.UI.Client/src/packages/webhook/components/webhook-events-modal/webhook-events-modal.element.ts
@@ -1,9 +1,7 @@
import { UmbWebhookEventRepository } from '../../repository/event/webhook-event.repository.js';
import type { UmbWebhookEventModel } from '../../types.js';
import type { UmbWebhookPickerModalData, UmbWebhookPickerModalValue } from './webhook-events-modal.token.js';
-import { UmbTextStyles } from '@umbraco-cms/backoffice/style';
-import { css, html, customElement, state, repeat } from '@umbraco-cms/backoffice/external/lit';
-
+import { customElement, html, state, repeat } from '@umbraco-cms/backoffice/external/lit';
import { UmbModalBaseElement } from '@umbraco-cms/backoffice/modal';
import { UmbSelectionManager } from '@umbraco-cms/backoffice/utils';
@@ -67,32 +65,36 @@ export class UmbWebhookEventsModalElement extends UmbModalBaseElement<
}
override render() {
- return html`
-
- ${repeat(
- this._events,
- (item) => item.alias,
- (item) => html`
- this.#selectionManager.select(item.alias)}
- @deselected=${() => this.#selectionManager.deselect(item.alias)}
- ?selected=${this.value.events.includes(item)}>
-
-
- `,
- )}
-
-
-
-
-
- `;
+ return html`
+
+
+ ${repeat(
+ this._events,
+ (item) => item.alias,
+ (item) => html`
+ this.#selectionManager.select(item.alias)}
+ @deselected=${() => this.#selectionManager.deselect(item.alias)}
+ ?selected=${this.value.events.includes(item)}>
+
+
+ `,
+ )}
+
+
+
+
+
+
+ `;
}
-
- static override styles = [UmbTextStyles, css``];
}
export default UmbWebhookEventsModalElement;
diff --git a/src/Umbraco.Web.UI.Client/src/packages/webhook/workspace/webhook-root/webhook-root-workspace.element.ts b/src/Umbraco.Web.UI.Client/src/packages/webhook/workspace/webhook-root/webhook-root-workspace.element.ts
index 071ecf38ef..3149d847cc 100644
--- a/src/Umbraco.Web.UI.Client/src/packages/webhook/workspace/webhook-root/webhook-root-workspace.element.ts
+++ b/src/Umbraco.Web.UI.Client/src/packages/webhook/workspace/webhook-root/webhook-root-workspace.element.ts
@@ -5,9 +5,11 @@ import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element';
@customElement('umb-webhook-root-workspace')
export class UmbWebhookRootWorkspaceElement extends UmbLitElement {
override render() {
- return html`
- ;
- `;
+ return html`
+
+ ;
+
+ `;
}
}
diff --git a/src/Umbraco.Web.UI.Client/src/packages/webhook/workspace/webhook/views/webhook-details-workspace-view.element.ts b/src/Umbraco.Web.UI.Client/src/packages/webhook/workspace/webhook/views/webhook-details-workspace-view.element.ts
index c9f9ea0eb6..0be8864bd5 100644
--- a/src/Umbraco.Web.UI.Client/src/packages/webhook/workspace/webhook/views/webhook-details-workspace-view.element.ts
+++ b/src/Umbraco.Web.UI.Client/src/packages/webhook/workspace/webhook/views/webhook-details-workspace-view.element.ts
@@ -1,17 +1,16 @@
-import type { UmbInputWebhookHeadersElement } from '../../../components/input-webhook-headers.element.js';
import { UMB_WEBHOOK_WORKSPACE_CONTEXT } from '../webhook-workspace.context-token.js';
+import type { UmbInputWebhookHeadersElement } from '../../../components/input-webhook-headers.element.js';
import type { UmbInputWebhookEventsElement } from '../../../components/input-webhook-events.element.js';
-import { css, html, customElement, state, nothing } from '@umbraco-cms/backoffice/external/lit';
+import { css, customElement, html, state, nothing } from '@umbraco-cms/backoffice/external/lit';
import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element';
-import type { UmbWorkspaceViewElement } from '@umbraco-cms/backoffice/extension-registry';
import { UmbTextStyles } from '@umbraco-cms/backoffice/style';
-import '@umbraco-cms/backoffice/culture';
-import type { UmbWebhookDetailModel } from '@umbraco-cms/backoffice/webhook';
-
import type { UmbChangeEvent } from '@umbraco-cms/backoffice/event';
import type { UmbInputDocumentTypeElement } from '@umbraco-cms/backoffice/document-type';
+import type { UmbWebhookDetailModel } from '@umbraco-cms/backoffice/webhook';
+import type { UmbWorkspaceViewElement } from '@umbraco-cms/backoffice/extension-registry';
import type { UUIBooleanInputEvent, UUIInputEvent } from '@umbraco-cms/backoffice/external/uui';
+import '@umbraco-cms/backoffice/culture';
import '../../../components/input-webhook-headers.element.js';
import '../../../components/input-webhook-events.element.js';
@@ -43,9 +42,9 @@ export class UmbWebhookDetailsWorkspaceViewElement extends UmbLitElement impleme
});
}
- #onEventsChange(event: UmbChangeEvent) {
- const events = (event.target as UmbInputWebhookEventsElement).events;
- if (events[0].eventType !== this.contentType) {
+ #onEventsChange(event: UmbChangeEvent & { target: UmbInputWebhookEventsElement }) {
+ const events = event.target.events ?? [];
+ if (events.length && events[0].eventType !== this.contentType) {
this.#webhookWorkspaceContext?.setTypes([]);
}
this.#webhookWorkspaceContext?.setEvents(events);
@@ -75,7 +74,9 @@ export class UmbWebhookDetailsWorkspaceViewElement extends UmbLitElement impleme
if (this.contentType !== 'Content' && this.contentType !== 'Media') return nothing;
return html`
-
+
${this.#renderContentTypePickerEditor()}
`;
@@ -84,17 +85,20 @@ export class UmbWebhookDetailsWorkspaceViewElement extends UmbLitElement impleme
#renderContentTypePickerEditor() {
switch (this.contentType) {
case 'Content':
- return html``;
+ return html`
+
+ `;
case 'Media':
- return html``;
+ return html`
+
+ `;
default:
return nothing;
}
@@ -105,20 +109,28 @@ export class UmbWebhookDetailsWorkspaceViewElement extends UmbLitElement impleme
return html`
-
+
-
+
${this.#renderContentTypePicker()}
-
-
+
+
-
+
`;
+ return html`
+
+ `;
}
static override styles = [UmbTextStyles];