diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/components/property-editor-config/property-editor-config.element.ts b/src/Umbraco.Web.UI.Client/src/packages/core/components/property-editor-config/property-editor-config.element.ts index 31cdf53688..5325f19f3c 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/components/property-editor-config/property-editor-config.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/components/property-editor-config/property-editor-config.element.ts @@ -1,8 +1,6 @@ -import { html, customElement, property, state, ifDefined } from '@umbraco-cms/backoffice/external/lit'; -import { UmbTextStyles } from "@umbraco-cms/backoffice/style"; -import { - PropertyEditorConfigProperty, -} from '@umbraco-cms/backoffice/extension-registry'; +import { html, customElement, state, ifDefined, repeat } from '@umbraco-cms/backoffice/external/lit'; +import { UmbTextStyles } from '@umbraco-cms/backoffice/style'; +import { PropertyEditorConfigProperty } from '@umbraco-cms/backoffice/extension-registry'; import { UmbLitElement } from '@umbraco-cms/internal/lit-element'; import { UMB_DATA_TYPE_VARIANT_CONTEXT } from '@umbraco-cms/backoffice/data-type'; @@ -14,53 +12,46 @@ import { UMB_DATA_TYPE_VARIANT_CONTEXT } from '@umbraco-cms/backoffice/data-type */ @customElement('umb-property-editor-config') export class UmbPropertyEditorConfigElement extends UmbLitElement { - // TODO: Make this element generic, so its not bound to DATA-TYPEs. This will require moving some functionality of Data-Type-Context to this. and this might need to self provide a variant Context for its inner property editor UIs. #variantContext?: typeof UMB_DATA_TYPE_VARIANT_CONTEXT.TYPE; - /** - * Data. The element will render configuration editors with values from this data. - * If a value is not found in this data, the element will use the default value from the configuration. - * @type {Array<{ alias: string; value: unknown }>} - * @attr - * @default [] - */ - @property({ type: Array }) - public data: Array<{ alias: string; value: unknown }> = []; - @state() private _properties: Array = []; - constructor() { super(); this.consumeContext(UMB_DATA_TYPE_VARIANT_CONTEXT, (instance) => { this.#variantContext = instance; - this.observe(this.#variantContext.properties, (properties) => { - this._properties = properties as Array; - }, 'observeProperties'); + this.#observeProperties(); }); + } + #observeProperties() { + if (!this.#variantContext) return; + this.observe( + this.#variantContext.properties, + (properties) => { + this._properties = properties as Array; + }, + 'observeProperties', + ); } render() { - return html` - ${this._properties.length > 0 - ? html` - ${this._properties?.map( - (property) => html` - - ` - )} - ` - : html`
No configuration
`} - `; + return this._properties.length > 0 + ? repeat( + this._properties, + (property) => property.alias, + (property) => + html``, + ) + : html`
No configuration
`; } static styles = [UmbTextStyles]; diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/property-editor/schemas/Umbraco.CheckboxList.ts b/src/Umbraco.Web.UI.Client/src/packages/core/property-editor/schemas/Umbraco.CheckboxList.ts index 1999866902..5f3e5f6250 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/property-editor/schemas/Umbraco.CheckboxList.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/property-editor/schemas/Umbraco.CheckboxList.ts @@ -3,7 +3,7 @@ import type { ManifestPropertyEditorSchema } from '@umbraco-cms/backoffice/exten export const manifest: ManifestPropertyEditorSchema = { type: 'propertyEditorSchema', name: 'Checkbox List', - alias: 'Umbraco.CheckboxList', + alias: 'Umbraco.CheckBoxList', meta: { defaultPropertyEditorUiAlias: 'Umb.PropertyEditorUi.CheckboxList', }, diff --git a/src/Umbraco.Web.UI.Client/src/packages/settings/data-types/workspace/data-type-workspace.context.ts b/src/Umbraco.Web.UI.Client/src/packages/settings/data-types/workspace/data-type-workspace.context.ts index 4df074b8e9..fd3cf35957 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/settings/data-types/workspace/data-type-workspace.context.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/settings/data-types/workspace/data-type-workspace.context.ts @@ -1,12 +1,25 @@ import { UmbDataTypeRepository } from '../repository/data-type.repository.js'; import { UmbDataTypeVariantContext } from '../variant-context/data-type-variant-context.js'; -import { UmbInvariantableWorkspaceContextInterface, UmbWorkspaceContext, UmbWorkspaceContextInterface } from '@umbraco-cms/backoffice/workspace'; +import { + UmbInvariantableWorkspaceContextInterface, + UmbWorkspaceContext, + UmbWorkspaceContextInterface, +} from '@umbraco-cms/backoffice/workspace'; import type { DataTypeResponseModel } from '@umbraco-cms/backoffice/backend-api'; -import { appendToFrozenArray, UmbArrayState, UmbObjectState } from '@umbraco-cms/backoffice/observable-api'; +import { + appendToFrozenArray, + UmbArrayState, + UmbObjectState, + UmbStringState, +} from '@umbraco-cms/backoffice/observable-api'; import { UmbControllerHost, UmbControllerHostElement } from '@umbraco-cms/backoffice/controller-api'; import { UmbContextToken } from '@umbraco-cms/backoffice/context-api'; import { Observable, combineLatest, map } from '@umbraco-cms/backoffice/external/rxjs'; -import { PropertyEditorConfigDefaultData, PropertyEditorConfigProperty, umbExtensionsRegistry } from '@umbraco-cms/backoffice/extension-registry'; +import { + PropertyEditorConfigDefaultData, + PropertyEditorConfigProperty, + umbExtensionsRegistry, +} from '@umbraco-cms/backoffice/extension-registry'; import { UMB_PROPERTY_EDITOR_SCHEMA_ALIAS_DEFAULT } from '@umbraco-cms/backoffice/property-editor'; export class UmbDataTypeWorkspaceContext @@ -30,64 +43,99 @@ export class UmbDataTypeWorkspaceContext private _propertyEditorSchemaConfigDefaultData: Array = []; private _propertyEditorUISettingsDefaultData: Array = []; - private _propertyEditorSchemaConfigProperties?: Array; - private _propertyEditorUISettingsProperties?: Array; + private _propertyEditorSchemaConfigProperties: Array = []; + private _propertyEditorUISettingsProperties: Array = []; + + private _propertyEditorSchemaConfigDefaultUIAlias: string | null = null; private _configDefaultData?: Array; + private _propertyEditorUISettingsSchemaAlias?: string; + #defaults = new UmbArrayState([], (entry) => entry.alias); defaults = this.#defaults.asObservable(); + #propertyEditorUiIcon = new UmbStringState(null); + propertyEditorUiIcon = this.#propertyEditorUiIcon.asObservable(); + + #propertyEditorUiName = new UmbStringState(null); + propertyEditorUiName = this.#propertyEditorUiName.asObservable(); + constructor(host: UmbControllerHostElement) { super(host, 'Umb.Workspace.DataType', new UmbDataTypeRepository(host)); + this.#observePropertyEditorUIAlias(); + } - this.observe(this.propertyEditorUiAlias, (propertyEditorUiAlias) => { - if (!propertyEditorUiAlias) { - // No property editor ui alias, so we clean up and reset the properties. - this.removeControllerByAlias('propertyEditorUiAlias'); - this._propertyEditorUISettingsProperties = []; - this._propertyEditorUISettingsDefaultData = []; - this._mergeConfigProperties(); - this._mergeConfigDefaultData(); - return; + #observePropertyEditorUIAlias() { + this.observe(this.propertyEditorUiAlias, async (propertyEditorUiAlias) => { + // 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(); + this.setPropertyEditorUiAlias(this._propertyEditorSchemaConfigDefaultUIAlias!); + } else { + await this.#setPropertyEditorUIConfig(propertyEditorUiAlias); + this.setPropertyEditorSchemaAlias(this._propertyEditorUISettingsSchemaAlias!); + await this.#observePropertyEditorSchemaAlias(); } - this.observe( - umbExtensionsRegistry.getByTypeAndAlias('propertyEditorUi', propertyEditorUiAlias), - (manifest) => { - this._observePropertyEditorSchemaConfig( - manifest?.meta.propertyEditorSchemaAlias || UMB_PROPERTY_EDITOR_SCHEMA_ALIAS_DEFAULT - ); - this._propertyEditorUISettingsProperties = manifest?.meta.settings?.properties || []; - this._propertyEditorUISettingsDefaultData = manifest?.meta.settings?.defaultData || []; - this._mergeConfigProperties(); - this._mergeConfigDefaultData(); - } - , 'observePropertyEditorUiAlias' - ); + this._mergeConfigProperties(); + this._mergeConfigDefaultData(); }); } - private _observePropertyEditorSchemaConfig(propertyEditorSchemaAlias: string) { - this.observe( + #observePropertyEditorSchemaAlias() { + return this.observe(this.propertyEditorSchemaAlias, async (propertyEditorSchemaAlias) => { + if (!propertyEditorSchemaAlias) { + this.setPropertyEditorSchemaAlias(UMB_PROPERTY_EDITOR_SCHEMA_ALIAS_DEFAULT); + return; + } + + await this.#setPropertyEditorSchemaConfig(propertyEditorSchemaAlias); + }).asPromise(); + } + + #setPropertyEditorSchemaConfig(propertyEditorSchemaAlias: string) { + return this.observe( umbExtensionsRegistry.getByTypeAndAlias('propertyEditorSchema', propertyEditorSchemaAlias), (manifest) => { this._propertyEditorSchemaConfigProperties = manifest?.meta.settings?.properties || []; this._propertyEditorSchemaConfigDefaultData = manifest?.meta.settings?.defaultData || []; - this._mergeConfigProperties(); - this._mergeConfigDefaultData(); - } - ); + this._propertyEditorSchemaConfigDefaultUIAlias = manifest?.meta.defaultPropertyEditorUiAlias || null; + }, + ).asPromise(); + } + + #setPropertyEditorUIConfig(propertyEditorUIAlias: string) { + return this.observe( + umbExtensionsRegistry.getByTypeAndAlias('propertyEditorUi', propertyEditorUIAlias), + (manifest) => { + this.#propertyEditorUiIcon.next(manifest?.meta.icon || null); + this.#propertyEditorUiName.next(manifest?.name || null); + + this._propertyEditorUISettingsSchemaAlias = manifest?.meta.propertyEditorSchemaAlias; + this._propertyEditorUISettingsProperties = manifest?.meta.settings?.properties || []; + this._propertyEditorUISettingsDefaultData = manifest?.meta.settings?.defaultData || []; + }, + ).asPromise(); } private _mergeConfigProperties() { - if(this._propertyEditorSchemaConfigProperties && this._propertyEditorUISettingsProperties) { - this.#properties.next([...this._propertyEditorSchemaConfigProperties, ...this._propertyEditorUISettingsProperties]); + console.log('schema properties', this._propertyEditorSchemaConfigProperties); + console.log('ui properties', this._propertyEditorUISettingsProperties); + + if (this._propertyEditorSchemaConfigProperties && this._propertyEditorUISettingsProperties) { + this.#properties.next([ + ...this._propertyEditorSchemaConfigProperties, + ...this._propertyEditorUISettingsProperties, + ]); } } private _mergeConfigDefaultData() { - if(!this._propertyEditorSchemaConfigDefaultData || !this._propertyEditorUISettingsDefaultData) return; + if (!this._propertyEditorSchemaConfigDefaultData || !this._propertyEditorUISettingsDefaultData) return; this._configDefaultData = [ ...this._propertyEditorSchemaConfigDefaultData, @@ -159,17 +207,22 @@ export class UmbDataTypeWorkspaceContext return combineLatest([ this.#data.asObservablePart((data) => data?.values?.find((x) => x.alias === propertyAlias)?.value as ReturnType), - this.#defaults.asObservablePart((defaults) => defaults?.find((x) => x.alias === propertyAlias)?.value as ReturnType), + this.#defaults.asObservablePart( + (defaults) => defaults?.find((x) => x.alias === propertyAlias)?.value as ReturnType, + ), ]).pipe( map(([value, defaultValue]) => { - return (value ?? defaultValue); - }) + return value ?? defaultValue; + }), ); //return this.#data.asObservablePart((data) => data?.values?.find((x) => x.alias === propertyAlias)?.value ?? this.getPropertyDefaultValue(propertyAlias) as ReturnType); } getPropertyValue(propertyAlias: string) { - return this.#data.getValue()?.values?.find((x) => x.alias === propertyAlias)?.value as ReturnType ?? this.getPropertyDefaultValue(propertyAlias) as ReturnType; + return ( + (this.#data.getValue()?.values?.find((x) => x.alias === propertyAlias)?.value as ReturnType) ?? + (this.getPropertyDefaultValue(propertyAlias) as ReturnType) + ); } // TODO: its not called a property in the model, but we do consider this way in our front-end @@ -207,7 +260,10 @@ export class UmbDataTypeWorkspaceContext } } -export const UMB_DATA_TYPE_WORKSPACE_CONTEXT = new UmbContextToken( +export const UMB_DATA_TYPE_WORKSPACE_CONTEXT = new UmbContextToken< + UmbWorkspaceContextInterface, + UmbDataTypeWorkspaceContext +>( 'UmbWorkspaceContext', - (context): context is UmbDataTypeWorkspaceContext => context.getEntityType?.() === 'data-type' + (context): context is UmbDataTypeWorkspaceContext => context.getEntityType?.() === 'data-type', ); diff --git a/src/Umbraco.Web.UI.Client/src/packages/settings/data-types/workspace/data-type-workspace.element.ts b/src/Umbraco.Web.UI.Client/src/packages/settings/data-types/workspace/data-type-workspace.element.ts index 2da3dea777..32ba430ef3 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/settings/data-types/workspace/data-type-workspace.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/settings/data-types/workspace/data-type-workspace.element.ts @@ -1,5 +1,5 @@ import { UmbDataTypeWorkspaceContext } from './data-type-workspace.context.js'; -import { UmbTextStyles } from "@umbraco-cms/backoffice/style"; +import { UmbTextStyles } from '@umbraco-cms/backoffice/style'; import { html, customElement } from '@umbraco-cms/backoffice/external/lit'; import type { UmbRoute } from '@umbraco-cms/backoffice/router'; import { UmbLitElement } from '@umbraco-cms/internal/lit-element'; @@ -24,7 +24,7 @@ export class UmbDataTypeWorkspaceElement extends UmbLitElement { new UmbWorkspaceIsNewRedirectController( this, this.#workspaceContext, - this.shadowRoot!.querySelector('umb-router-slot')! + this.shadowRoot!.querySelector('umb-router-slot')!, ); }, }, diff --git a/src/Umbraco.Web.UI.Client/src/packages/settings/data-types/workspace/views/details/data-type-details-workspace-view.element.ts b/src/Umbraco.Web.UI.Client/src/packages/settings/data-types/workspace/views/details/data-type-details-workspace-view.element.ts index 9ff081efdc..36f841c9f2 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/settings/data-types/workspace/views/details/data-type-details-workspace-view.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/settings/data-types/workspace/views/details/data-type-details-workspace-view.element.ts @@ -1,5 +1,5 @@ import { UMB_DATA_TYPE_WORKSPACE_CONTEXT } from '../../data-type-workspace.context.js'; -import { UmbTextStyles } from "@umbraco-cms/backoffice/style"; +import { UmbTextStyles } from '@umbraco-cms/backoffice/style'; import { css, html, nothing, customElement, state } from '@umbraco-cms/backoffice/external/lit'; import { UmbModalManagerContext, @@ -8,10 +8,7 @@ import { } from '@umbraco-cms/backoffice/modal'; import { UmbLitElement } from '@umbraco-cms/internal/lit-element'; import type { DataTypeResponseModel } from '@umbraco-cms/backoffice/backend-api'; -import { - UmbWorkspaceEditorViewExtensionElement, - umbExtensionsRegistry, -} from '@umbraco-cms/backoffice/extension-registry'; +import { UmbWorkspaceEditorViewExtensionElement } from '@umbraco-cms/backoffice/extension-registry'; @customElement('umb-data-type-details-workspace-view') export class UmbDataTypeDetailsWorkspaceViewEditElement @@ -22,19 +19,16 @@ export class UmbDataTypeDetailsWorkspaceViewEditElement _dataType?: DataTypeResponseModel; @state() - private _propertyEditorUiIcon?: string; + private _propertyEditorUiIcon?: string | null = null; @state() - private _propertyEditorUiName?: string; + private _propertyEditorUiName?: string | null = null; @state() - private _propertyEditorUiAlias?: string; + private _propertyEditorUiAlias?: string | null = null; @state() - private _propertyEditorSchemaAlias?: string; - - @state() - private _data: Array = []; + private _propertyEditorSchemaAlias?: string | null = null; private _workspaceContext?: typeof UMB_DATA_TYPE_WORKSPACE_CONTEXT.TYPE; private _modalContext?: UmbModalManagerContext; @@ -58,95 +52,45 @@ export class UmbDataTypeDetailsWorkspaceViewEditElement } this.observe(this._workspaceContext.data, (dataType) => { - if (!dataType) return; - - // TODO: handle if model is not of the type wanted. this._dataType = dataType; + }); - if (!this._dataType.propertyEditorUiAlias) { - if (this._dataType.propertyEditorAlias) { - // Get the property editor UI alias from the property editor alias: - this.observe( - umbExtensionsRegistry.getByTypeAndAlias('propertyEditorSchema', this._dataType.propertyEditorAlias), - (propertyEditorSchema) => { - // TODO: show error. We have stored a propertyEditorSchemaAlias and can't find the PropertyEditorSchema in the registry. - if (!propertyEditorSchema) return; - this._setPropertyEditorUiAlias(propertyEditorSchema.meta.defaultPropertyEditorUiAlias ?? undefined); - }, - '_observePropertyEditorSchemaForDefaultUI' - ); - } else { - this._setPropertyEditorUiAlias(undefined); - } - } else { - this._setPropertyEditorUiAlias(this._dataType.propertyEditorUiAlias); - } + this.observe(this._workspaceContext.propertyEditorUiAlias, (value) => { + this._propertyEditorUiAlias = value; + }); - if (this._dataType.values && this._dataType.values !== this._data) { - this._data = this._dataType.values; - } + this.observe(this._workspaceContext.propertyEditorSchemaAlias, (value) => { + this._propertyEditorSchemaAlias = value; + }); + + this.observe(this._workspaceContext.propertyEditorUiName, (value) => { + this._propertyEditorUiName = value; + }); + + this.observe(this._workspaceContext.propertyEditorUiIcon, (value) => { + this._propertyEditorUiIcon = value; }); } - private _setPropertyEditorUiAlias(value: string | undefined) { - const oldValue = this._propertyEditorUiAlias; - if (oldValue !== value) { - this._propertyEditorUiAlias = value; - this._observePropertyEditorUI(value || undefined); - } - } - - private _observePropertyEditorUI(propertyEditorUiAlias?: string) { - if (!propertyEditorUiAlias) { - this._propertyEditorUiName = this._propertyEditorUiIcon = this._propertyEditorUiAlias = undefined; - this.removeControllerByAlias('_observePropertyEditorUI'); - return; - } - - // remove the '_observePropertyEditorSchemaForDefaultUI' controller, as we do not want to observe for default value anymore: - this.removeControllerByAlias('_observePropertyEditorSchemaForDefaultUI'); - - this.observe( - umbExtensionsRegistry.getByTypeAndAlias('propertyEditorUi', propertyEditorUiAlias), - (propertyEditorUI) => { - // TODO: show error. We have stored a PropertyEditorUIAlias and can't find the PropertyEditorUI in the registry. - if (!propertyEditorUI) return; - - this._propertyEditorUiName = propertyEditorUI?.meta.label ?? propertyEditorUI?.name ?? ''; - this._propertyEditorUiAlias = propertyEditorUI?.alias ?? ''; - this._propertyEditorUiIcon = propertyEditorUI?.meta.icon ?? ''; - this._propertyEditorSchemaAlias = propertyEditorUI?.meta.propertyEditorSchemaAlias ?? ''; - - this._workspaceContext?.setPropertyEditorSchemaAlias(this._propertyEditorSchemaAlias); - }, - '_observePropertyEditorUI' - ); - } - private _openPropertyEditorUIPicker() { - if (!this._dataType) return; - const modalContext = this._modalContext?.open(UMB_PROPERTY_EDITOR_UI_PICKER_MODAL, { selection: this._propertyEditorUiAlias ? [this._propertyEditorUiAlias] : [], }); modalContext?.onSubmit().then(({ selection }) => { - this._selectPropertyEditorUI(selection[0]); + this._workspaceContext?.setPropertyEditorUiAlias(selection[0]); }); } - private _selectPropertyEditorUI(propertyEditorUiAlias: string | undefined) { - this._workspaceContext?.setPropertyEditorUiAlias(propertyEditorUiAlias); - } - render() { return html` - ${this._renderPropertyEditorUI()} - ${this._renderConfig()} + ${this.#renderPropertyEditorReference()} + ${this.#renderPropertyEditorConfig()} `; } - private _renderPropertyEditorUI() { + #renderPropertyEditorReference() { + console.log(this._dataType); return html` ${this._propertyEditorUiAlias && this._propertyEditorSchemaAlias @@ -178,18 +122,10 @@ export class UmbDataTypeDetailsWorkspaceViewEditElement `; } - private _renderConfig() { - return html` - ${this._propertyEditorSchemaAlias && this._propertyEditorUiAlias - ? html` - - - - ` - : nothing} - `; + #renderPropertyEditorConfig() { + return html` + + `; } static styles = [