Merge remote-tracking branch 'origin/main' into feature/global-search
This commit is contained in:
2
src/Umbraco.Web.UI.Client/.gitignore
vendored
2
src/Umbraco.Web.UI.Client/.gitignore
vendored
@@ -42,7 +42,7 @@ playwright/.cache/
|
||||
storybook-static/
|
||||
|
||||
# API Docs
|
||||
api-docs/
|
||||
ui-api/
|
||||
|
||||
custom-elements.json
|
||||
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
# Manifest Picker Example
|
||||
|
||||
This example demonstrates the Manifest picker input UI.
|
||||
15
src/Umbraco.Web.UI.Client/examples/manifest-picker/index.ts
Normal file
15
src/Umbraco.Web.UI.Client/examples/manifest-picker/index.ts
Normal 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',
|
||||
},
|
||||
},
|
||||
];
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -7,5 +7,8 @@ import type { DataTypeChangeModeModel } from './DataTypeChangeModeModel';
|
||||
|
||||
export type DatatypeConfigurationResponseModel = {
|
||||
canBeChanged: DataTypeChangeModeModel;
|
||||
documentListViewId: string;
|
||||
mediaListViewId: string;
|
||||
memberListViewId: string;
|
||||
};
|
||||
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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`,
|
||||
},
|
||||
});
|
||||
|
||||
@@ -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`,
|
||||
},
|
||||
});
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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';
|
||||
|
||||
@@ -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());
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
export * from './input-manifest.element.js';
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
`,
|
||||
];
|
||||
|
||||
@@ -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';
|
||||
|
||||
@@ -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>`
|
||||
: '';
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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`;
|
||||
}
|
||||
|
||||
@@ -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>`;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user