From ee696e720de1ae1eb373661b0e3cbafea66b57a1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jesper=20M=C3=B8ller=20Jensen?= Date: Mon, 5 Sep 2022 11:39:53 +0200 Subject: [PATCH] actions: split action service into two services --- .../shared/section-sidebar.element.ts | 2 +- .../action-list-page.element.ts} | 28 ++++---- .../tree/actions/action-page.service.ts | 72 +++++++++++++++++++ .../backoffice/tree/actions/action.element.ts | 50 +++++++++++++ .../tree/{ => actions}/actions.service.ts | 57 +++++---------- .../src/backoffice/tree/actions/index.ts | 11 +++ .../tree-action-create-page-2.element.ts | 24 ++----- .../tree-action-create-page.element.ts | 26 ++----- .../actions/tree-action-create.element.ts | 19 ++--- .../actions/tree-action-delete.element.ts | 14 ++-- .../actions/tree-action-reload.element.ts | 6 +- .../tree/shared/tree-item.element.ts | 4 +- 12 files changed, 189 insertions(+), 124 deletions(-) rename src/Umbraco.Web.UI.Client/src/backoffice/tree/{actions-modal.element.ts => actions/action-list-page.element.ts} (64%) create mode 100644 src/Umbraco.Web.UI.Client/src/backoffice/tree/actions/action-page.service.ts create mode 100644 src/Umbraco.Web.UI.Client/src/backoffice/tree/actions/action.element.ts rename src/Umbraco.Web.UI.Client/src/backoffice/tree/{ => actions}/actions.service.ts (63%) create mode 100644 src/Umbraco.Web.UI.Client/src/backoffice/tree/actions/index.ts diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/sections/shared/section-sidebar.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/sections/shared/section-sidebar.element.ts index 0766c3ff51..485370d34a 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/sections/shared/section-sidebar.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/sections/shared/section-sidebar.element.ts @@ -4,7 +4,7 @@ import { customElement, state } from 'lit/decorators.js'; import { Subscription } from 'rxjs'; import { UmbContextConsumerMixin } from '../../../core/context'; import { UmbSectionContext } from '../section.context'; -import '../../tree/actions.service'; +import '../../tree/actions/actions.service'; @customElement('umb-section-sidebar') export class UmbSectionSidebar extends UmbContextConsumerMixin(LitElement) { diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/tree/actions-modal.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/tree/actions/action-list-page.element.ts similarity index 64% rename from src/Umbraco.Web.UI.Client/src/backoffice/tree/actions-modal.element.ts rename to src/Umbraco.Web.UI.Client/src/backoffice/tree/actions/action-list-page.element.ts index ee01a43546..914ce3e44c 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/tree/actions-modal.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/tree/actions/action-list-page.element.ts @@ -1,13 +1,11 @@ -import { css, html, LitElement } from 'lit'; +import { css, html } from 'lit'; import { UUITextStyles } from '@umbraco-ui/uui-css/lib'; -import { customElement, property } from 'lit/decorators.js'; -import { UmbActionService } from './actions.service'; -import { UmbContextConsumerMixin } from '../../core/context'; -import type { ManifestEntityAction } from '../../core/models'; -import './actions/tree-action.element'; +import { customElement } from 'lit/decorators.js'; +import type { ManifestEntityAction } from '../../../core/models'; +import UmbActionElement from './action.element'; -@customElement('umb-actions-modal') -export class UmbActionsModal extends UmbContextConsumerMixin(LitElement) { +@customElement('umb-action-list-page') +export class UmbActionListPageElement extends UmbActionElement { static styles = [ UUITextStyles, css` @@ -26,9 +24,7 @@ export class UmbActionsModal extends UmbContextConsumerMixin(LitElement) { `, ]; - @property() - name = ''; - + //TODO Replace with real data private _actionList: Array Promise }> = [ { name: 'create', @@ -38,7 +34,7 @@ export class UmbActionsModal extends UmbContextConsumerMixin(LitElement) { icon: 'add', weight: 10, }, - loader: () => import('./actions/tree-action-create.element'), + loader: () => import('./tree-action-create.element'), type: 'entityAction', }, { @@ -49,7 +45,7 @@ export class UmbActionsModal extends UmbContextConsumerMixin(LitElement) { icon: 'delete', weight: 20, }, - loader: () => import('./actions/tree-action-delete.element'), + loader: () => import('./tree-action-delete.element'), type: 'entityAction', }, { @@ -60,7 +56,7 @@ export class UmbActionsModal extends UmbContextConsumerMixin(LitElement) { icon: 'sync', weight: 30, }, - loader: () => import('./actions/tree-action-reload.element'), + loader: () => import('./tree-action-reload.element'), type: 'entityAction', }, ]; @@ -76,7 +72,7 @@ export class UmbActionsModal extends UmbContextConsumerMixin(LitElement) { render() { return html`
-

${this.name}

+

${this._entity.name}

${this.renderActions()}
`; @@ -85,6 +81,6 @@ export class UmbActionsModal extends UmbContextConsumerMixin(LitElement) { declare global { interface HTMLElementTagNameMap { - 'umb-actions-modal': UmbActionsModal; + 'umb-action-list-page': UmbActionListPageElement; } } diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/tree/actions/action-page.service.ts b/src/Umbraco.Web.UI.Client/src/backoffice/tree/actions/action-page.service.ts new file mode 100644 index 0000000000..0116c9c249 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/backoffice/tree/actions/action-page.service.ts @@ -0,0 +1,72 @@ +import { UUITextStyles } from '@umbraco-ui/uui-css'; +import { css, LitElement, nothing, PropertyValueMap } from 'lit'; +import { customElement, property, state } from 'lit/decorators.js'; +import { UmbContextProviderMixin } from '../../../core/context'; +import UmbActionElement, { ActionPageEntity } from './action.element'; +import { BehaviorSubject, Observable } from 'rxjs'; + +// TODO how do we dynamically import this so we don't have to import every page that could potentially be used? + +@customElement('umb-action-page-service') +export class UmbActionPageService extends UmbContextProviderMixin(LitElement) { + static styles = [UUITextStyles, css``]; + + @property({ type: Object }) + public actionEntity: ActionPageEntity = { key: '', name: '' }; + + private _entity: BehaviorSubject = new BehaviorSubject({ key: '', name: '' }); + public readonly entity: Observable = this._entity.asObservable(); + + @state() + private _pages: Array = []; + + connectedCallback() { + super.connectedCallback(); + this.provideContext('umbActionPageService', this); + this.openFreshPage('umb-action-list-page'); + } + + protected updated(_changedProperties: PropertyValueMap | Map): void { + super.updated(_changedProperties); + + if (_changedProperties.has('actionEntity')) { + this._entity.next(this.actionEntity); + //TODO: Move back to first page + this.openFreshPage('umb-action-list-page'); + } + } + + public openPage(elementName: string) { + const element = document.createElement(elementName) as UmbActionElement; + this._pages.push(element); + this.requestUpdate('_pages'); + } + + public openFreshPage(elementName: string) { + this._pages = []; + this.openPage(elementName); + } + + public closeTopPage() { + this._pages.pop(); + this.requestUpdate('_pages'); + } + + private _renderTopPage() { + if (this._pages.length === 0) { + return nothing; + } + + return this._pages[this._pages.length - 1]; + } + + render() { + return this._renderTopPage(); + } +} + +declare global { + interface HTMLElementTagNameMap { + 'umb-action-page-service': UmbActionPageService; + } +} diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/tree/actions/action.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/tree/actions/action.element.ts new file mode 100644 index 0000000000..3844a1a6c6 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/backoffice/tree/actions/action.element.ts @@ -0,0 +1,50 @@ +import { LitElement } from 'lit'; +import { customElement, state } from 'lit/decorators.js'; +import { Subscription } from 'rxjs'; +import { UmbContextConsumerMixin } from '../../../core/context'; +import { UmbActionPageService } from './action-page.service'; +import { UmbActionService } from './actions.service'; + +export type ActionPageEntity = { + key: string; + name: string; +}; + +@customElement('umb-action') +export default class UmbActionElement extends UmbContextConsumerMixin(LitElement) { + @state() + protected _entity: ActionPageEntity = { name: '', key: '' }; + + protected _actionService?: UmbActionService; + protected _actionPageService?: UmbActionPageService; + private _actionPageSubscription?: Subscription; + + connectedCallback() { + super.connectedCallback(); + + this.consumeContext('umbActionService', (actionService: UmbActionService) => { + this._actionService = actionService; + }); + + this.consumeContext('umbActionPageService', (actionPageService: UmbActionPageService) => { + this._actionPageService = actionPageService; + + this._actionPageSubscription?.unsubscribe(); + this._actionPageService?.entity.subscribe((entity: ActionPageEntity) => { + this._entity = entity; + console.log('entity changed', this._entity); + }); + }); + } + + disconnectCallback() { + super.disconnectedCallback(); + this._actionPageSubscription?.unsubscribe(); + } +} + +declare global { + interface HTMLElementTagNameMap { + 'umb-action': UmbActionElement; + } +} diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/tree/actions.service.ts b/src/Umbraco.Web.UI.Client/src/backoffice/tree/actions/actions.service.ts similarity index 63% rename from src/Umbraco.Web.UI.Client/src/backoffice/tree/actions.service.ts rename to src/Umbraco.Web.UI.Client/src/backoffice/tree/actions/actions.service.ts index c5b9966f07..c6648a2de8 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/tree/actions.service.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/tree/actions/actions.service.ts @@ -1,12 +1,16 @@ import { UUITextStyles } from '@umbraco-ui/uui-css'; import { css, html, LitElement, nothing } from 'lit'; -import { customElement, property, state } from 'lit/decorators.js'; -import { UmbContextProviderMixin } from '../../core/context'; -import type { ManifestEntityAction } from '../../core/models'; +import { customElement, query, state } from 'lit/decorators.js'; +import { UmbContextProviderMixin } from '../../../core/context'; -import './actions-modal.element'; -import './actions/tree-action-create-page.element'; -import './actions/tree-action-create-page-2.element'; +import { ActionPageEntity } from './action.element'; +import { UmbActionPageService } from '.'; +import '.'; + +// import './actions-modal.element'; +// import './tree-action-create-page.element'; +// import './tree-action-create-page-2.element'; +// import './action-page.service'; // TODO how do we dynamically import this so we don't have to import every page that could potentially be used? @customElement('umb-action-service') @@ -53,50 +57,27 @@ export class UmbActionService extends UmbContextProviderMixin(LitElement) { `, ]; + @query('umb-action-page-service') + private _actionPageService!: UmbActionPageService; + @state() private _modalOpen = false; @state() - private _name = ''; - - public key = ''; - - @state() - private _pages: Array = []; + private entity: { name: string; key: string } = { name: '', key: '' }; connectedCallback() { super.connectedCallback(); this.provideContext('umbActionService', this); } - public open(name: string, key: string) { - this._name = name; - this.key = key; + public open(entity: ActionPageEntity) { + this.entity = entity; this._modalOpen = true; } public close() { this._modalOpen = false; - this._pages = []; - } - - public openPage(elementName: string) { - const element = document.createElement(elementName); - this._pages.push(element); - this.requestUpdate('_pages'); - } - - public closeTopPage() { - this._pages.pop(); - this.requestUpdate('_pages'); - } - - private _renderTopPage() { - if (this._pages.length === 0) { - return nothing; - } - - return this._pages[this._pages.length - 1]; } private _renderBackdrop() { @@ -106,11 +87,7 @@ export class UmbActionService extends UmbContextProviderMixin(LitElement) { private _renderModal() { return this._modalOpen - ? html`
- ${this._pages.length === 0 - ? html`` - : this._renderTopPage()} -
` + ? html`` : nothing; } diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/tree/actions/index.ts b/src/Umbraco.Web.UI.Client/src/backoffice/tree/actions/index.ts new file mode 100644 index 0000000000..66477c0462 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/backoffice/tree/actions/index.ts @@ -0,0 +1,11 @@ +export * from './action-list-page.element'; +export * from './action-page.service'; +export * from './actions.service'; +export * from './tree-action.element'; + +// We need these to make it work, even though they have import errors. // TODO: Fix later +export * from './tree-action-create-page.element'; +export * from './tree-action-create-page-2.element'; +export * from './tree-action-create.element'; +export * from './tree-action-delete.element'; +export * from './tree-action-reload.element'; diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/tree/actions/tree-action-create-page-2.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/tree/actions/tree-action-create-page-2.element.ts index b6221b4fec..811e2066c0 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/tree/actions/tree-action-create-page-2.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/tree/actions/tree-action-create-page-2.element.ts @@ -1,34 +1,22 @@ import { UUITextStyles } from '@umbraco-ui/uui-css'; -import { css, html, LitElement } from 'lit'; -import { customElement, property } from 'lit/decorators.js'; -import { UmbContextConsumerMixin } from '../../../core/context'; -import type { ManifestEntityAction } from '../../../core/models'; -import { UmbActionService } from '../actions.service'; +import { css, html } from 'lit'; +import { customElement } from 'lit/decorators.js'; +import UmbActionElement from './action.element'; @customElement('umb-tree-action-create-page-2') -export default class UmbTreeActionCreatePageElement extends UmbContextConsumerMixin(LitElement) { +export class UmbTreeActionCreatePageElement extends UmbActionElement { static styles = [UUITextStyles, css``]; - private _actionService?: UmbActionService; - - constructor() { - super(); - - this.consumeContext('umbActionService', (actionService: UmbActionService) => { - this._actionService = actionService; - }); - } - private _save() { this._actionService?.close(); } private _back() { - this._actionService?.closeTopPage(); + this._actionPageService?.closeTopPage(); } render() { - return html`

Create page 2

+ return html`

Create page 2 for entity: ${this._entity.name}

This is the last create page, here you can go back og save (it just closes the modal for now)

`; diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/tree/actions/tree-action-create-page.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/tree/actions/tree-action-create-page.element.ts index 8a7dac6c7a..5aa29fe437 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/tree/actions/tree-action-create-page.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/tree/actions/tree-action-create-page.element.ts @@ -1,34 +1,22 @@ import { UUITextStyles } from '@umbraco-ui/uui-css'; -import { css, html, LitElement } from 'lit'; -import { customElement, property } from 'lit/decorators.js'; -import { UmbContextConsumerMixin } from '../../../core/context'; -import type { ManifestEntityAction } from '../../../core/models'; -import { UmbActionService } from '../actions.service'; +import { css, html } from 'lit'; +import { customElement } from 'lit/decorators.js'; +import UmbActionElement from './action.element'; @customElement('umb-tree-action-create-page') -export default class UmbTreeActionCreatePageElement extends UmbContextConsumerMixin(LitElement) { +export class UmbTreeActionCreatePageElement extends UmbActionElement { static styles = [UUITextStyles, css``]; - private _actionService?: UmbActionService; - - constructor() { - super(); - - this.consumeContext('umbActionService', (actionService: UmbActionService) => { - this._actionService = actionService; - }); - } - private _next() { - this._actionService?.openPage('umb-tree-action-create-page-2'); + this._actionPageService?.openPage('umb-tree-action-create-page-2'); } private _back() { - this._actionService?.closeTopPage(); + this._actionPageService?.closeTopPage(); } render() { - return html`

Create page 1

+ return html`

Create page 1 for entity: ${this._entity.name}

This is the first create page, here you can go next or back (it just closes the modal for now)

`; diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/tree/actions/tree-action-create.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/tree/actions/tree-action-create.element.ts index ba299f8f50..84046569c7 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/tree/actions/tree-action-create.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/tree/actions/tree-action-create.element.ts @@ -1,30 +1,19 @@ import { UUITextStyles } from '@umbraco-ui/uui-css'; -import { css, html, LitElement } from 'lit'; +import { css, html } from 'lit'; import { customElement, property } from 'lit/decorators.js'; -import { UmbContextConsumerMixin } from '../../../core/context'; import type { ManifestEntityAction } from '../../../core/models'; -import { UmbActionService } from '../actions.service'; +import UmbActionElement from './action.element'; @customElement('umb-tree-action-create') -export default class UmbTreeActionCreateElement extends UmbContextConsumerMixin(LitElement) { +export default class UmbTreeActionCreateElement extends UmbActionElement { static styles = [UUITextStyles, css``]; @property({ attribute: false }) public treeAction?: ManifestEntityAction; - private _actionService?: UmbActionService; - - constructor() { - super(); - - this.consumeContext('umbActionService', (actionService: UmbActionService) => { - this._actionService = actionService; - }); - } - private _handleLabelClick() { console.log(this.treeAction, 'label clicked'); - this._actionService?.openPage('umb-tree-action-create-page'); + this._actionPageService?.openPage('umb-tree-action-create-page'); } render() { diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/tree/actions/tree-action-delete.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/tree/actions/tree-action-delete.element.ts index 70ad957860..c3632eda00 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/tree/actions/tree-action-delete.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/tree/actions/tree-action-delete.element.ts @@ -1,30 +1,24 @@ import { UUITextStyles } from '@umbraco-ui/uui-css'; -import { css, html, LitElement } from 'lit'; +import { css, html } from 'lit'; import { customElement, property } from 'lit/decorators.js'; -import { UmbContextConsumerMixin } from '../../../core/context'; import type { ManifestEntityAction } from '../../../core/models'; import { UmbModalService } from '../../../core/services/modal'; import { UmbNodeStore } from '../../../core/stores/node.store'; -import { UmbActionService } from '../actions.service'; +import UmbActionElement from './action.element'; @customElement('umb-tree-action-delete') -export default class UmbTreeActionDeleteElement extends UmbContextConsumerMixin(LitElement) { +export default class UmbTreeActionDeleteElement extends UmbActionElement { static styles = [UUITextStyles, css``]; @property({ attribute: false }) public treeAction?: ManifestEntityAction; - private _actionService?: UmbActionService; private _modalService?: UmbModalService; private _nodeStore?: UmbNodeStore; constructor() { super(); - this.consumeContext('umbActionService', (actionService: UmbActionService) => { - this._actionService = actionService; - }); - this.consumeContext('umbModalService', (modalService: UmbModalService) => { this._modalService = modalService; }); @@ -43,7 +37,7 @@ export default class UmbTreeActionDeleteElement extends UmbContextConsumerMixin( modalHandler?.onClose.then(({ confirmed }: any) => { if (confirmed && this._actionService) { - this._nodeStore?.trash(this._actionService.key); + this._nodeStore?.trash(this._entity.key); this._actionService.close(); } }); diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/tree/actions/tree-action-reload.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/tree/actions/tree-action-reload.element.ts index b6b0fda791..2f1fc7132f 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/tree/actions/tree-action-reload.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/tree/actions/tree-action-reload.element.ts @@ -1,11 +1,11 @@ import { UUITextStyles } from '@umbraco-ui/uui-css'; -import { css, html, LitElement } from 'lit'; +import { css, html } from 'lit'; import { customElement, property } from 'lit/decorators.js'; -import { UmbContextConsumerMixin } from '../../../core/context'; import type { ManifestEntityAction } from '../../../core/models'; +import UmbActionElement from './action.element'; @customElement('umb-tree-action-reload') -export default class UmbTreeActionReloadElement extends UmbContextConsumerMixin(LitElement) { +export default class UmbTreeActionReloadElement extends UmbActionElement { static styles = [UUITextStyles, css``]; @property({ attribute: false }) diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/tree/shared/tree-item.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/tree/shared/tree-item.element.ts index 54b74b03b4..e86d10084b 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/tree/shared/tree-item.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/tree/shared/tree-item.element.ts @@ -7,7 +7,7 @@ import { UUIMenuItemEvent } from '@umbraco-ui/uui'; import { UmbSectionContext } from '../../sections/section.context'; import { Subscription } from 'rxjs'; import { Entity } from '../../../mocks/data/entity.data'; -import { UmbActionService } from '../actions.service'; +import { UmbActionService } from '../actions/actions.service'; @customElement('umb-tree-item') export class UmbTreeItem extends UmbContextConsumerMixin(LitElement) { @@ -115,7 +115,7 @@ export class UmbTreeItem extends UmbContextConsumerMixin(LitElement) { } private _openActions() { - this._actionService?.open(this.label, this.itemKey); + this._actionService?.open({ name: this.label, key: this.itemKey }); } render() {