Merge branch 'v14/fix/create-block-in-workspace' into v14/feature/block-grid-validation

This commit is contained in:
Niels Lyngsø
2024-08-27 13:43:39 +02:00
7 changed files with 78 additions and 19 deletions

View File

@@ -133,9 +133,30 @@ export class UmbBlockGridEntriesContext
blockGroups: this._manager?.getBlockGroups() ?? [],
openClipboard: routingInfo.view === 'clipboard',
originData: { index: index, areaKey: this.#areaKey, parentUnique: this.#parentUnique },
createBlockInWorkspace: true,
},
};
})
.onSubmit(async (value, data) => {
if (value?.create && data) {
const created = await this.create(
value.create.contentElementTypeKey,
// We can parse an empty object, cause the rest will be filled in by others.
{} as any,
data.originData as UmbBlockGridWorkspaceOriginData,
);
if (created) {
this.insert(
created.layout,
created.content,
created.settings,
data.originData as UmbBlockGridWorkspaceOriginData,
);
} else {
throw new Error('Failed to create block');
}
}
})
.observeRouteBuilder((routeBuilder) => {
// TODO: Does it make any sense that this is a state? Check usage and confirm. [NL]
this._catalogueRouteBuilderState.setValue(routeBuilder);

View File

@@ -4,7 +4,6 @@ import type { UmbBlockRteLayoutModel, UmbBlockRteTypeModel } from '../types.js';
import {
UMB_BLOCK_RTE_WORKSPACE_MODAL,
type UmbBlockRteWorkspaceOriginData,
type UmbBlockRteWorkspaceData,
} from '../workspace/block-rte-workspace.modal-token.js';
import { UMB_BLOCK_RTE_MANAGER_CONTEXT } from './block-rte-manager.context-token.js';
import { UmbBooleanState } from '@umbraco-cms/backoffice/observable-api';
@@ -41,9 +40,30 @@ export class UmbBlockRteEntriesContext extends UmbBlockEntriesContext<
blockGroups: [],
openClipboard: routingInfo.view === 'clipboard',
originData: {},
createBlockInWorkspace: true,
},
};
})
.onSubmit(async (value, data) => {
if (value?.create && data) {
const created = await this.create(
value.create.contentElementTypeKey,
// We can parse an empty object, cause the rest will be filled in by others.
{} as any,
data.originData as UmbBlockRteWorkspaceOriginData,
);
if (created) {
this.insert(
created.layout,
created.content,
created.settings,
data.originData as UmbBlockRteWorkspaceOriginData,
);
} else {
throw new Error('Failed to create block');
}
}
})
.observeRouteBuilder((routeBuilder) => {
this._catalogueRouteBuilderState.setValue(routeBuilder);
});
@@ -114,10 +134,10 @@ export class UmbBlockRteEntriesContext extends UmbBlockEntriesContext<
async create(
contentElementTypeKey: string,
partialLayoutEntry?: Omit<UmbBlockRteLayoutModel, 'contentUdi'>,
modalData?: UmbBlockRteWorkspaceData,
originData?: UmbBlockRteWorkspaceOriginData,
) {
await this._retrieveManager;
return this._manager?.create(contentElementTypeKey, partialLayoutEntry, modalData);
return this._manager?.create(contentElementTypeKey, partialLayoutEntry, originData);
}
// insert Block?
@@ -126,10 +146,10 @@ export class UmbBlockRteEntriesContext extends UmbBlockEntriesContext<
layoutEntry: UmbBlockRteLayoutModel,
content: UmbBlockDataType,
settings: UmbBlockDataType | undefined,
modalData: UmbBlockRteWorkspaceData,
originData: UmbBlockRteWorkspaceOriginData,
) {
await this._retrieveManager;
return this._manager?.insert(layoutEntry, content, settings, modalData) ?? false;
return this._manager?.insert(layoutEntry, content, settings, originData) ?? false;
}
// create Block?

View File

