register and render property actions
This commit is contained in:
@@ -0,0 +1,38 @@
|
||||
import { UUITextStyles } from '@umbraco-ui/uui';
|
||||
import { CSSResultGroup, html, LitElement } from 'lit';
|
||||
import { customElement, property, state } from 'lit/decorators.js';
|
||||
import { createExtensionElement, UmbExtensionManifestPropertyAction } from '../../core/extension';
|
||||
|
||||
@customElement('umb-node-property-action')
|
||||
export class UmbNodePropertyAction extends LitElement {
|
||||
static styles: CSSResultGroup = [
|
||||
UUITextStyles
|
||||
];
|
||||
|
||||
private _propertyAction?: UmbExtensionManifestPropertyAction;
|
||||
@property({ type: Object })
|
||||
public get propertyAction(): UmbExtensionManifestPropertyAction | undefined {
|
||||
return this._propertyAction;
|
||||
}
|
||||
public set propertyAction(value: UmbExtensionManifestPropertyAction | undefined) {
|
||||
this._propertyAction = value;
|
||||
this._createElement();
|
||||
}
|
||||
|
||||
@state()
|
||||
private _element?: HTMLElement;
|
||||
|
||||
private async _createElement () {
|
||||
if (!this.propertyAction) return;
|
||||
|
||||
try {
|
||||
this._element = await createExtensionElement(this.propertyAction);
|
||||
} catch (error) {
|
||||
// TODO: loading JS failed so we should do some nice UI. (This does only happen if extension has a js prop, otherwise we concluded that no source was needed resolved the load.)
|
||||
}
|
||||
}
|
||||
|
||||
render () {
|
||||
return html`${this._element}`;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,93 @@
|
||||
import { UUITextStyles } from '@umbraco-ui/uui';
|
||||
import { css, CSSResultGroup, html, LitElement } from 'lit';
|
||||
import { customElement, property, state } from 'lit/decorators.js';
|
||||
import { Subscription, map } from 'rxjs';
|
||||
import { UmbContextConsumerMixin } from '../../core/context';
|
||||
import { UmbExtensionManifestPropertyAction, UmbExtensionRegistry } from '../../core/extension';
|
||||
|
||||
import './node-property-action.element';
|
||||
|
||||
@customElement('umb-node-property-actions')
|
||||
export class UmbNodePropertyActions extends UmbContextConsumerMixin(LitElement) {
|
||||
static styles: CSSResultGroup = [
|
||||
UUITextStyles,
|
||||
css`
|
||||
#dropdown {
|
||||
background-color: white;
|
||||
border-radius: var(--uui-border-radius);
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
box-sizing: border-box;
|
||||
box-shadow: var(--uui-shadow-depth-3);
|
||||
min-width: 200px;
|
||||
color: black; /* Change to variable */
|
||||
}
|
||||
`,
|
||||
];
|
||||
|
||||
|
||||
@property()
|
||||
public propertyEditorUIAlias = '';
|
||||
|
||||
@state()
|
||||
private _actions: Array<UmbExtensionManifestPropertyAction> = [];
|
||||
|
||||
@state()
|
||||
private _open = false;
|
||||
|
||||
private _extensionRegistry?: UmbExtensionRegistry;
|
||||
private _subscription?: Subscription;
|
||||
|
||||
constructor () {
|
||||
super();
|
||||
|
||||
this.consumeContext('umbExtensionRegistry', (extensionRegistry: UmbExtensionRegistry) => {
|
||||
this._extensionRegistry = extensionRegistry;
|
||||
this._usePropertyActions();
|
||||
});
|
||||
}
|
||||
|
||||
private _usePropertyActions () {
|
||||
this._subscription?.unsubscribe();
|
||||
|
||||
this._extensionRegistry?.extensionsOfType('propertyAction')
|
||||
.pipe(
|
||||
map(propertyActions => propertyActions.filter(propertyAction => propertyAction.meta.propertyEditors.includes(this.propertyEditorUIAlias))))
|
||||
.subscribe(extensions => {
|
||||
this._actions = extensions;
|
||||
});
|
||||
}
|
||||
|
||||
disconnectedCallback () {
|
||||
super.disconnectedCallback();
|
||||
this._subscription?.unsubscribe();
|
||||
}
|
||||
|
||||
render () {
|
||||
return html`
|
||||
${ this._actions?.length > 0 ? html`
|
||||
<uui-popover
|
||||
.open=${this._open}
|
||||
placement="bottom-start"
|
||||
@close="${() => this._open = false}">
|
||||
<uui-button
|
||||
slot="trigger"
|
||||
look="secondary"
|
||||
label="More"
|
||||
@click="${() => this._open = true}"
|
||||
compact>
|
||||
<uui-symbol-more></uui-symbol-more>
|
||||
</uui-button>
|
||||
|
||||
<div slot="popover" id="dropdown">
|
||||
${this._actions.map(
|
||||
action => html`
|
||||
<umb-node-property-action .propertyAction=${action}></umb-node-property-action>
|
||||
`
|
||||
)}
|
||||
</div>
|
||||
</uui-popover>
|
||||
` : '' }
|
||||
`;
|
||||
}
|
||||
}
|
||||
@@ -8,6 +8,8 @@ import { createExtensionElement, UmbExtensionManifest, UmbExtensionRegistry } fr
|
||||
import { UmbDataTypeStore } from '../../core/stores/data-type.store';
|
||||
import { DataTypeEntity } from '../../mocks/data/content.data';
|
||||
|
||||
import './node-property-actions.element';
|
||||
|
||||
@customElement('umb-node-property')
|
||||
class UmbNodeProperty extends UmbContextConsumerMixin(LitElement) {
|
||||
static styles = [
|
||||
@@ -141,11 +143,16 @@ class UmbNodeProperty extends UmbContextConsumerMixin(LitElement) {
|
||||
this._dataTypeSubscription?.unsubscribe();
|
||||
}
|
||||
|
||||
private _renderPropertyActions () {
|
||||
return html`${ this._dataType ? html`<umb-node-property-actions .propertyEditorUIAlias="${this._dataType.propertyEditorUIAlias}"></umb-node-property-actions>`: '' }`;
|
||||
}
|
||||
|
||||
render() {
|
||||
return html`
|
||||
<umb-editor-property-layout>
|
||||
<div slot="header">
|
||||
<uui-label>${this.property.label}</uui-label>
|
||||
${ this._renderPropertyActions() }
|
||||
<p>${this.property.description}</p>
|
||||
</div>
|
||||
<div slot="editor">${this._element}</div>
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
import { html, LitElement } from 'lit';
|
||||
import { customElement, property } from 'lit/decorators.js';
|
||||
import { UmbContextConsumerMixin } from '../../core/context';
|
||||
import { UmbNotificationService } from '../../core/services/notification.service';
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-empty-interface
|
||||
interface UmbPropertyActionElement {
|
||||
value: string;
|
||||
}
|
||||
|
||||
@customElement('umb-property-action-copy')
|
||||
export default class UmbPropertyActionCopy extends UmbContextConsumerMixin(LitElement) implements UmbPropertyActionElement {
|
||||
|
||||
@property()
|
||||
value = '';
|
||||
|
||||
private _notificationService?: UmbNotificationService;
|
||||
|
||||
constructor () {
|
||||
super();
|
||||
|
||||
this.consumeContext('umbProperty', (property) => {
|
||||
console.log('PROPERTY', property);
|
||||
});
|
||||
|
||||
this.consumeContext('umbNotificationService', (notificationService: UmbNotificationService) => {
|
||||
this._notificationService = notificationService;
|
||||
});
|
||||
}
|
||||
|
||||
private _handleLabelClick () {
|
||||
this._notificationService?.peek('Copied to clipboard');
|
||||
}
|
||||
|
||||
render() {
|
||||
return html`<uui-menu-item label="Copy" @click-label="${this._handleLabelClick}"></uui-menu-item>`;
|
||||
}
|
||||
}
|
||||
|
||||
declare global {
|
||||
interface HTMLElementTagNameMap {
|
||||
'umb-property-action-copy': UmbPropertyActionCopy;
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
import { BehaviorSubject, map, Observable } from 'rxjs';
|
||||
|
||||
// TODO: how do we want to type extensions?
|
||||
export type UmbExtensionType = 'startUp' | 'section' | 'propertyEditorUI' | 'dashboard';
|
||||
export type UmbExtensionType = 'startUp' | 'section' | 'propertyEditorUI' | 'propertyAction' | 'dashboard';
|
||||
|
||||
export type UmbExtensionManifestJSModel = {
|
||||
elementName?: string;
|
||||
@@ -41,6 +41,16 @@ export type UmbExtensionManifestPropertyEditor = {
|
||||
meta: UmbManifestPropertyEditorMeta;
|
||||
} & UmbExtensionManifestBase;
|
||||
|
||||
// Property Actions
|
||||
export type UmbExtensionManifestPropertyAction = {
|
||||
type: 'propertyAction';
|
||||
meta: UmbManifestPropertyActionMeta;
|
||||
} & UmbExtensionManifestBase;
|
||||
|
||||
export type UmbManifestPropertyActionMeta = {
|
||||
propertyEditors: Array<string>;
|
||||
};
|
||||
|
||||
// Dashboard:
|
||||
export type UmbManifestDashboardMeta = {
|
||||
sections: Array<string>;
|
||||
@@ -67,6 +77,7 @@ export type UmbExtensionManifestCore =
|
||||
| UmbExtensionManifestSection
|
||||
| UmbExtensionManifestDashboard
|
||||
| UmbExtensionManifestPropertyEditor
|
||||
| UmbExtensionManifestPropertyAction
|
||||
| UmbExtensionManifestEditorView;
|
||||
|
||||
// the 'Other' manifest type:
|
||||
@@ -107,6 +118,7 @@ export class UmbExtensionRegistry {
|
||||
extensionsOfType(type: 'section'): Observable<Array<UmbExtensionManifestSection>>;
|
||||
extensionsOfType(type: 'dashboard'): Observable<Array<UmbExtensionManifestDashboard>>;
|
||||
extensionsOfType(type: 'propertyEditor'): Observable<Array<UmbExtensionManifestPropertyEditor>>;
|
||||
extensionsOfType(type: 'propertyAction'): Observable<Array<UmbExtensionManifestPropertyAction>>;
|
||||
extensionsOfType(type: UmbExtensionManifestCoreTypes): Observable<Array<UmbExtensionManifestCore>>;
|
||||
extensionsOfType(type: string): Observable<Array<UmbExtensionManifestOther>>;
|
||||
extensionsOfType<T extends UmbExtensionManifestBase>(type: string): Observable<Array<T>>;
|
||||
|
||||
@@ -111,5 +111,15 @@ export const internalManifests: Array<UmbExtensionManifestCore> = [
|
||||
weight: 90,
|
||||
icon: 'info',
|
||||
}
|
||||
},
|
||||
{
|
||||
type: 'propertyAction',
|
||||
alias: 'Umb.PropertyAction.Copy',
|
||||
name: 'Copy',
|
||||
elementName: 'umb-property-action-copy',
|
||||
js: () => import('./backoffice/property-actions/property-action-copy.element'),
|
||||
meta: {
|
||||
propertyEditors: ['Umb.PropertyEditorUI.Text'],
|
||||
}
|
||||
}
|
||||
];
|
||||
Reference in New Issue
Block a user