Merge remote-tracking branch 'origin/main' into feature/global-search

This commit is contained in:
JesmoDev
2024-03-22 10:56:12 +01:00
19 changed files with 407 additions and 147 deletions

View File

@@ -42,7 +42,7 @@ playwright/.cache/
storybook-static/
# API Docs
api-docs/
ui-api/
custom-elements.json

View File

@@ -0,0 +1,3 @@
# Manifest Picker Example
This example demonstrates the Manifest picker input UI.

View File

@@ -0,0 +1,15 @@
import type { ManifestDashboard } from '@umbraco-cms/backoffice/extension-registry';
export const manifests: Array<ManifestDashboard> = [
{
type: 'dashboard',
name: 'Example Manifest Picker Dashboard',
alias: 'example.dashboard.manifestPicker',
element: () => import('./manifest-picker-dashboard.js'),
weight: 1000,
meta: {
label: 'Manifest Picker example',
pathname: 'example-manifest-picker',
},
},
];

View File

@@ -0,0 +1,97 @@
import { css, html, customElement, state, when, nothing } from '@umbraco-cms/backoffice/external/lit';
import { umbExtensionsRegistry } from '@umbraco-cms/backoffice/extension-registry';
import { UmbInputManifestElement } from '@umbraco-cms/backoffice/components';
import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element';
import { UmbTextStyles } from '@umbraco-cms/backoffice/style';
import { UUISelectEvent } from '@umbraco-cms/backoffice/external/uui';
@customElement('example-manifest-picker-dashboard')
export class ExampleManifestPickerDashboard extends UmbLitElement {
#options: Array<Option> = [];
@state()
private _selectedExtensionType: string = 'collectionView';
@state()
private _selectedManifest: string = '';
constructor() {
super();
this.observe(umbExtensionsRegistry.extensions, (extensions) => {
const types = [...new Set(extensions.map((x) => x.type))];
this.#options = types.sort().map((x) => ({
name: x,
value: x,
selected: x === this._selectedExtensionType,
}));
});
}
#onSelect(event: UUISelectEvent) {
this._selectedManifest = '';
this._selectedExtensionType = event.target.value as string;
}
#onChange(event: { target: UmbInputManifestElement }) {
const selectedManifest = event.target.value;
this._selectedManifest = selectedManifest?.value ?? '';
}
render() {
return html`
<uui-box>
<umb-property-layout label="Select a extension type...">
<uui-select
slot="editor"
label="Select type..."
placeholder="Select type..."
.options=${this.#options}
@change=${this.#onSelect}></uui-select>
</umb-property-layout>
${when(
this._selectedExtensionType,
() => html`
<umb-property-layout label="Selected extension type" description=${this._selectedExtensionType}>
<div slot="editor">
<umb-input-manifest
.extensionType=${this._selectedExtensionType}
@change=${this.#onChange}></umb-input-manifest>
</div>
</umb-property-layout>
`,
() => nothing,
)}
${when(
this._selectedManifest,
() => html`
<umb-property-layout label="Selected manifest">
<div slot="editor">
<code>${this._selectedManifest}</code>
</div>
</umb-property-layout>
`,
() => nothing,
)}
</uui-box>
`;
}
static styles = [
UmbTextStyles,
css`
:host {
display: block;
padding: var(--uui-size-layout-1);
}
`,
];
}
export default ExampleManifestPickerDashboard;
declare global {
interface HTMLElementTagNameMap {
'example-manifest-picker-dashboard': ExampleManifestPickerDashboard;
}
}

View File

@@ -7,5 +7,8 @@ import type { DataTypeChangeModeModel } from './DataTypeChangeModeModel';
export type DatatypeConfigurationResponseModel = {
canBeChanged: DataTypeChangeModeModel;
documentListViewId: string;
mediaListViewId: string;
memberListViewId: string;
};

View File

