Feature: System and DT fields component

This commit is contained in:
Lone Iversen
2024-02-22 17:07:21 +01:00
parent d173ea9c9d
commit a68971360e
7 changed files with 224 additions and 1 deletions

View File

@@ -0,0 +1,144 @@
import type { UmbPropertyTypeModel } from '@umbraco-cms/backoffice/content-type';
import { UmbDocumentTypeDetailRepository } from '@umbraco-cms/backoffice/document-type';
import { UmbChangeEvent } from '@umbraco-cms/backoffice/event';
import { css, html, customElement, property, repeat, state, query } from '@umbraco-cms/backoffice/external/lit';
import type { UUIComboboxElement, UUIComboboxEvent } from '@umbraco-cms/backoffice/external/uui';
import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element';
import { UMB_DOCUMENT_TYPE_PICKER_MODAL, UMB_MODAL_MANAGER_CONTEXT } from '@umbraco-cms/backoffice/modal';
import { UmbStringState } from '@umbraco-cms/backoffice/observable-api';
@customElement('umb-field-dropdown-list')
export class UmbFieldDropdownListElement extends UmbLitElement {
@property({ type: String })
public value = '';
#documentTypeDetailRepository = new UmbDocumentTypeDetailRepository(this);
#unique = new UmbStringState<string>('');
readonly unique = this.#unique.asObservable();
@property({ type: String })
set documentTypeUnique(value: string) {
this.#unique.setValue(value);
}
get documentTypeUnique(): string | null | undefined {
return this.#unique.getValue();
}
@state()
private _documentTypeName?: string;
@state()
private _documentTypeIcon?: string;
@state()
private _customFields: Array<UmbPropertyTypeModel> = [];
@query('uui-combobox')
private _combobox!: UUIComboboxElement;
private _systemFields = [
{ value: 'sortOrder', name: this.localize.term('general_sort'), group: 'System Fields' },
{ value: 'updateDate', name: this.localize.term('content_updateDate'), group: 'System Fields' },
{ value: 'updater', name: this.localize.term('content_updatedBy'), group: 'System Fields' },
{ value: 'createDate', name: this.localize.term('content_createDate'), group: 'System Fields' },
{ value: 'owner', name: this.localize.term('content_createBy'), group: 'System Fields' },
{ value: 'published', name: this.localize.term('content_isPublished'), group: 'System Fields' },
{ value: 'contentTypeAlias', name: this.localize.term('content_documentType'), group: 'System Fields' },
{ value: 'email', name: this.localize.term('general_email'), group: 'System Fields' },
{ value: 'username', name: this.localize.term('general_username'), group: 'System Fields' },
];
constructor() {
super();
this.observe(this.unique, async (unique) => {
if (unique) {
const { data } = await this.#documentTypeDetailRepository.requestByUnique(unique);
this._customFields = data?.properties ?? [];
this._documentTypeName = data?.name;
this._documentTypeIcon = data?.icon;
} else {
this._customFields = [];
this._documentTypeIcon = undefined;
this._documentTypeName = undefined;
}
this.value = '';
this.dispatchEvent(new UmbChangeEvent());
});
}
#changeFieldType() {
this.consumeContext(UMB_MODAL_MANAGER_CONTEXT, async (modalManager) => {
if (modalManager) {
// TODO: Make as mode for the Picker Modal, so the click to select immediately submits the modal(And in that mode we do not want to see a Submit button).
const modalContext = modalManager.open(UMB_DOCUMENT_TYPE_PICKER_MODAL, {
data: {
hideTreeRoot: true,
multiple: false,
},
value: {
selection: this.documentTypeUnique ? [this.documentTypeUnique] : [],
},
});
const modalValue = await modalContext?.onSubmit();
this.documentTypeUnique = modalValue.selection[0] ?? '';
}
});
}
#onChange(e: UUIComboboxEvent) {
e.stopPropagation();
const alias = (e.composedPath()[0] as UUIComboboxElement).value as string;
this.value = alias;
this.dispatchEvent(new UmbChangeEvent());
}
render() {
return html`
<uui-ref-node
@open=${this.#changeFieldType}
.name=${this._documentTypeName ?? 'System Field'}
@change=${this.#onChange}>
<uui-icon name=${this._documentTypeIcon ?? 'icon-database'} slot="icon"></uui-icon>
<uui-combobox slot="tag" .value=${this.value}>
<uui-combobox-list>
${this.documentTypeUnique
? repeat(
this._customFields,
(item) => item.id,
(item) =>
html`<uui-combobox-list-option .value=${item.alias}>${item.alias}</uui-combobox-list-option>`,
)
: repeat(
this._systemFields,
(item) => item.value,
(item) =>
html`<uui-combobox-list-option .value=${item.value}>${item.name}</uui-combobox-list-option>`,
)}
</uui-combobox-list>
</uui-combobox>
</uui-ref-node>
`;
}
static styles = [
css`
uui-ref-node {
width: auto;
}
uui-combobox-list-option {
padding: calc(var(--uui-size-2, 6px) + 1px);
}
`,
];
}
export default UmbFieldDropdownListElement;
declare global {
interface HTMLElementTagNameMap {
'umb-field-dropdown-list': UmbFieldDropdownListElement;
}
}

