simple block list editor implementation
This commit is contained in:
@@ -183,6 +183,7 @@ export const data: Array<DocumentResponseModel> = [
|
||||
{
|
||||
udi: '1234',
|
||||
contentTypeKey: '4f68ba66-6fb2-4778-83b8-6ab4ca3a7c5c',
|
||||
elementProperty: 'Hello world',
|
||||
},
|
||||
],
|
||||
settingsData: [],
|
||||
|
||||
@@ -24,12 +24,24 @@ export class UmbPropertyEditorUIBlockListBlockElement extends UmbLitElement impl
|
||||
|
||||
#context = new UmbBlockContext(this);
|
||||
|
||||
@state()
|
||||
_contentUdi?: string;
|
||||
|
||||
@state()
|
||||
_label = '';
|
||||
|
||||
@state()
|
||||
_workspacePath?: string;
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.observe(this.#context.workspacePath, (workspacePath) => {
|
||||
this._workspacePath = workspacePath;
|
||||
});
|
||||
this.observe(this.#context.contentUdi, (contentUdi) => {
|
||||
this._contentUdi = contentUdi;
|
||||
});
|
||||
this.observe(this.#context.label, (label) => {
|
||||
this._label = label;
|
||||
});
|
||||
@@ -65,6 +77,11 @@ export class UmbPropertyEditorUIBlockListBlockElement extends UmbLitElement impl
|
||||
return html`
|
||||
${this.#renderRefBlock()}
|
||||
<uui-action-bar>
|
||||
${this._workspacePath
|
||||
? html`<uui-button label="edit" compact href=${this._workspacePath + 'edit/' + this._contentUdi}>
|
||||
<uui-icon name="icon-edit"></uui-icon>
|
||||
</uui-button>`
|
||||
: ''}
|
||||
<uui-button label="delete" compact @click=${this.#requestDelete}>
|
||||
<uui-icon name="icon-remove"></uui-icon>
|
||||
</uui-button>
|
||||
|
||||
@@ -15,7 +15,12 @@ import '../../components/block-list-block/index.js';
|
||||
import { buildUdi } from '@umbraco-cms/backoffice/utils';
|
||||
import { UmbId } from '@umbraco-cms/backoffice/id';
|
||||
import type { NumberRangeValueType } from '@umbraco-cms/backoffice/models';
|
||||
import { UMB_MODAL_MANAGER_CONTEXT_TOKEN, UmbModalManagerContext } from '@umbraco-cms/backoffice/modal';
|
||||
import {
|
||||
UMB_MODAL_MANAGER_CONTEXT_TOKEN,
|
||||
UMB_WORKSPACE_MODAL,
|
||||
UmbModalManagerContext,
|
||||
UmbModalRouteRegistrationController,
|
||||
} from '@umbraco-cms/backoffice/modal';
|
||||
import { UmbChangeEvent } from '@umbraco-cms/backoffice/event';
|
||||
|
||||
export interface UmbBlockListLayoutModel extends UmbBlockLayoutBaseModel {}
|
||||
@@ -78,6 +83,9 @@ export class UmbPropertyEditorUIBlockListElement extends UmbLitElement implement
|
||||
@state()
|
||||
_layouts: Array<UmbBlockLayoutBaseModel> = [];
|
||||
|
||||
@state()
|
||||
_workspacePath?: string;
|
||||
|
||||
#modalContext?: UmbModalManagerContext;
|
||||
|
||||
constructor() {
|
||||
|
||||
@@ -19,6 +19,9 @@ export class UmbBlockContext<
|
||||
#label = new UmbStringState('');
|
||||
public readonly label = this.#label.asObservable();
|
||||
|
||||
#workspacePath = new UmbStringState(undefined);
|
||||
public readonly workspacePath = this.#workspacePath.asObservable();
|
||||
|
||||
#blockType = new UmbObjectState<BlockType | undefined>(undefined);
|
||||
public readonly blockType = this.#blockType.asObservable();
|
||||
public readonly blockTypeContentElementTypeKey = this.#blockType.asObservablePart((x) => x?.contentElementTypeKey);
|
||||
@@ -51,6 +54,13 @@ export class UmbBlockContext<
|
||||
// Consume block manager:
|
||||
this.consumeContext(UMB_BLOCK_MANAGER_CONTEXT, (manager) => {
|
||||
this.#manager = manager;
|
||||
this.observe(
|
||||
manager.workspacePath,
|
||||
(workspacePath) => {
|
||||
this.#workspacePath.next(workspacePath);
|
||||
},
|
||||
'observeWorkspacePath',
|
||||
);
|
||||
this.#observeBlockType();
|
||||
this.#observeData();
|
||||
});
|
||||
|
||||
@@ -2,11 +2,12 @@ import type { UmbBlockLayoutBaseModel, UmbBlockDataType } from '..//types.js';
|
||||
import { UmbContextToken } from '@umbraco-cms/backoffice/context-api';
|
||||
import { UmbContextBase } from '@umbraco-cms/backoffice/class-api';
|
||||
import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api';
|
||||
import { UmbArrayState } from '@umbraco-cms/backoffice/observable-api';
|
||||
import { UmbArrayState, UmbStringState } from '@umbraco-cms/backoffice/observable-api';
|
||||
import { UmbDocumentTypeDetailRepository } from '@umbraco-cms/backoffice/document-type';
|
||||
import { DocumentTypeResponseModel } from '@umbraco-cms/backoffice/backend-api';
|
||||
import { getKeyFromUdi } from '@umbraco-cms/backoffice/utils';
|
||||
import { UmbBlockTypeBase } from '@umbraco-cms/backoffice/block';
|
||||
import { UMB_WORKSPACE_MODAL, UmbModalRouteRegistrationController } from '@umbraco-cms/backoffice/modal';
|
||||
|
||||
// TODO: We are using backend model here, I think we should get our own model:
|
||||
type ElementTypeModel = DocumentTypeResponseModel;
|
||||
@@ -18,6 +19,9 @@ export class UmbBlockManagerContext<
|
||||
//
|
||||
#contentTypeRepository = new UmbDocumentTypeDetailRepository(this);
|
||||
|
||||
#workspacePath = new UmbStringState(undefined);
|
||||
workspacePath = this.#workspacePath.asObservable();
|
||||
|
||||
#contentTypes = new UmbArrayState(<Array<ElementTypeModel>>[], (x) => x.id);
|
||||
public readonly contentTypes = this.#contentTypes.asObservable();
|
||||
|
||||
@@ -53,6 +57,18 @@ export class UmbBlockManagerContext<
|
||||
|
||||
constructor(host: UmbControllerHost) {
|
||||
super(host, UMB_BLOCK_MANAGER_CONTEXT);
|
||||
|
||||
// TODO: Make specific modal token that requires data.
|
||||
// IDEA: Make a Workspace registration controller that can be used to register a workspace, which does both edit and create?.
|
||||
new UmbModalRouteRegistrationController(this, UMB_WORKSPACE_MODAL)
|
||||
.addAdditionalPath('block')
|
||||
.onSetup(() => {
|
||||
return { data: { entityType: 'block', preset: {} }, modal: { size: 'medium' } };
|
||||
})
|
||||
.observeRouteBuilder((routeBuilder) => {
|
||||
const newPath = routeBuilder({});
|
||||
this.#workspacePath.next(newPath);
|
||||
});
|
||||
}
|
||||
|
||||
async ensureContentType(id?: string) {
|
||||
@@ -99,14 +115,14 @@ export class UmbBlockManagerContext<
|
||||
return this.#settings.asObservablePart((source) => source.find((x) => x.udi === udi));
|
||||
}
|
||||
|
||||
updateLayout(contentUdi: string, layoutData: Partial<BlockLayoutType>) {
|
||||
return this.#layouts.updateOne(contentUdi, layoutData);
|
||||
setOneLayout(layoutData: BlockLayoutType) {
|
||||
return this.#layouts.appendOne(layoutData);
|
||||
}
|
||||
updateContent(udi: string, contentData: Partial<UmbBlockDataType>) {
|
||||
return this.#contents.updateOne(udi, contentData);
|
||||
setOneContent(contentData: UmbBlockDataType) {
|
||||
this.#contents.appendOne(contentData);
|
||||
}
|
||||
updateSettings(udi: string, settingsData: Partial<UmbBlockDataType>) {
|
||||
return this.#settings.updateOne(udi, settingsData);
|
||||
setOneSettings(settingsData: UmbBlockDataType) {
|
||||
this.#settings.appendOne(settingsData);
|
||||
}
|
||||
|
||||
createBlock(layoutEntry: BlockLayoutType, contentElementTypeKey: string) {
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { manifests as modalManifests } from './modals/manifests.js';
|
||||
import { manifests as workspaceManifests } from './workspace/manifests.js';
|
||||
|
||||
export const manifests = [...modalManifests];
|
||||
export const manifests = [...modalManifests, ...workspaceManifests];
|
||||
|
||||
@@ -21,13 +21,17 @@ export class UmbBlockWorkspaceContext<LayoutDataType extends UmbBlockLayoutBaseM
|
||||
//
|
||||
readonly workspaceAlias: string = 'Umb.Workspace.Block';
|
||||
|
||||
#blockManager?: typeof UMB_BLOCK_MANAGER_CONTEXT.TYPE;
|
||||
|
||||
#entityType: string;
|
||||
#contentUdi: string;
|
||||
|
||||
#isNew = new UmbBooleanState<boolean | undefined>(undefined);
|
||||
readonly isNew = this.#isNew.asObservable();
|
||||
|
||||
#layout = new UmbObjectState<LayoutDataType | undefined>(undefined);
|
||||
readonly layout = this.#layout.asObservable();
|
||||
//readonly unique = this.#layout.asObservablePart((x) => x?.contentUdi);
|
||||
readonly contentUdi = this.#layout.asObservablePart((x) => x?.contentUdi);
|
||||
|
||||
readonly content = new UmbBlockElementManager(this);
|
||||
@@ -37,16 +41,21 @@ export class UmbBlockWorkspaceContext<LayoutDataType extends UmbBlockLayoutBaseM
|
||||
// TODO: Get the name of the contentElementType..
|
||||
#label = new UmbStringState<string | undefined>(undefined);
|
||||
readonly name = this.#label.asObservable();
|
||||
readonly unique = this.#layout.asObservablePart((data) => data?.contentUdi);
|
||||
|
||||
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, 'Umb.Workspace.Block');
|
||||
this.#entityType = workspaceArgs.manifest.meta?.entityType;
|
||||
|
||||
this.observe(this.contentUdi, (contentUdi) => {
|
||||
this.#contentUdi = contentUdi ?? '';
|
||||
});
|
||||
}
|
||||
|
||||
async load(unique: string) {
|
||||
this.consumeContext(UMB_BLOCK_MANAGER_CONTEXT, (context) => {
|
||||
this.#blockManager = context;
|
||||
|
||||
this.observe(
|
||||
context.layoutOf(unique),
|
||||
(layoutData) => {
|
||||
@@ -146,9 +155,20 @@ export class UmbBlockWorkspaceContext<LayoutDataType extends UmbBlockLayoutBaseM
|
||||
}
|
||||
|
||||
async save() {
|
||||
if (!this.#layout.value) return;
|
||||
if (!this.#layout.value || !this.#blockManager) return;
|
||||
|
||||
// TODO: Save the block type, but only in non-live-editing mode.
|
||||
const layoutData = this.#layout.value;
|
||||
this.#blockManager.setOneLayout(this.#layout.value);
|
||||
|
||||
const contentData = this.content.getData();
|
||||
if (contentData) {
|
||||
this.#blockManager.setOneContent(contentData);
|
||||
}
|
||||
const settingsData = this.settings.getData();
|
||||
if (settingsData) {
|
||||
this.#blockManager.setOneSettings(settingsData);
|
||||
}
|
||||
|
||||
this.saveComplete(this.#layout.value);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user