Block Element Manager
This commit is contained in:
@@ -6,6 +6,7 @@ export interface UmbBlockLayoutBaseModel {
|
||||
export interface UmbBlockDataType {
|
||||
udi: string;
|
||||
contentTypeKey: string;
|
||||
[key: string]: unknown;
|
||||
}
|
||||
|
||||
export interface UmbBlockValueType<BlockLayoutType extends UmbBlockLayoutBaseModel> {
|
||||
|
||||
@@ -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<UmbBlockDataType | undefined>(undefined);
|
||||
#getDataPromise = new Promise<void>((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<ReturnType = unknown>(propertyAlias: string) {
|
||||
await this.#getDataPromise;
|
||||
|
||||
return this.#data.asObservablePart((data) => data?.[propertyAlias] as ReturnType);
|
||||
}
|
||||
|
||||
async getPropertyValue<ReturnType = unknown>(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;
|
||||
@@ -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<UmbBlockElementPropertyDatasetContext>(
|
||||
'UmbPropertyDatasetContext',
|
||||
);
|
||||
@@ -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<string | undefined> = '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<ReturnType = unknown>(propertyAlias: string) {
|
||||
return await this.#elementManager.propertyValueByAlias<ReturnType>(propertyAlias);
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO: Write proper JSDocs here.
|
||||
*/
|
||||
async setPropertyValue(propertyAlias: string, value: unknown) {
|
||||
return this.#elementManager.setPropertyValue(propertyAlias, value);
|
||||
}
|
||||
}
|
||||
@@ -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<LayoutDataType extends UmbBlockLayoutBaseModel = UmbBlockLayoutBaseModel>
|
||||
extends UmbEditableWorkspaceContextBase<never, LayoutDataType>
|
||||
implements UmbInvariantableWorkspaceContextInterface
|
||||
extends UmbEditableWorkspaceContextBase<UmbBlockWorkspaceContext>
|
||||
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<boolean | undefined>(undefined);
|
||||
readonly isNew = this.#isNew.asObservable();
|
||||
|
||||
#layout = new UmbObjectState<LayoutDataType | undefined>(undefined);
|
||||
readonly layout = this.#layout.asObservable();
|
||||
|
||||
#content = new UmbObjectState<UmbBlockDataType | undefined>(undefined);
|
||||
readonly content = this.#content.asObservable();
|
||||
// Consider not storing this here:
|
||||
//#content = new UmbObjectState<UmbBlockDataType | undefined>(undefined);
|
||||
//readonly content = this.#content.asObservable();
|
||||
|
||||
#settings = new UmbObjectState<UmbBlockDataType | undefined>(undefined);
|
||||
readonly settings = this.#settings.asObservable();
|
||||
// Consider not storing this here:
|
||||
//#settings = new UmbObjectState<UmbBlockDataType | undefined>(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<string | undefined>(undefined);
|
||||
@@ -38,14 +47,10 @@ export class UmbBlockWorkspaceContext<LayoutDataType extends UmbBlockLayoutBaseM
|
||||
|
||||
constructor(host: UmbControllerHost, workspaceArgs: { manifest: ManifestWorkspace }) {
|
||||
// TODO: We don't need a repo here, so maybe we should not require this of the UmbEditableWorkspaceContextBase
|
||||
super(host, workspaceArgs.manifest.alias, undefined as never);
|
||||
super(host, UMB_BLOCK_WORKSPACE_CONTEXT);
|
||||
this.#entityType = workspaceArgs.manifest.meta?.entityType;
|
||||
}
|
||||
|
||||
createPropertyDatasetContext(host: UmbControllerHost): UmbPropertyDatasetContext {
|
||||
return new UmbInvariantWorkspacePropertyDatasetContext(host, this);
|
||||
}
|
||||
|
||||
async load(unique: string) {
|
||||
this.consumeContext(UMB_BLOCK_MANAGER_CONTEXT, (context) => {
|
||||
this.observe(context.value, (value) => {
|
||||
@@ -64,6 +69,8 @@ export class UmbBlockWorkspaceContext<LayoutDataType extends UmbBlockLayoutBaseM
|
||||
}
|
||||
|
||||
async create(contentElementTypeId: string) {
|
||||
//
|
||||
// TODO: Condense this into some kind of create method?
|
||||
const key = UmbId.new();
|
||||
const contentUdi = `umb://block/${key}`;
|
||||
const layout: UmbBlockLayoutBaseModel = {
|
||||
@@ -73,11 +80,21 @@ export class UmbBlockWorkspaceContext<LayoutDataType extends UmbBlockLayoutBaseM
|
||||
udi: contentUdi,
|
||||
contentTypeKey: contentElementTypeId,
|
||||
};
|
||||
this.content.setData(content);
|
||||
|
||||
// TODO: If we have Settings dedicated to this block type, we initiate them here:
|
||||
|
||||
this.setIsNew(true);
|
||||
this.#layout.next(layout as LayoutDataType);
|
||||
}
|
||||
|
||||
getIsNew() {
|
||||
return this.#isNew.value;
|
||||
}
|
||||
setIsNew(value: boolean): void {
|
||||
this.#isNew.next(value);
|
||||
}
|
||||
|
||||
getData() {
|
||||
return this.#layout.getValue();
|
||||
}
|
||||
@@ -93,17 +110,18 @@ export class UmbBlockWorkspaceContext<LayoutDataType extends UmbBlockLayoutBaseM
|
||||
getName() {
|
||||
return 'block name content element type here...';
|
||||
}
|
||||
setName(name: string | undefined) {
|
||||
alert('You cannot set a name of a block-type.');
|
||||
|
||||
// NOTICE currently the property methods are for layout, but this could be seen as wrong, we might need to dedicate a data manager for the layout as well.
|
||||
|
||||
async propertyValueByAlias<propertyAliasType extends keyof LayoutDataType>(propertyAlias: propertyAliasType) {
|
||||
return this.#layout.asObservablePart(
|
||||
(layout) => layout?.[propertyAlias as keyof LayoutDataType] as LayoutDataType[propertyAliasType],
|
||||
);
|
||||
}
|
||||
|
||||
async propertyValueByAlias<ReturnType = unknown>(propertyAlias: string) {
|
||||
return this.#layout.asObservablePart((data) => data?.[propertyAlias as keyof BlockTypeData] as ReturnType);
|
||||
}
|
||||
|
||||
getPropertyValue<ReturnType = unknown>(propertyAlias: string) {
|
||||
getPropertyValue<propertyAliasType extends keyof LayoutDataType>(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) {
|
||||
|
||||
@@ -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';
|
||||
@@ -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<ManifestWorkspaceAction> = [
|
||||
export const manifests: Array<ManifestTypes> = [
|
||||
{
|
||||
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<ManifestWorkspaceAction> = [
|
||||
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',
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
@@ -11,6 +11,12 @@ export abstract class UmbEditableWorkspaceContextBase<RepositoryType, WorkspaceD
|
||||
{
|
||||
public readonly host: UmbControllerHost;
|
||||
public readonly workspaceAlias: string;
|
||||
/*
|
||||
*
|
||||
* HER SKAL DU FORTSÆTTE I MORGEN, Det vil kræve ændringer i mange workspace contexts.
|
||||
*
|
||||
*/
|
||||
// TODO: Get rid of the repository, as it prevents flexibility needed for Blocks and other workspaces that like to borrow the features of EditableWorkspace but not using one repository.
|
||||
// TODO: I think we should get rid of the repository from this one.
|
||||
public readonly repository: RepositoryType;
|
||||
|
||||
|
||||
@@ -41,7 +41,7 @@ export class UmbDocumentWorkspaceContext
|
||||
}
|
||||
|
||||
readonly unique = this.#currentData.asObservablePart((data) => 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?.
|
||||
|
||||
Reference in New Issue
Block a user