From 23ec98874cb6e309d193704f606a59a9cf77670e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jesper=20M=C3=B8ller=20Jensen?= Date: Tue, 4 Oct 2022 13:38:28 +0200 Subject: [PATCH] added editor action extension, schemas and api --- src/Umbraco.Web.UI.Client/schemas/api/api.yml | 119 +++++++++++------- .../schemas/generated-schema.ts | 47 ++++--- .../editor-action-extension.element.ts | 46 +++++++ .../editor-entity-layout.element.ts | 30 ++++- .../editor-action-users-save.element.ts | 24 ++++ .../src/core/extension/extension.registry.ts | 2 + .../src/core/models/index.ts | 2 + .../src/temp-internal-manifests.ts | 18 +++ .../temp-schema-generator/manifests.ts | 19 ++- 9 files changed, 240 insertions(+), 67 deletions(-) create mode 100644 src/Umbraco.Web.UI.Client/src/backoffice/editors/shared/editor-action-extension/editor-action-extension.element.ts create mode 100644 src/Umbraco.Web.UI.Client/src/backoffice/editors/users/views/users/actions/editor-action-users-save.element.ts diff --git a/src/Umbraco.Web.UI.Client/schemas/api/api.yml b/src/Umbraco.Web.UI.Client/schemas/api/api.yml index 3c4e98e020..8819b25df0 100644 --- a/src/Umbraco.Web.UI.Client/schemas/api/api.yml +++ b/src/Umbraco.Web.UI.Client/schemas/api/api.yml @@ -486,6 +486,78 @@ components: - meta - alias - name + MetaEditorAction: + type: object + properties: + editors: + type: array + items: + type: string + required: + - editors + IManifestEditorAction: + type: object + properties: + type: + type: string + enum: + - editorAction + meta: + $ref: '#/components/schemas/MetaEditorAction' + js: + type: string + elementName: + type: string + alias: + type: string + name: + type: string + required: + - type + - meta + - alias + - name + MetaEditorView: + type: object + properties: + editors: + type: array + items: + type: string + pathname: + type: string + weight: + type: number + format: float + icon: + type: string + required: + - editors + - pathname + - weight + - icon + IManifestEditorView: + type: object + properties: + type: + type: string + enum: + - editorView + meta: + $ref: '#/components/schemas/MetaEditorView' + js: + type: string + elementName: + type: string + alias: + type: string + name: + type: string + required: + - type + - meta + - alias + - name MetaTreeItemAction: type: object properties: @@ -624,47 +696,6 @@ components: - meta - alias - name - MetaEditorView: - type: object - properties: - editors: - type: array - items: - type: string - pathname: - type: string - weight: - type: number - format: float - icon: - type: string - required: - - editors - - pathname - - weight - - icon - IManifestEditorView: - type: object - properties: - type: - type: string - enum: - - editorView - meta: - $ref: '#/components/schemas/MetaEditorView' - js: - type: string - elementName: - type: string - alias: - type: string - name: - type: string - required: - - type - - meta - - alias - - name MetaPropertyAction: type: object properties: @@ -765,10 +796,11 @@ components: - $ref: '#/components/schemas/IManifestSection' - $ref: '#/components/schemas/IManifestTree' - $ref: '#/components/schemas/IManifestEditor' + - $ref: '#/components/schemas/IManifestEditorAction' + - $ref: '#/components/schemas/IManifestEditorView' - $ref: '#/components/schemas/IManifestTreeItemAction' - $ref: '#/components/schemas/IManifestPropertyEditorUI' - $ref: '#/components/schemas/IManifestDashboard' - - $ref: '#/components/schemas/IManifestEditorView' - $ref: '#/components/schemas/IManifestPropertyAction' - $ref: '#/components/schemas/IManifestPackageView' - $ref: '#/components/schemas/IManifestEntrypoint' @@ -779,10 +811,11 @@ components: section: '#/components/schemas/IManifestSection' tree: '#/components/schemas/IManifestTree' editor: '#/components/schemas/IManifestEditor' + editorAction: '#/components/schemas/IManifestEditorAction' + editorView: '#/components/schemas/IManifestEditorView' treeItemAction: '#/components/schemas/IManifestTreeItemAction' propertyEditorUI: '#/components/schemas/IManifestPropertyEditorUI' dashboard: '#/components/schemas/IManifestDashboard' - editorView: '#/components/schemas/IManifestEditorView' propertyAction: '#/components/schemas/IManifestPropertyAction' packageView: '#/components/schemas/IManifestPackageView' entrypoint: '#/components/schemas/IManifestEntrypoint' diff --git a/src/Umbraco.Web.UI.Client/schemas/generated-schema.ts b/src/Umbraco.Web.UI.Client/schemas/generated-schema.ts index fdc1e66117..c134812f22 100644 --- a/src/Umbraco.Web.UI.Client/schemas/generated-schema.ts +++ b/src/Umbraco.Web.UI.Client/schemas/generated-schema.ts @@ -151,6 +151,34 @@ export interface components { alias: string; name: string; }; + MetaEditorAction: { + editors: string[]; + }; + IManifestEditorAction: { + /** @enum {string} */ + type: "editorAction"; + meta: components["schemas"]["MetaEditorAction"]; + js?: string; + elementName?: string; + alias: string; + name: string; + }; + MetaEditorView: { + editors: string[]; + pathname: string; + /** Format: float */ + weight: number; + icon: string; + }; + IManifestEditorView: { + /** @enum {string} */ + type: "editorView"; + meta: components["schemas"]["MetaEditorView"]; + js?: string; + elementName?: string; + alias: string; + name: string; + }; MetaTreeItemAction: { trees: string[]; label: string; @@ -206,22 +234,6 @@ export interface components { alias: string; name: string; }; - MetaEditorView: { - editors: string[]; - pathname: string; - /** Format: float */ - weight: number; - icon: string; - }; - IManifestEditorView: { - /** @enum {string} */ - type: "editorView"; - meta: components["schemas"]["MetaEditorView"]; - js?: string; - elementName?: string; - alias: string; - name: string; - }; MetaPropertyAction: { propertyEditors: string[]; }; @@ -264,10 +276,11 @@ export interface components { | components["schemas"]["IManifestSection"] | components["schemas"]["IManifestTree"] | components["schemas"]["IManifestEditor"] + | components["schemas"]["IManifestEditorAction"] + | components["schemas"]["IManifestEditorView"] | components["schemas"]["IManifestTreeItemAction"] | components["schemas"]["IManifestPropertyEditorUI"] | components["schemas"]["IManifestDashboard"] - | components["schemas"]["IManifestEditorView"] | components["schemas"]["IManifestPropertyAction"] | components["schemas"]["IManifestPackageView"] | components["schemas"]["IManifestEntrypoint"] diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/editors/shared/editor-action-extension/editor-action-extension.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/editors/shared/editor-action-extension/editor-action-extension.element.ts new file mode 100644 index 0000000000..de0542a5b4 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/backoffice/editors/shared/editor-action-extension/editor-action-extension.element.ts @@ -0,0 +1,46 @@ +import { UUITextStyles } from '@umbraco-ui/uui'; +import { CSSResultGroup, html, LitElement } from 'lit'; +import { customElement, property, state } from 'lit/decorators.js'; +import { createExtensionElement } from '../../../../core/extension'; +import type { ManifestEditorAction } from '../../../../core/models'; + +@customElement('umb-editor-action-extension') +export class UmbEditorActionExtensionElement extends LitElement { + static styles: CSSResultGroup = [UUITextStyles]; + + private _editorAction?: ManifestEditorAction; + @property({ type: Object }) + public get editorAction(): ManifestEditorAction | undefined { + return this._editorAction; + } + public set editorAction(value: ManifestEditorAction | undefined) { + this._editorAction = value; + this._createElement(); + } + + @state() + private _element?: any; + + private async _createElement() { + if (!this.editorAction) return; + + try { + this._element = await createExtensionElement(this.editorAction); + if (!this._element) return; + + this._element.editorAction = this.editorAction; + } 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}`; + } +} + +declare global { + interface HTMLElementTagNameMap { + 'umb-editor-action-extension': UmbEditorActionExtensionElement; + } +} diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/editors/shared/editor-entity-layout/editor-entity-layout.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/editors/shared/editor-entity-layout/editor-entity-layout.element.ts index 9dd3c6f90a..c424638fa2 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/editors/shared/editor-entity-layout/editor-entity-layout.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/editors/shared/editor-entity-layout/editor-entity-layout.element.ts @@ -1,4 +1,5 @@ import '../editor-layout/editor-layout.element'; +import '../editor-action-extension/editor-action-extension.element'; import { UUITextStyles } from '@umbraco-ui/uui-css/lib'; import { css, html, LitElement, nothing } from 'lit'; @@ -8,7 +9,7 @@ import { map, Subscription } from 'rxjs'; import { UmbContextConsumerMixin } from '../../../../core/context'; import { createExtensionElement, UmbExtensionRegistry } from '../../../../core/extension'; -import type { ManifestEditorView } from '../../../../core/models'; +import type { ManifestEditorAction, ManifestEditorView } from '../../../../core/models'; @customElement('umb-editor-entity-layout') export class UmbEditorEntityLayout extends UmbContextConsumerMixin(LitElement) { @@ -71,6 +72,9 @@ export class UmbEditorEntityLayout extends UmbContextConsumerMixin(LitElement) { @state() private _editorViews: Array = []; + @state() + private _editorActions: Array = []; + @state() private _currentView = ''; @@ -79,6 +83,7 @@ export class UmbEditorEntityLayout extends UmbContextConsumerMixin(LitElement) { private _extensionRegistry?: UmbExtensionRegistry; private _editorViewsSubscription?: Subscription; + private _editorActionsSubscription?: Subscription; private _routerFolder = ''; constructor() { @@ -86,7 +91,8 @@ export class UmbEditorEntityLayout extends UmbContextConsumerMixin(LitElement) { this.consumeContext('umbExtensionRegistry', (extensionRegistry: UmbExtensionRegistry) => { this._extensionRegistry = extensionRegistry; - this._useEditorViews(); + this._observeEditorViews(); + this._observeEditorActions(); }); } @@ -96,7 +102,7 @@ export class UmbEditorEntityLayout extends UmbContextConsumerMixin(LitElement) { this._routerFolder = window.location.pathname.split('/view')[0]; } - private _useEditorViews() { + private _observeEditorViews() { this._editorViewsSubscription?.unsubscribe(); this._editorViewsSubscription = this._extensionRegistry @@ -114,6 +120,17 @@ export class UmbEditorEntityLayout extends UmbContextConsumerMixin(LitElement) { }); } + private _observeEditorActions() { + this._editorActionsSubscription?.unsubscribe(); + + this._editorActionsSubscription = this._extensionRegistry + ?.extensionsOfType('editorAction') + .pipe(map((extensions) => extensions.filter((extension) => extension.meta.editors.includes(this.alias)))) + .subscribe((editorActions) => { + this._editorActions = editorActions; + }); + } + private async _createRoutes() { if (this._editorViews.length > 0) { this._routes = []; @@ -184,7 +201,12 @@ export class UmbEditorEntityLayout extends UmbContextConsumerMixin(LitElement) { `; diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/editors/users/views/users/actions/editor-action-users-save.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/editors/users/views/users/actions/editor-action-users-save.element.ts new file mode 100644 index 0000000000..a536251d32 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/backoffice/editors/users/views/users/actions/editor-action-users-save.element.ts @@ -0,0 +1,24 @@ +import { css, html, LitElement, nothing } from 'lit'; +import { UUITextStyles } from '@umbraco-ui/uui-css/lib'; +import { customElement, state } from 'lit/decorators.js'; + +@customElement('umb-editor-action-users-save') +export class UmbEditorActionUsersSaveElement extends LitElement { + static styles = [UUITextStyles, css``]; + + private _handleSave() { + console.log('save'); + } + + render() { + return html``; + } +} + +export default UmbEditorActionUsersSaveElement; + +declare global { + interface HTMLElementTagNameMap { + 'umb-editor-action-users-save': UmbEditorActionUsersSaveElement; + } +} 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 4b8f2c9599..6b0c2c4b28 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 @@ -17,6 +17,7 @@ import type { ManifestTree, ManifestTreeItemAction, ManifestEditor, + ManifestEditorAction, ManifestCustom, ManifestPackageView, } from '../models'; @@ -65,6 +66,7 @@ export class UmbExtensionRegistry { extensionsOfType(type: 'treeItemAction'): Observable>; extensionsOfType(type: 'dashboard'): Observable>; extensionsOfType(type: 'editorView'): Observable>; + extensionsOfType(type: 'editorAction'): Observable>; extensionsOfType(type: 'propertyEditorUI'): Observable>; extensionsOfType(type: 'propertyAction'): Observable>; extensionsOfType(type: 'packageView'): Observable>; diff --git a/src/Umbraco.Web.UI.Client/src/core/models/index.ts b/src/Umbraco.Web.UI.Client/src/core/models/index.ts index 80f628566e..937ba5b4db 100644 --- a/src/Umbraco.Web.UI.Client/src/core/models/index.ts +++ b/src/Umbraco.Web.UI.Client/src/core/models/index.ts @@ -22,6 +22,7 @@ export type ManifestSection = components['schemas']['IManifestSection']; export type ManifestTree = components['schemas']['IManifestTree']; export type ManifestTreeItemAction = components['schemas']['IManifestTreeItemAction']; export type ManifestEditor = components['schemas']['IManifestEditor']; +export type ManifestEditorAction = components['schemas']['IManifestEditorAction']; export type ManifestPropertyEditorUI = components['schemas']['IManifestPropertyEditorUI']; export type ManifestDashboard = components['schemas']['IManifestDashboard']; export type ManifestEditorView = components['schemas']['IManifestEditorView']; @@ -40,6 +41,7 @@ export type ManifestElementType = | ManifestPropertyEditorUI | ManifestDashboard | ManifestEditorView + | ManifestEditorAction | ManifestPackageView; // eslint-disable-next-line @typescript-eslint/no-explicit-any 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 277ad11310..af460b0f6b 100644 --- a/src/Umbraco.Web.UI.Client/src/temp-internal-manifests.ts +++ b/src/Umbraco.Web.UI.Client/src/temp-internal-manifests.ts @@ -269,6 +269,24 @@ export const internalManifests: Array Promise import('./backoffice/editors/users/views/users/actions/editor-action-users-save.element'), + meta: { + editors: ['Umb.Editor.Users'], + }, + }, + { + type: 'editorAction', + alias: 'Umb.EditorAction.Users.Delete', + name: 'EditorActionUserDelete', + loader: () => import('./backoffice/editors/users/views/users/actions/editor-action-users-save.element'), + meta: { + editors: ['Umb.Editor.DataType'], + }, + }, { type: 'editorView', alias: 'Umb.EditorView.Users.UserGroups', diff --git a/src/Umbraco.Web.UI.Client/temp-schema-generator/manifests.ts b/src/Umbraco.Web.UI.Client/temp-schema-generator/manifests.ts index 01e470e6f6..a32cf4710d 100644 --- a/src/Umbraco.Web.UI.Client/temp-schema-generator/manifests.ts +++ b/src/Umbraco.Web.UI.Client/temp-schema-generator/manifests.ts @@ -33,10 +33,11 @@ export type Manifest = | IManifestSection | IManifestTree | IManifestEditor + | IManifestEditorAction + | IManifestEditorView | IManifestTreeItemAction | IManifestPropertyEditorUI | IManifestDashboard - | IManifestEditorView | IManifestPropertyAction | IManifestPackageView | IManifestEntrypoint @@ -46,13 +47,15 @@ export type ManifestStandardTypes = | 'section' | 'tree' | 'editor' + | 'editorView' + | 'editorAction' | 'treeItemAction' | 'propertyEditorUI' | 'dashboard' - | 'editorView' | 'propertyAction' | 'packageView' - | 'entrypoint'; + | 'entrypoint' + ; export interface ManifestsResponse { manifests: Manifest[]; @@ -156,6 +159,16 @@ export interface IManifestSection extends IManifestElement { meta: MetaSection; } +export interface IManifestEditorAction extends IManifestElement { + type: 'editorAction'; + meta: MetaEditorAction; +} + +export interface MetaEditorAction { + editors: Array; +} + + export interface IManifestTree extends IManifestElement { type: 'tree'; meta: MetaTree;