@@ -1,5 +1,5 @@
import type { UmbBlockRteLayoutModel, UmbBlockRteTypeModel } from '../types.js';
import type { UmbBlockRteWorkspaceData } from '../index.js';
import type { UmbBlockRteWorkspaceOriginData } from '../index.js';
import type { UmbBlockDataType } from '../../block/types.js';
import type { Editor } from '@umbraco-cms/backoffice/external/tinymce';
import { UmbBlockManagerContext } from '@umbraco-cms/backoffice/block';
@@ -36,7 +36,7 @@ export class UmbBlockRteManagerContext<
partialLayoutEntry?: Omit<BlockLayoutType, 'contentUdi'>,
// This property is used by some implementations, but not used in this.
// eslint-disable-next-line @typescript-eslint/no-unused-vars
originData?: UmbBlockRteWorkspaceData,
originData?: UmbBlockRteWorkspaceOriginData,
) {
const data = super.createBlockData(contentElementTypeKey, partialLayoutEntry);
@@ -57,13 +57,13 @@ export class UmbBlockRteManagerContext<
layoutEntry: BlockLayoutType,
content: UmbBlockDataType,
settings: UmbBlockDataType | undefined,
modalData: UmbBlockRteWorkspaceData,
originData: UmbBlockRteWorkspaceOriginData,
) {
if (!this.#editor) return false;
this._layouts.appendOne(layoutEntry);
this.insertBlockData(layoutEntry, content, settings, modalData);
this.insertBlockData(layoutEntry, content, settings, originData);
if (layoutEntry.displayInline) {
this.#editor.selection.setContent(

View File

@@ -21,7 +21,7 @@ export class UmbBlockTypeCardElement extends UmbLitElement {
(x) => x.unique,
);
@property({ type: String, attribute: false })
@property({ type: String })
href?: string;
@property({ type: String, attribute: false })

View File

@@ -148,6 +148,10 @@ export abstract class UmbBlockManagerContext<
getContentTypeNameOf(contentTypeKey: string) {
return this.#contentTypes.getValue().find((x) => x.unique === contentTypeKey)?.name;
}
getContentTypeHasProperties(contentTypeKey: string) {
const properties = this.#contentTypes.getValue().find((x) => x.unique === contentTypeKey)?.properties;
return properties ? properties.length > 0 : false;
}
blockTypeOf(contentTypeKey: string) {
return this.#blockTypes.asObservablePart((source) =>
source.find((x) => x.contentElementTypeKey === contentTypeKey),

View File

@@ -1,6 +1,10 @@
import { UMB_BLOCK_WORKSPACE_MODAL } from '../../workspace/index.js';
import type { UmbBlockTypeGroup, UmbBlockTypeWithGroupKey } from '@umbraco-cms/backoffice/block-type';
import type { UmbBlockCatalogueModalData, UmbBlockCatalogueModalValue } from '@umbraco-cms/backoffice/block';
import {
UMB_BLOCK_MANAGER_CONTEXT,
type UmbBlockCatalogueModalData,
type UmbBlockCatalogueModalValue,
} from '@umbraco-cms/backoffice/block';
import { css, html, customElement, state, repeat, nothing } from '@umbraco-cms/backoffice/external/lit';
import type { UUIInputEvent } from '@umbraco-cms/backoffice/external/uui';
import { UMB_MODAL_CONTEXT, UmbModalBaseElement } from '@umbraco-cms/backoffice/modal';
@@ -14,8 +18,7 @@ export class UmbBlockCatalogueModalElement extends UmbModalBaseElement<
UmbBlockCatalogueModalData,
UmbBlockCatalogueModalValue
> {
//
private _search = '';
#search = '';
private _groupedBlocks: Array<{ name?: string; blocks: Array<UmbBlockTypeWithGroupKey> }> = [];
@@ -28,6 +31,9 @@ export class UmbBlockCatalogueModalElement extends UmbModalBaseElement<
@state()
private _filtered: Array<{ name?: string; blocks: Array<UmbBlockTypeWithGroupKey> }> = [];
@state()
_manager?: typeof UMB_BLOCK_MANAGER_CONTEXT.TYPE;
constructor() {
super();
@@ -49,6 +55,10 @@ export class UmbBlockCatalogueModalElement extends UmbModalBaseElement<
});
}
});
this.consumeContext(UMB_BLOCK_MANAGER_CONTEXT, (manager) => {
this._manager = manager;
});
}
override connectedCallback() {
@@ -71,10 +81,10 @@ export class UmbBlockCatalogueModalElement extends UmbModalBaseElement<
}
#updateFiltered() {
if (this._search.length === 0) {
if (this.#search.length === 0) {
this._filtered = this._groupedBlocks;
} else {
const search = this._search.toLowerCase();
const search = this.#search.toLowerCase();
this._filtered = this._groupedBlocks.map((group) => {
return { ...group, blocks: group.blocks.filter((block) => block.label?.toLocaleLowerCase().includes(search)) };
});
@@ -82,7 +92,7 @@ export class UmbBlockCatalogueModalElement extends UmbModalBaseElement<
}
#onSearch(e: UUIInputEvent) {
this._search = e.target.value as string;
this.#search = e.target.value as string;
this.#updateFiltered();
}
@@ -98,7 +108,7 @@ export class UmbBlockCatalogueModalElement extends UmbModalBaseElement<
override render() {
return html`
<umb-body-layout headline="${this.localize.term('blockEditor_addBlock')}">
${this.#renderViews()} ${this._openClipboard ? this.#renderClipboard() : this.#renderCreateEmpty()}
${this.#renderViews()}${this.#renderMain()}
<div slot="actions">
<uui-button label=${this.localize.term('general_close')} @click=${this._rejectModal}></uui-button>
<uui-button
@@ -111,6 +121,10 @@ export class UmbBlockCatalogueModalElement extends UmbModalBaseElement<
`;
}
#renderMain() {
return this._manager ? (this._openClipboard ? this.#renderClipboard() : this.#renderCreateEmpty()) : nothing;
}
#renderClipboard() {
return html`Clipboard`;
}
@@ -140,7 +154,7 @@ export class UmbBlockCatalogueModalElement extends UmbModalBaseElement<
.backgroundColor=${block.backgroundColor}
.contentElementTypeKey=${block.contentElementTypeKey}
@open=${() => this.#chooseBlock(block.contentElementTypeKey)}
?href=${this._workspacePath
.href=${this._workspacePath && this._manager!.getContentTypeHasProperties(block.contentElementTypeKey)
? `${this._workspacePath}create/${block.contentElementTypeKey}`
: undefined}>
</umb-block-type-card>

View File

@@ -332,7 +332,7 @@ export class UmbPropertyElement extends UmbLitElement {
if ('checkValidity' in this._element) {
const dataPath = this.dataPath;
this.#controlValidator = new UmbFormControlValidator(this, this._element as any, dataPath);
// We trust blindly that the dataPath is available at this stage. [NL]
// We trust blindly that the dataPath will be present at this stage and not arrive later than this moment. [NL]
if (dataPath) {
this.#validationMessageBinder = new UmbBindServerValidationToFormControl(
this,