diff --git a/src/Umbraco.Web.UI.Client/src/packages/block/block/types.ts b/src/Umbraco.Web.UI.Client/src/packages/block/block/types.ts index 1883faa267..8956368b42 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/block/block/types.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/block/block/types.ts @@ -6,6 +6,7 @@ export interface UmbBlockLayoutBaseModel { export interface UmbBlockDataType { udi: string; contentTypeKey: string; + [key: string]: unknown; } export interface UmbBlockValueType { diff --git a/src/Umbraco.Web.UI.Client/src/packages/block/block/workspace/block-element-manager.ts b/src/Umbraco.Web.UI.Client/src/packages/block/block/workspace/block-element-manager.ts new file mode 100644 index 0000000000..933a196a99 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/packages/block/block/workspace/block-element-manager.ts @@ -0,0 +1,81 @@ +import { UmbBlockDataType } from '../types.js'; +import { UmbBlockElementPropertyDatasetContext } from './block-element-property-dataset.context.js'; +import { UmbContentTypePropertyStructureManager } from '@umbraco-cms/backoffice/content-type'; +import { UmbObjectState, UmbObserverController } from '@umbraco-cms/backoffice/observable-api'; +import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api'; +import { UmbBaseController } from '@umbraco-cms/backoffice/class-api'; +import { UmbDocumentTypeDetailRepository } from '@umbraco-cms/backoffice/document-type'; + +export class UmbBlockElementManager extends UmbBaseController { + // + #data = new UmbObjectState(undefined); + #getDataPromise = new Promise((resolve) => { + this.#getDataResolver = resolve; + }); + #getDataResolver!: () => void; + + readonly unique = this.#data.asObservablePart((data) => data?.udi); + readonly contentTypeId = this.#data.asObservablePart((data) => data?.contentTypeKey); + + readonly structure; + + constructor(host: UmbControllerHost) { + // TODO: Get Workspace Alias via Manifest. + super(host); + + this.structure = new UmbContentTypePropertyStructureManager(this, new UmbDocumentTypeDetailRepository(this)); + + new UmbObserverController(this, this.contentTypeId, (id) => this.structure.loadType(id)); + } + + setData(data: UmbBlockDataType) { + this.#data.next(data); + this.#getDataResolver(); + } + + getData() { + return this.#data.getValue(); + } + + getEntityId() { + return this.getData()?.udi; + } + + getEntityType() { + return 'element'; + } + + getContentTypeId() { + return this.getData()?.contentTypeKey; + } + + async propertyValueByAlias(propertyAlias: string) { + await this.#getDataPromise; + + return this.#data.asObservablePart((data) => data?.[propertyAlias] as ReturnType); + } + + async getPropertyValue(propertyAlias: string) { + await this.#getDataPromise; + + return this.#data.getValue()?.[propertyAlias] as ReturnType; + } + + async setPropertyValue(alias: string, value: unknown) { + await this.#getDataPromise; + + this.#data.update({ [alias]: value }); + } + + public createPropertyDatasetContext(host: UmbControllerHost) { + return new UmbBlockElementPropertyDatasetContext(host, this); + } + + public destroy(): void { + this.#data.destroy(); + this.structure.destroy(); + super.destroy(); + } +} + +export default UmbBlockElementManager; diff --git a/src/Umbraco.Web.UI.Client/src/packages/block/block/workspace/block-element-property-dataset.context-token.ts b/src/Umbraco.Web.UI.Client/src/packages/block/block/workspace/block-element-property-dataset.context-token.ts new file mode 100644 index 0000000000..584fff6a95 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/packages/block/block/workspace/block-element-property-dataset.context-token.ts @@ -0,0 +1,6 @@ +import { UmbBlockElementPropertyDatasetContext } from './block-element-property-dataset.context.js'; +import { UmbContextToken } from '@umbraco-cms/backoffice/context-api'; + +export const UMB_BLOCK_ELEMENT_PROPERTY_DATASET_CONTEXT = new UmbContextToken( + 'UmbPropertyDatasetContext', +); diff --git a/src/Umbraco.Web.UI.Client/src/packages/block/block/workspace/block-element-property-dataset.context.ts b/src/Umbraco.Web.UI.Client/src/packages/block/block/workspace/block-element-property-dataset.context.ts new file mode 100644 index 0000000000..9f83a366ac --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/packages/block/block/workspace/block-element-property-dataset.context.ts @@ -0,0 +1,50 @@ +import { UmbBlockElementManager } from './block-element-manager.js'; +import { UMB_BLOCK_ELEMENT_PROPERTY_DATASET_CONTEXT } from './block-element-property-dataset.context-token.js'; +import { UMB_PROPERTY_DATASET_CONTEXT, UmbPropertyDatasetContext } from '@umbraco-cms/backoffice/property'; +import { type UmbControllerHost } from '@umbraco-cms/backoffice/controller-api'; +import { UmbBaseController } from '@umbraco-cms/backoffice/class-api'; +import { UmbVariantId } from '@umbraco-cms/backoffice/variant'; +import { type Observable } from '@umbraco-cms/backoffice/external/rxjs'; + +export class UmbBlockElementPropertyDatasetContext extends UmbBaseController implements UmbPropertyDatasetContext { + #elementManager: UmbBlockElementManager; + + // default data: + + getVariantId() { + return UmbVariantId.CreateInvariant(); + } + getEntityType() { + return this.#elementManager.getEntityType(); + } + getUnique() { + return this.#elementManager.getEntityId(); + } + + getName(): string | undefined { + return 'TODO: get label'; + } + readonly name: Observable = 'TODO: get label observable' as any; + + constructor(host: UmbControllerHost, elementManager: UmbBlockElementManager) { + // The controller alias, is a very generic name cause we want only one of these for this controller host. + super(host, UMB_PROPERTY_DATASET_CONTEXT.toString()); + this.#elementManager = elementManager; + + this.provideContext(UMB_BLOCK_ELEMENT_PROPERTY_DATASET_CONTEXT, this); + } + + /** + * TODO: Write proper JSDocs here. + */ + async propertyValueByAlias(propertyAlias: string) { + return await this.#elementManager.propertyValueByAlias(propertyAlias); + } + + /** + * TODO: Write proper JSDocs here. + */ + async setPropertyValue(propertyAlias: string, value: unknown) { + return this.#elementManager.setPropertyValue(propertyAlias, value); + } +} diff --git a/src/Umbraco.Web.UI.Client/src/packages/block/block/workspace/block-workspace.context.ts b/src/Umbraco.Web.UI.Client/src/packages/block/block/workspace/block-workspace.context.ts index 4fb2a70109..a70eeea9a8 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/block/block/workspace/block-workspace.context.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/block/block/workspace/block-workspace.context.ts @@ -1,12 +1,11 @@ import type { UmbBlockLayoutBaseModel, UmbBlockDataType } from '../types.js'; -import { UmbPropertyDatasetContext } from '@umbraco-cms/backoffice/property'; +import { UmbBlockElementManager } from './block-element-manager.js'; import { - UmbInvariantableWorkspaceContextInterface, UmbEditableWorkspaceContextBase, + UmbSaveableWorkspaceContextInterface, UmbWorkspaceContextInterface, - UmbInvariantWorkspacePropertyDatasetContext, } from '@umbraco-cms/backoffice/workspace'; -import { UmbObjectState, UmbStringState } from '@umbraco-cms/backoffice/observable-api'; +import { UmbBooleanState, UmbObjectState, UmbStringState } from '@umbraco-cms/backoffice/observable-api'; import { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api'; import { UmbContextToken } from '@umbraco-cms/backoffice/context-api'; import { ManifestWorkspace } from '@umbraco-cms/backoffice/extension-registry'; @@ -14,22 +13,32 @@ import { UmbId } from '@umbraco-cms/backoffice/id'; import { UMB_BLOCK_MANAGER_CONTEXT } from '@umbraco-cms/backoffice/block'; export class UmbBlockWorkspaceContext - extends UmbEditableWorkspaceContextBase - implements UmbInvariantableWorkspaceContextInterface + extends UmbEditableWorkspaceContextBase + implements UmbSaveableWorkspaceContextInterface { // Just for context token safety: public readonly IS_BLOCK_WORKSPACE_CONTEXT = true; + // + readonly workspaceAlias: string = 'Umb.Workspace.Block'; #entityType: string; + #isNew = new UmbBooleanState(undefined); + readonly isNew = this.#isNew.asObservable(); + #layout = new UmbObjectState(undefined); readonly layout = this.#layout.asObservable(); - #content = new UmbObjectState(undefined); - readonly content = this.#content.asObservable(); + // Consider not storing this here: + //#content = new UmbObjectState(undefined); + //readonly content = this.#content.asObservable(); - #settings = new UmbObjectState(undefined); - readonly settings = this.#settings.asObservable(); + // Consider not storing this here: + //#settings = new UmbObjectState(undefined); + //readonly settings = this.#settings.asObservable(); + + readonly content = new UmbBlockElementManager(this); + readonly settings = new UmbBlockElementManager(this); // TODO: Get the name of the contentElementType.. #label = new UmbStringState(undefined); @@ -38,14 +47,10 @@ export class UmbBlockWorkspaceContext { this.observe(context.value, (value) => { @@ -64,6 +69,8 @@ export class UmbBlockWorkspaceContext(propertyAlias: propertyAliasType) { + return this.#layout.asObservablePart( + (layout) => layout?.[propertyAlias as keyof LayoutDataType] as LayoutDataType[propertyAliasType], + ); } - async propertyValueByAlias(propertyAlias: string) { - return this.#layout.asObservablePart((data) => data?.[propertyAlias as keyof BlockTypeData] as ReturnType); - } - - getPropertyValue(propertyAlias: string) { + getPropertyValue(propertyAlias: propertyAliasType) { // TODO: Should be using Content, then we need a toggle or another method for getting settings. - return this.#layout.getValue()?.[propertyAlias as keyof BlockTypeData] as ReturnType; + return this.#layout.getValue()?.[propertyAlias as keyof LayoutDataType] as LayoutDataType[propertyAliasType]; } async setPropertyValue(alias: string, value: unknown) { diff --git a/src/Umbraco.Web.UI.Client/src/packages/block/block/workspace/index.ts b/src/Umbraco.Web.UI.Client/src/packages/block/block/workspace/index.ts new file mode 100644 index 0000000000..be726e193c --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/packages/block/block/workspace/index.ts @@ -0,0 +1,4 @@ +export * from './block-element-property-dataset.context-token.js'; +export * from './block-workspace.context.js'; + +export const UMB_BLOCK_WORKSPACE_ALIAS = 'Umb.Workspace.Block'; diff --git a/src/Umbraco.Web.UI.Client/src/packages/block/block/workspace/manifests.ts b/src/Umbraco.Web.UI.Client/src/packages/block/block/workspace/manifests.ts index d97b804357..85454e80de 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/block/block/workspace/manifests.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/block/block/workspace/manifests.ts @@ -1,13 +1,11 @@ -import { UMB_BLOCK_GRID_TYPE_WORKSPACE_ALIAS } from '../../block-grid/workspace/index.js'; -import { UMB_BLOCK_LIST_TYPE_WORKSPACE_ALIAS } from '../../block-list/workspace/index.js'; -import { UMB_BLOCK_RTE_TYPE_WORKSPACE_ALIAS } from '../../block-rte/workspace/index.js'; +import { UMB_BLOCK_WORKSPACE_ALIAS } from './index.js'; import { UmbSaveWorkspaceAction } from '@umbraco-cms/backoffice/workspace'; -import type { ManifestWorkspaceAction } from '@umbraco-cms/backoffice/extension-registry'; +import type { ManifestTypes } from '@umbraco-cms/backoffice/extension-registry'; -export const manifests: Array = [ +export const manifests: Array = [ { type: 'workspaceAction', - alias: 'Umb.WorkspaceAction.BlockType.Save', + alias: 'Umb.WorkspaceAction.Block.Save', name: 'Save Block Type Workspace Action', api: UmbSaveWorkspaceAction, meta: { @@ -18,12 +16,19 @@ export const manifests: Array = [ conditions: [ { alias: 'Umb.Condition.WorkspaceAlias', - oneOf: [ - UMB_BLOCK_GRID_TYPE_WORKSPACE_ALIAS, - UMB_BLOCK_LIST_TYPE_WORKSPACE_ALIAS, - UMB_BLOCK_RTE_TYPE_WORKSPACE_ALIAS, - ], + oneOf: [UMB_BLOCK_WORKSPACE_ALIAS], }, ], }, + { + type: 'workspace', + name: 'Block List Type Workspace', + alias: UMB_BLOCK_WORKSPACE_ALIAS, + element: () => import('./block-workspace.element.js'), + api: () => import('./block-workspace.context.js'), + weight: 900, + meta: { + entityType: 'block', + }, + }, ]; diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/workspace/workspace-context/editable-workspace-context-base.ts b/src/Umbraco.Web.UI.Client/src/packages/core/workspace/workspace-context/editable-workspace-context-base.ts index 181ae88f59..096de98eb8 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/workspace/workspace-context/editable-workspace-context-base.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/workspace/workspace-context/editable-workspace-context-base.ts @@ -11,6 +11,12 @@ export abstract class UmbEditableWorkspaceContextBase data?.id); - readonly documentTypeKey = this.#currentData.asObservablePart((data) => data?.contentTypeId); + readonly contentTypeId = this.#currentData.asObservablePart((data) => data?.contentTypeId); readonly variants = this.#currentData.asObservablePart((data) => data?.variants || []); readonly urls = this.#currentData.asObservablePart((data) => data?.urls || []); @@ -57,7 +57,7 @@ export class UmbDocumentWorkspaceContext this.structure = new UmbContentTypePropertyStructureManager(this, new UmbDocumentTypeDetailRepository(this)); this.splitView = new UmbWorkspaceSplitViewManager(); - new UmbObserverController(this.host, this.documentTypeKey, (id) => this.structure.loadType(id)); + new UmbObserverController(this.host, this.contentTypeId, (id) => this.structure.loadType(id)); /* TODO: Make something to ensure all variants are present in data? Seems like a good idea?.