From 11ac9538d1b9d2bceb24030482d091d6d898a470 Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Tue, 21 Jun 2022 10:38:36 +0200 Subject: [PATCH] register and render property actions --- .../node-property-action.element.ts | 38 ++++++++ .../node-property-actions.element.ts | 93 +++++++++++++++++++ .../components/node-property.element.ts | 7 ++ .../property-action-copy.element.ts | 44 +++++++++ .../src/core/extension/extension.registry.ts | 14 ++- .../src/temp-internal-manifests.ts | 10 ++ 6 files changed, 205 insertions(+), 1 deletion(-) create mode 100644 src/Umbraco.Web.UI.Client/src/backoffice/components/node-property-action.element.ts create mode 100644 src/Umbraco.Web.UI.Client/src/backoffice/components/node-property-actions.element.ts create mode 100644 src/Umbraco.Web.UI.Client/src/backoffice/property-actions/property-action-copy.element.ts diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/components/node-property-action.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/components/node-property-action.element.ts new file mode 100644 index 0000000000..a7aae0b63a --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/backoffice/components/node-property-action.element.ts @@ -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}`; + } +} \ No newline at end of file diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/components/node-property-actions.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/components/node-property-actions.element.ts new file mode 100644 index 0000000000..5377fb9c2d --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/backoffice/components/node-property-actions.element.ts @@ -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 = []; + + @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` + + + + + + + + ` : '' } + `; + } +} \ No newline at end of file diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/components/node-property.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/components/node-property.element.ts index d49eb74eff..8230f18562 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/components/node-property.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/components/node-property.element.ts @@ -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``: '' }`; + } + render() { return html`
${this.property.label} + ${ this._renderPropertyActions() }

${this.property.description}

${this._element}
diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/property-actions/property-action-copy.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/property-actions/property-action-copy.element.ts new file mode 100644 index 0000000000..cc934d8cea --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/backoffice/property-actions/property-action-copy.element.ts @@ -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``; + } +} + +declare global { + interface HTMLElementTagNameMap { + 'umb-property-action-copy': UmbPropertyActionCopy; + } +} diff --git a/src/Umbraco.Web.UI.Client/src/core/extension/extension.registry.ts b/src/Umbraco.Web.UI.Client/src/core/extension/extension.registry.ts index afafe61568..6a40e22669 100644 --- a/src/Umbraco.Web.UI.Client/src/core/extension/extension.registry.ts +++ b/src/Umbraco.Web.UI.Client/src/core/extension/extension.registry.ts @@ -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; +}; + // Dashboard: export type UmbManifestDashboardMeta = { sections: Array; @@ -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>; extensionsOfType(type: 'dashboard'): Observable>; extensionsOfType(type: 'propertyEditor'): Observable>; + extensionsOfType(type: 'propertyAction'): Observable>; extensionsOfType(type: UmbExtensionManifestCoreTypes): Observable>; extensionsOfType(type: string): Observable>; extensionsOfType(type: string): Observable>; diff --git a/src/Umbraco.Web.UI.Client/src/temp-internal-manifests.ts b/src/Umbraco.Web.UI.Client/src/temp-internal-manifests.ts index 19d93b6aa0..c7099f6a23 100644 --- a/src/Umbraco.Web.UI.Client/src/temp-internal-manifests.ts +++ b/src/Umbraco.Web.UI.Client/src/temp-internal-manifests.ts @@ -111,5 +111,15 @@ export const internalManifests: Array = [ 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'], + } } ]; \ No newline at end of file