@@ -21,6 +21,9 @@ export class MemberResource {
*/
public static getFilterMember({
memberTypeId,
memberGroupName,
isApproved,
isLockedOut,
orderBy = 'username',
orderDirection,
filter,
@@ -28,6 +31,9 @@ export class MemberResource {
take = 100,
}: {
memberTypeId?: string,
memberGroupName?: string,
isApproved?: boolean,
isLockedOut?: boolean,
orderBy?: string,
orderDirection?: DirectionModel,
filter?: string,
@@ -39,6 +45,9 @@ export class MemberResource {
url: '/umbraco/management/api/v1/filter/member',
query: {
'memberTypeId': memberTypeId,
'memberGroupName': memberGroupName,
'isApproved': isApproved,
'isLockedOut': isLockedOut,
'orderBy': orderBy,
'orderDirection': orderDirection,
'filter': filter,

View File

@@ -209,6 +209,17 @@ export class PackageResource {
});
}
/**
* @returns any Success
* @throws ApiError
*/
public static getPackageManifestPublic(): CancelablePromise<Array<PackageManifestResponseModel>> {
return __request(OpenAPI, {
method: 'GET',
url: '/umbraco/management/api/v1/package/manifest/public',
});
}
/**
* @returns PagedPackageMigrationStatusResponseModel Success
* @throws ApiError

View File

@@ -44,6 +44,7 @@ export class SecurityResource {
responseHeader: 'Umb-Notifications',
errors: {
400: `Bad Request`,
401: `The resource is protected and requires an authentication token`,
},
});
}
@@ -86,7 +87,6 @@ export class SecurityResource {
mediaType: 'application/json',
errors: {
400: `Bad Request`,
401: `The resource is protected and requires an authentication token`,
404: `Not Found`,
},
});

View File

@@ -618,6 +618,7 @@ export class UserResource {
},
errors: {
401: `The resource is protected and requires an authentication token`,
404: `Not Found`,
},
});
}
@@ -800,7 +801,6 @@ export class UserResource {
responseHeader: 'Umb-Notifications',
errors: {
400: `Bad Request`,
401: `The resource is protected and requires an authentication token`,
404: `Not Found`,
},
});

View File

@@ -10,6 +10,7 @@ import { UmbDeleteEvent } from '@umbraco-cms/backoffice/event';
import { UMB_DOCUMENT_TYPE_PICKER_MODAL } from '@umbraco-cms/backoffice/document-type';
import { UmbSorterController } from '@umbraco-cms/backoffice/sorter';
/** TODO: Look into sending a "change" event when there is a change, rather than create, delete, and change event. Make sure it doesn't break move for RTE/List/Grid. [LI] */
@customElement('umb-input-block-type')
export class UmbInputBlockTypeElement<
BlockType extends UmbBlockTypeWithGroupKey = UmbBlockTypeWithGroupKey,

View File

@@ -20,6 +20,7 @@ export * from './input-date/index.js';
export * from './input-dropdown/index.js';
export * from './input-eye-dropper/index.js';
export * from './input-list-base/index.js';
export * from './input-manifest/index.js';
export * from './input-multi-url/index.js';
export * from './input-number-range/index.js';
export * from './input-radio-button-list/index.js';

View File

@@ -1,18 +1,14 @@
import { UmbDocumentTypePickerContext } from '../../../documents/document-types/components/input-document-type/input-document-type.context.js';
import { UmbMediaTypePickerContext } from '../../../media/media-types/components/input-media-type/input-media-type.context.js';
import { UmbMemberTypePickerContext } from '../../../members/member-type/components/input-member-type/input-member-type.context.js';
import { html, customElement, property, css } from '@umbraco-cms/backoffice/external/lit';
import { FormControlMixin } from '@umbraco-cms/backoffice/external/uui';
import { UmbChangeEvent } from '@umbraco-cms/backoffice/event';
import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element';
import { UmbDocumentTypeDetailRepository } from '@umbraco-cms/backoffice/document-type';
import { UmbChangeEvent, UmbSelectionChangeEvent } from '@umbraco-cms/backoffice/event';
import { UmbMediaTypeDetailRepository } from '@umbraco-cms/backoffice/media-type';
import { UmbMemberTypeDetailRepository } from '@umbraco-cms/backoffice/member-type';
import { UMB_ITEM_PICKER_MODAL, UMB_MODAL_MANAGER_CONTEXT } from '@umbraco-cms/backoffice/modal';
import { UMB_DOCUMENT_TYPE_PICKER_MODAL, UmbDocumentTypeDetailRepository } from '@umbraco-cms/backoffice/document-type';
import { UMB_MEMBER_TYPE_PICKER_MODAL, UmbMemberTypeDetailRepository } from '@umbraco-cms/backoffice/member-type';
import { UMB_ITEM_PICKER_MODAL, UMB_MEDIA_TYPE_PICKER_MODAL, UMB_MODAL_MANAGER_CONTEXT } from '@umbraco-cms/backoffice/modal';
import type { UmbContentTypeModel } from '@umbraco-cms/backoffice/content-type';
import type { UmbDetailRepositoryBase } from '@umbraco-cms/backoffice/repository';
import type { UmbItemPickerModel } from '@umbraco-cms/backoffice/modal';
import type { UmbPickerInputContext } from '@umbraco-cms/backoffice/picker-input';
import type { UmbItemPickerModel, UmbModalToken, UmbPickerModalValue } from '@umbraco-cms/backoffice/modal';
export type UmbContentTypePropertyValue = {
label: string;
@@ -22,7 +18,7 @@ export type UmbContentTypePropertyValue = {
type UmbInputContentTypePropertyConfigurationItem = {
item: UmbItemPickerModel;
pickerContext(): UmbPickerInputContext<any>;
pickerModal(): UmbModalToken<any, UmbPickerModalValue>;
pickableFilter?(item: any): boolean;
repository(): UmbDetailRepositoryBase<any>;
systemProperties?: Array<UmbItemPickerModel>;
@@ -43,22 +39,19 @@ export class UmbInputContentTypePropertyElement extends FormControlMixin(UmbLitE
label: this.localize.term('content_documentType'),
description: this.localize.term('defaultdialogs_selectContentType'),
value: 'documentTypes',
icon: 'icon-document',
},
pickerContext: () => new UmbDocumentTypePickerContext(this),
pickerModal: () => UMB_DOCUMENT_TYPE_PICKER_MODAL,
pickableFilter: (docType) => !docType.isElement,
repository: () => new UmbDocumentTypeDetailRepository(this),
systemProperties: [
{
label: this.localize.term('content_documentType'),
description: 'contentTypeAlias',
value: 'contentTypeAlias',
},
{ label: this.localize.term('content_createDate'), description: 'createDate', value: 'createDate' },
{ label: this.localize.term('content_createBy'), description: 'owner', value: 'owner' },
{ label: this.localize.term('content_isPublished'), description: 'published', value: 'published' },
{ label: this.localize.term('general_sort'), description: 'sortOrder', value: 'sortOrder' },
{ label: this.localize.term('content_updateDate'), description: 'updateDate', value: 'updateDate' },
{ label: this.localize.term('content_updatedBy'), description: 'updater', value: 'updater' },
{ label: this.localize.term('content_documentType'), description: 'contentTypeAlias', value: 'contentTypeAlias', icon: 'icon-settings' },
{ label: this.localize.term('content_createDate'), description: 'createDate', value: 'createDate', icon: 'icon-settings' },
{ label: this.localize.term('content_createBy'), description: 'owner', value: 'owner', icon: 'icon-settings' },
{ label: this.localize.term('content_isPublished'), description: 'published', value: 'published', icon: 'icon-settings' },
{ label: this.localize.term('general_sort'), description: 'sortOrder', value: 'sortOrder', icon: 'icon-settings' },
{ label: this.localize.term('content_updateDate'), description: 'updateDate', value: 'updateDate', icon: 'icon-settings' },
{ label: this.localize.term('content_updatedBy'), description: 'updater', value: 'updater', icon: 'icon-settings' },
],
},
elementTypes: {
@@ -66,8 +59,9 @@ export class UmbInputContentTypePropertyElement extends FormControlMixin(UmbLitE
label: this.localize.term('create_elementType'),
description: this.localize.term('content_nestedContentSelectElementTypeModalTitle'),
value: 'elementTypes',
icon: 'icon-plugin',
},
pickerContext: () => new UmbDocumentTypePickerContext(this),
pickerModal: () => UMB_DOCUMENT_TYPE_PICKER_MODAL,
pickableFilter: (docType) => docType.isElement,
repository: () => new UmbDocumentTypeDetailRepository(this),
systemProperties: [
@@ -83,20 +77,17 @@ export class UmbInputContentTypePropertyElement extends FormControlMixin(UmbLitE
label: this.localize.term('content_mediatype'),
description: this.localize.term('defaultdialogs_selectMediaType'),
value: 'mediaTypes',
icon: 'icon-picture',
},
pickerContext: () => new UmbMediaTypePickerContext(this),
pickerModal: () => UMB_MEDIA_TYPE_PICKER_MODAL,
repository: () => new UmbMediaTypeDetailRepository(this),
systemProperties: [
{
label: this.localize.term('content_documentType'),
description: 'contentTypeAlias',
value: 'contentTypeAlias',
},
{ label: this.localize.term('content_createDate'), description: 'createDate', value: 'createDate' },
{ label: this.localize.term('content_createBy'), description: 'owner', value: 'owner' },
{ label: this.localize.term('general_sort'), description: 'sortOrder', value: 'sortOrder' },
{ label: this.localize.term('content_updateDate'), description: 'updateDate', value: 'updateDate' },
{ label: this.localize.term('content_updatedBy'), description: 'updater', value: 'updater' },
{ label: this.localize.term('content_documentType'), description: 'contentTypeAlias', value: 'contentTypeAlias', icon: 'icon-settings' },
{ label: this.localize.term('content_createDate'), description: 'createDate', value: 'createDate', icon: 'icon-settings' },
{ label: this.localize.term('content_createBy'), description: 'owner', value: 'owner', icon: 'icon-settings' },
{ label: this.localize.term('general_sort'), description: 'sortOrder', value: 'sortOrder', icon: 'icon-settings' },
{ label: this.localize.term('content_updateDate'), description: 'updateDate', value: 'updateDate', icon: 'icon-settings' },
{ label: this.localize.term('content_updatedBy'), description: 'updater', value: 'updater', icon: 'icon-settings' },
],
},
memberTypes: {
@@ -104,19 +95,16 @@ export class UmbInputContentTypePropertyElement extends FormControlMixin(UmbLitE
label: this.localize.term('content_membertype'),
description: this.localize.term('defaultdialogs_selectMemberType'),
value: 'memberTypes',
icon: 'icon-user',
},
pickerContext: () => new UmbMemberTypePickerContext(this),
pickerModal: () => UMB_MEMBER_TYPE_PICKER_MODAL,
repository: () => new UmbMemberTypeDetailRepository(this),
systemProperties: [
{
label: this.localize.term('content_documentType'),
description: 'contentTypeAlias',
value: 'contentTypeAlias',
},
{ label: this.localize.term('content_createDate'), description: 'createDate', value: 'createDate' },
{ label: this.localize.term('general_email'), description: 'email', value: 'email' },
{ label: this.localize.term('content_updateDate'), description: 'updateDate', value: 'updateDate' },
{ label: this.localize.term('general_username'), description: 'username', value: 'username' },
{ label: this.localize.term('content_documentType'), description: 'contentTypeAlias', value: 'contentTypeAlias', icon: 'icon-settings' },
{ label: this.localize.term('content_createDate'), description: 'createDate', value: 'createDate', icon: 'icon-settings' },
{ label: this.localize.term('general_email'), description: 'email', value: 'email', icon: 'icon-settings' },
{ label: this.localize.term('content_updateDate'), description: 'updateDate', value: 'updateDate', icon: 'icon-settings' },
{ label: this.localize.term('general_username'), description: 'username', value: 'username', icon: 'icon-settings' },
],
},
};
@@ -195,28 +183,33 @@ export class UmbInputContentTypePropertyElement extends FormControlMixin(UmbLitE
const config = this.#configuration[configKey];
if (!config) return;
const pickerContext = config.pickerContext();
const pickerModal = config.pickerModal();
pickerContext.max = 1;
await pickerContext.openPicker({
hideTreeRoot: true,
multiple: false,
pickableFilter: config.pickableFilter,
const pickerContext = this.#modalManager?.open(this, pickerModal, {
data: {
hideTreeRoot: true,
multiple: false,
pickableFilter: config.pickableFilter,
},
});
const selectedItems = pickerContext.getSelection();
// NOTE: We listen for the selection change event to submit the picker.
// This is to enforce a single selection and progress to the next modal.
pickerContext?.addEventListener(UmbSelectionChangeEvent.TYPE, pickerContext.submit);
const pickerValue = await pickerContext?.onSubmit();
const selectedItems = pickerValue?.selection ?? [];
if (selectedItems.length === 0) return;
const repository = config.repository();
const { data } = await repository.requestByUnique(selectedItems[0]);
const { data } = await repository.requestByUnique(selectedItems[0] ?? '');
if (!data) return;
this.#openPropertyPicker(data, config.systemProperties);
this.#openPropertyPicker(data, config);
}
async #openPropertyPicker(contentType?: UmbContentTypeModel, systemProperties?: Array<UmbItemPickerModel>) {
async #openPropertyPicker(contentType: UmbContentTypeModel, config: UmbInputContentTypePropertyConfigurationItem) {
if (!contentType) return;
if (!this.#modalManager) return;
@@ -225,9 +218,10 @@ export class UmbInputContentTypePropertyElement extends FormControlMixin(UmbLitE
label: property.name,
value: property.alias,
description: property.alias,
icon: config.item.icon,
})) ?? [];
const items = [...(systemProperties ?? []), ...properties];
const items = [...(config.systemProperties ?? []), ...properties];
const modalContext = this.#modalManager.open(this, UMB_ITEM_PICKER_MODAL, {
data: {
@@ -243,7 +237,7 @@ export class UmbInputContentTypePropertyElement extends FormControlMixin(UmbLitE
this.selectedProperty = {
label: modalValue.label,
alias: modalValue.value,
isSystem: systemProperties?.some((property) => property.value === modalValue.value) ?? false,
isSystem: config.systemProperties?.some((property) => property.value === modalValue.value) ?? false,
};
this.dispatchEvent(new UmbChangeEvent());

View File

@@ -0,0 +1 @@
export * from './input-manifest.element.js';

View File

@@ -0,0 +1,85 @@
import { html, customElement, property, css } from '@umbraco-cms/backoffice/external/lit';
import { UmbChangeEvent } from '@umbraco-cms/backoffice/event';
import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element';
import { UMB_ITEM_PICKER_MODAL, UMB_MODAL_MANAGER_CONTEXT } from '@umbraco-cms/backoffice/modal';
import { umbExtensionsRegistry } from '@umbraco-cms/backoffice/extension-registry';
@customElement('umb-input-manifest')
export class UmbInputManifestElement extends UmbLitElement {
#extensions: Array<typeof umbExtensionsRegistry.MANIFEST_TYPES> = [];
#extensionType?: string;
@property({ type: String, attribute: 'extension-type' })
public set extensionType(value: string | undefined) {
this.#extensionType = value;
this.#observeExtensions();
}
public get extensionType(): string | undefined {
return this.#extensionType;
}
@property({ attribute: false })
value?: typeof UMB_ITEM_PICKER_MODAL.VALUE;
@property({ type: Number })
max = Infinity;
#observeExtensions() {
if (!this.#extensionType) return;
this.observe(umbExtensionsRegistry.byType(this.#extensionType), (extensions) => {
this.#extensions = extensions.sort((a, b) => a.type.localeCompare(b.type) || a.alias.localeCompare(b.alias));
});
}
async #onClick() {
const modalManager = await this.getContext(UMB_MODAL_MANAGER_CONTEXT);
const modalContext = modalManager.open(this, UMB_ITEM_PICKER_MODAL, {
data: {
headline: `${this.localize.term('general_choose')}...`,
items: this.#extensions
.filter((ext) => ext.type === this.extensionType)
.map((ext) => ({
label: ext.name,
value: ext.alias,
description: ext.alias,
icon: (ext as any).meta?.icon, // HACK: Ugly way to get the icon. [LK]
})),
},
});
const modalValue = await modalContext.onSubmit();
if (!modalValue) return;
this.value = modalValue;
this.dispatchEvent(new UmbChangeEvent());
}
render() {
return html`
<uui-button
label=${this.localize.term('general_choose')}
look="placeholder"
color="default"
@click=${this.#onClick}></uui-button>
`;
}
static styles = [
css`
:host {
display: flex;
flex-direction: column;
}
`,
];
}
export default UmbInputManifestElement;
declare global {
interface HTMLElementTagNameMap {
'umb-input-manifest': UmbInputManifestElement;
}
}

View File

@@ -1,7 +1,8 @@
import type { UmbCollectionColumnConfiguration } from '../../../../../collection/types.js';
import { html, customElement, property, repeat, css, state } from '@umbraco-cms/backoffice/external/lit';
import { html, customElement, property, repeat, css, state, nothing, when } from '@umbraco-cms/backoffice/external/lit';
import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element';
import { UmbPropertyValueChangeEvent } from '@umbraco-cms/backoffice/property-editor';
import { UmbTextStyles } from '@umbraco-cms/backoffice/style';
import type { UmbInputContentTypePropertyElement } from '@umbraco-cms/backoffice/components';
import type { UmbPropertyEditorConfigCollection } from '@umbraco-cms/backoffice/property-editor';
import type { UmbPropertyEditorUiElement } from '@umbraco-cms/backoffice/extension-registry';
@@ -15,6 +16,9 @@ export class UmbPropertyEditorUICollectionViewColumnConfigurationElement
extends UmbLitElement
implements UmbPropertyEditorUiElement
{
// TODO: [LK] Add sorting.
@property({ type: Array })
value?: Array<UmbCollectionColumnConfiguration> = [];
@@ -24,7 +28,7 @@ export class UmbPropertyEditorUICollectionViewColumnConfigurationElement
@state()
private _field?: UmbInputContentTypePropertyElement['selectedProperty'];
#onChange(e: CustomEvent) {
#onAdd(e: CustomEvent) {
const element = e.target as UmbInputContentTypePropertyElement;
if (!element.selectedProperty) return;
@@ -49,6 +53,15 @@ export class UmbPropertyEditorUICollectionViewColumnConfigurationElement
this.dispatchEvent(new UmbPropertyValueChangeEvent());
}
#onChangeLabel(e: UUIInputEvent, configuration: UmbCollectionColumnConfiguration) {
this.value = this.value?.map(
(config): UmbCollectionColumnConfiguration =>
config.alias === configuration.alias ? { ...config, header: e.target.value as string } : config,
);
this.dispatchEvent(new UmbPropertyValueChangeEvent());
}
#onRemove(unique: string) {
const newValue: Array<UmbCollectionColumnConfiguration> = [];
@@ -60,105 +73,86 @@ export class UmbPropertyEditorUICollectionViewColumnConfigurationElement
this.dispatchEvent(new UmbPropertyValueChangeEvent());
}
#onHeaderChange(e: UUIInputEvent, configuration: UmbCollectionColumnConfiguration) {
this.value = this.value?.map(
(config): UmbCollectionColumnConfiguration =>
config.alias === configuration.alias ? { ...config, header: e.target.value as string } : config,
);
this.dispatchEvent(new UmbPropertyValueChangeEvent());
}
#onTemplateChange(e: UUIInputEvent, configuration: UmbCollectionColumnConfiguration) {
this.value = this.value?.map(
(config): UmbCollectionColumnConfiguration =>
config.alias === configuration.alias ? { ...config, nameTemplate: e.target.value as string } : config,
);
this.dispatchEvent(new UmbPropertyValueChangeEvent());
}
render() {
if (!this.value) return nothing;
return html`
${this.#renderTable()}
<div id="layout-wrapper">
${repeat(
this.value,
(column) => column.alias,
(column) => this.#renderField(column),
)}
</div>
<umb-input-content-type-property
document-types
media-types
@change=${this.#onChange}></umb-input-content-type-property>
@change=${this.#onAdd}></umb-input-content-type-property>
`;
}
#renderTable() {
if (!this.value?.length) return;
#renderField(column: UmbCollectionColumnConfiguration) {
return html`
<uui-table>
<uui-table-row>
<uui-table-head-cell style="width:0"></uui-table-head-cell>
<uui-table-head-cell>Alias</uui-table-head-cell>
<uui-table-head-cell>Header</uui-table-head-cell>
<uui-table-head-cell>Template</uui-table-head-cell>
<uui-table-head-cell style="width:0"></uui-table-head-cell>
</uui-table-row>
${repeat(
this.value,
(configuration) => configuration.alias,
(configuration) => html`
<uui-table-row>
<uui-table-cell><uui-icon name="icon-navigation"></uui-icon></uui-table-cell>
${configuration.isSystem === 1
? this.#renderSystemFieldRow(configuration)
: this.#renderCustomFieldRow(configuration)}
<uui-table-cell>
<uui-button
label=${this.localize.term('general_remove')}
look="secondary"
@click=${() => this.#onRemove(configuration.alias)}></uui-button>
</uui-table-cell>
</uui-table-row>
`,
)}
</uui-table>
`;
}
<div class="layout-item">
<uui-icon name="icon-navigation"></uui-icon>
#renderSystemFieldRow(configuration: UmbCollectionColumnConfiguration) {
return html`
<uui-table-cell><strong>${configuration.alias}</strong> <small>(system field)</small></uui-table-cell>
<uui-table-cell>${configuration.header}</uui-table-cell>
<uui-table-cell></uui-table-cell>
`;
}
#renderCustomFieldRow(configuration: UmbCollectionColumnConfiguration) {
return html`
<uui-table-cell><strong>${configuration.alias}</strong></uui-table-cell>
<uui-table-cell>
<uui-input
label="header"
.value=${configuration.header ?? ''}
required
@change=${(e: UUIInputEvent) => this.#onHeaderChange(e, configuration)}></uui-input>
</uui-table-cell>
<uui-table-cell>
label="label"
placeholder="Enter a label..."
.value=${column.header ?? ''}
@change=${(e: UUIInputEvent) => this.#onChangeLabel(e, column)}></uui-input>
<div class="alias">
<code>${column.alias}</code>
</div>
<uui-input
disabled
label="template"
.value=${configuration.nameTemplate ?? ''}
@change=${(e: UUIInputEvent) => this.#onTemplateChange(e, configuration)}></uui-input>
</uui-table-cell>
placeholder="Enter a name template..."
.value=${column.nameTemplate ?? ''}></uui-input>
<div class="actions">
<uui-button
label=${this.localize.term('general_remove')}
look="secondary"
@click=${() => this.#onRemove(column.alias)}></uui-button>
</div>
</div>
`;
}
static styles = [
UmbTextStyles,
css`
:host {
#layout-wrapper {
display: flex;
flex-direction: column;
gap: var(--uui-size-space-1);
gap: 1px;
margin-bottom: var(--uui-size-1);
}
uui-input {
width: 100%;
.layout-item {
background-color: var(--uui-color-surface-alt);
display: flex;
align-items: center;
gap: var(--uui-size-6);
padding: var(--uui-size-3) var(--uui-size-6);
}
.layout-item > uui-icon {
flex: 0 0 var(--uui-size-6);
}
.layout-item > uui-input,
.layout-item > .alias {
flex: 1;
}
.layout-item > .actions {
flex: 0 0 auto;
display: flex;
justify-content: flex-end;
}
`,
];

View File

@@ -1,10 +1,10 @@
import './components/index.js';
export * from './workspace/index.js';
export * from './components/index.js';
export * from './repository/index.js';
export * from './entity.js';
export * from './tree/index.js';
export * from './modal/member-type-picker-modal.token.js';
export type { UmbMemberTypeDetailModel } from './types.js';

View File

@@ -1,8 +1,11 @@
import type { UmbBlockTypeBaseModel } from '@umbraco-cms/backoffice/block-type';
import { UmbInputBlockTypeElement } from '@umbraco-cms/backoffice/block-type';
import type { UmbPropertyEditorUiElement } from '@umbraco-cms/backoffice/extension-registry';
import { html, customElement, property } from '@umbraco-cms/backoffice/external/lit';
import type { UmbPropertyEditorConfigCollection } from '@umbraco-cms/backoffice/property-editor';
import { html, customElement, property, state } from '@umbraco-cms/backoffice/external/lit';
import {
UmbPropertyValueChangeEvent,
type UmbPropertyEditorConfigCollection,
} from '@umbraco-cms/backoffice/property-editor';
import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element';
/**
@@ -14,19 +17,37 @@ export class UmbPropertyEditorUIBlockRteBlockConfigurationElement
implements UmbPropertyEditorUiElement
{
@property({ attribute: false })
value: UmbBlockTypeBaseModel[] = [];
public set value(value: UmbBlockTypeBaseModel[]) {
this._value = value ?? [];
}
public get value() {
return this._value;
}
@state()
private _value: UmbBlockTypeBaseModel[] = [];
@property({ type: Object, attribute: false })
public config?: UmbPropertyEditorConfigCollection;
#onCreate(e: CustomEvent) {
const key = e.detail.contentElementTypeKey;
this.value = [...this._value, { contentElementTypeKey: key, forceHideContentEditorInOverlay: false }];
this.dispatchEvent(new UmbPropertyValueChangeEvent());
}
#onChange(e: CustomEvent) {
this.value = (e.target as UmbInputBlockTypeElement).value;
this.dispatchEvent(new UmbPropertyValueChangeEvent());
}
render() {
return UmbInputBlockTypeElement
? html`<umb-input-block-type
entity-type="block-rte-type"
.value=${this.value}
@change=${(e: Event) => {
this.value = (e.target as UmbInputBlockTypeElement).value;
}}></umb-input-block-type>`
@create=${this.#onCreate}
@change=${this.#onChange}
@delete=${this.#onChange}></umb-input-block-type>`
: '';
}
}

View File

@@ -1,6 +1,8 @@
import { UmbTextStyles } from '@umbraco-cms/backoffice/style';
import { customElement, html, property } from '@umbraco-cms/backoffice/external/lit';
import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element';
import type { UUIInputEvent } from '@umbraco-cms/backoffice/external/uui';
import { UmbPropertyValueChangeEvent } from '@umbraco-cms/backoffice/property-editor';
/**
* @element umb-property-editor-ui-tiny-mce-dimensions-configuration
@@ -10,17 +12,28 @@ export class UmbPropertyEditorUITinyMceDimensionsConfigurationElement extends Um
@property({ type: Object })
value: { width?: number; height?: number } = {};
#onChangeWidth(e: UUIInputEvent) {
this.value = { ...this.value, width: Number(e.target.value as string) };
this.dispatchEvent(new UmbPropertyValueChangeEvent());
}
#onChangeHeight(e: UUIInputEvent) {
this.value = { ...this.value, height: Number(e.target.value as string) };
this.dispatchEvent(new UmbPropertyValueChangeEvent());
}
render() {
return html`<uui-input
type="number"
label=${this.localize.term('general_width')}
placeholder=${this.localize.term('general_width')}
@change=${this.#onChangeWidth}
.value=${this.value?.width}></uui-input>
x
<uui-input
type="number"
label=${this.localize.term('general_height')}
placeholder=${this.localize.term('general_height')}
@change=${this.#onChangeHeight}
.value=${this.value?.height}></uui-input>
pixels`;
}

View File

@@ -1,6 +1,8 @@
import { customElement, html, property } from '@umbraco-cms/backoffice/external/lit';
import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element';
import type { UmbPropertyEditorUiElement } from '@umbraco-cms/backoffice/extension-registry';
import { UmbPropertyValueChangeEvent } from '@umbraco-cms/backoffice/property-editor';
import type { UUIInputEvent } from '@umbraco-cms/backoffice/external/uui';
/**
* @element umb-property-editor-ui-tiny-mce-maximagesize-configuration
@@ -13,8 +15,18 @@ export class UmbPropertyEditorUITinyMceMaxImageSizeConfigurationElement
@property({ type: Number })
value: number = 0;
#onChange(e: UUIInputEvent) {
this.value = Number(e.target.value as string);
this.dispatchEvent(new UmbPropertyValueChangeEvent());
}
render() {
return html`<uui-input label="Max size" type="number" placeholder="Max size" .value=${this.value}></uui-input>`;
return html`<uui-input
label="Max size"
type="number"
placeholder="Max size"
@change=${this.#onChange}
.value=${this.value}></uui-input>`;
}
}