Merge branch 'feature/tree-navigator' of https://github.com/umbraco/Umbraco.CMS.Backoffice into feature/tree-navigator

This commit is contained in:
Mads Rasmussen
2022-09-05 14:11:22 +02:00
12 changed files with 189 additions and 124 deletions

View File

@@ -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) {

View File

@@ -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<ManifestEntityAction & { loader?: () => Promise<object | HTMLElement> }> = [
{
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`
<div id="title">
<h3>${this.name}</h3>
<h3>${this._entity.name}</h3>
</div>
<div id="action-list">${this.renderActions()}</div>
`;
@@ -85,6 +81,6 @@ export class UmbActionsModal extends UmbContextConsumerMixin(LitElement) {
declare global {
interface HTMLElementTagNameMap {
'umb-actions-modal': UmbActionsModal;
'umb-action-list-page': UmbActionListPageElement;
}
}

View File

@@ -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<ActionPageEntity> = new BehaviorSubject({ key: '', name: '' });
public readonly entity: Observable<ActionPageEntity> = this._entity.asObservable();
@state()
private _pages: Array<HTMLElement> = [];
connectedCallback() {
super.connectedCallback();
this.provideContext('umbActionPageService', this);
this.openFreshPage('umb-action-list-page');
}
protected updated(_changedProperties: PropertyValueMap<any> | Map<PropertyKey, unknown>): 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;
}
}

View File

@@ -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;
}
}

View File

@@ -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<HTMLElement> = [];
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` <div id="action-modal">
${this._pages.length === 0
? html`<umb-actions-modal .name=${this._name}></umb-actions-modal>`
: this._renderTopPage()}
</div>`
? html`<umb-action-page-service id="action-modal" .actionEntity=${this.entity}></umb-action-page-service>`
: nothing;
}

View File

@@ -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';

View File

@@ -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`<h2>Create page 2</h2>
return html`<h2>Create page 2 for entity: ${this._entity.name}</h2>
<p>This is the last create page, here you can go back og save (it just closes the modal for now)</p>
<uui-button label="Back" look="secondary" @click=${this._back}></uui-button>
<uui-button label="Save" look="primary" color="positive" @click=${this._save}></uui-button>`;

View File

@@ -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`<h2>Create page 1</h2>
return html`<h2>Create page 1 for entity: ${this._entity.name}</h2>
<p>This is the first create page, here you can go next or back (it just closes the modal for now)</p>
<uui-button label="Back" look="secondary" @click=${this._back}></uui-button>
<uui-button label="Next" look="primary" @click=${this._next}></uui-button>`;

View File

@@ -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() {

View File

@@ -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();
}
});

View File

@@ -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 })

View File

@@ -7,7 +7,7 @@ import { UUIMenuItemEvent } from '@umbraco-ui/uui';
import { UmbSectionContext } from '../../sections/section.context';
import { map, 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) {
@@ -143,7 +143,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() {