View File

@@ -0,0 +1,50 @@
import type { Meta, StoryObj } from '@storybook/web-components';
import './field-dropdown-list.element.js';
import type { UmbFieldDropdownListElement } from './field-dropdown-list.element.js';
const meta: Meta<UmbFieldDropdownListElement> = {
title: 'Components/Inputs/Field Dropdown List',
component: 'umb-field-dropdown-list',
};
export default meta;
type Story = StoryObj<UmbFieldDropdownListElement>;
export const Overview: Story = {
args: {
options: [
{
name: 'One',
value: 'One',
},
{
name: 'Two',
value: 'Two',
},
{
name: 'Three',
value: 'Three',
},
],
},
};
export const WithSelectedValue: Story = {
args: {
options: [
{
name: 'One',
value: 'One',
},
{
name: 'Two',
value: 'Two',
selected: true,
},
{
name: 'Three',
value: 'Three',
},
],
},
};

View File

@@ -0,0 +1,20 @@
import { expect, fixture, html } from '@open-wc/testing';
import { UmbFieldDropdownListElement } from './field-dropdown-list.element.js';
import { type UmbTestRunnerWindow, defaultA11yConfig } from '@umbraco-cms/internal/test-utils';
describe('UmbInputDateElement', () => {
let element: UmbFieldDropdownListElement;
beforeEach(async () => {
element = await fixture(html` <umb-field-dropdown-list></umb-field-dropdown-list> `);
});
it('is defined with its own instance', () => {
expect(element).to.be.instanceOf(UmbFieldDropdownListElement);
});
if ((window as UmbTestRunnerWindow).__UMBRACO_TEST_RUN_A11Y_TEST) {
it('passes the a11y audit', async () => {
await expect(element).shadowDom.to.be.accessible(defaultA11yConfig);
});
}
});

View File

@@ -0,0 +1 @@
export * from './field-dropdown-list.element.js';

View File

@@ -8,6 +8,7 @@ export * from './dropdown/index.js';
export * from './empty-state/index.js';
export * from './entity-actions-bundle/index.js';
export * from './extension-slot/index.js';
export * from './field-list-input/index.js';
export * from './footer-layout/index.js';
export * from './header-app/index.js';
export * from './history/index.js';

View File

@@ -6,6 +6,8 @@ import type {
import { UmbTextStyles } from '@umbraco-cms/backoffice/style';
import { css, html, customElement, state } from '@umbraco-cms/backoffice/external/lit';
import { UmbModalBaseElement } from '@umbraco-cms/backoffice/modal';
import { UmbChangeEvent } from '@umbraco-cms/backoffice/event';
import { UmbFieldDropdownListElement } from '@umbraco-cms/backoffice/components';
@customElement('umb-templating-page-field-builder-modal')
export class UmbTemplatingPageFieldBuilderModalElement extends UmbModalBaseElement<
@@ -36,6 +38,10 @@ export class UmbTemplatingPageFieldBuilderModalElement extends UmbModalBaseEleme
/** TODO: Implement "Choose field" */
#onChangeFieldValue(e: Event) {
this._field = (e.target as UmbFieldDropdownListElement).value;
}
render() {
return html`
<umb-body-layout headline=${this.localize.term('template_insert')}>
@@ -44,7 +50,7 @@ export class UmbTemplatingPageFieldBuilderModalElement extends UmbModalBaseEleme
<uui-label for="page-field-value">
<umb-localize key="templateEditor_chooseField">Choose field</umb-localize>
</uui-label>
(Not implemented yet)
<umb-field-dropdown-list @change=${this.#onChangeFieldValue}></umb-field-dropdown-list>
<uui-label for="page-field-default-value">
<umb-localize key="templateEditor_defaultValue">Default value</umb-localize>

View File

@@ -28,6 +28,7 @@ export class UmbUmbracoNewsDashboardElement extends UmbLitElement {
render() {
return html`
<uui-box class="uui-text">
<umb-field-dropdown-list></umb-field-dropdown-list>
<h1 class="uui-h2" style="margin-top: var(--uui-size-layout-1);">Welcome, ${this.name}</h1>
<p class="uui-lead">
This is a preview version of Umbraco, where you can have a first-hand look at the new Backoffice.