Adds way to open debug info in a dialog
* UI needs tidying up - spacing * Consider dropping the other UI approach and use dialog only * Need to ensure all typed * Neaten/refactor code if needed * Lint code
This commit is contained in:
@@ -16,11 +16,7 @@ export class UmbModalLayoutFieldsViewerElement extends UmbModalLayoutElement<Sea
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: 100%;
|
||||
background-color: var(--uui-color-surface);
|
||||
box-shadow: var(--uui-shadow-depth-1, 0 1px 3px rgba(0, 0, 0, 0.12), 0 1px 2px rgba(0, 0, 0, 0.24));
|
||||
border-radius: var(--uui-border-radius);
|
||||
padding: var(--uui-size-space-5);
|
||||
box-sizing: border-box;
|
||||
|
||||
}
|
||||
|
||||
span {
|
||||
|
||||
@@ -133,7 +133,7 @@ export class UmbDashboardPublishedStatusElement extends UmbLitElement {
|
||||
|
||||
render() {
|
||||
return html`
|
||||
<umb-debug enabled></umb-debug>
|
||||
<umb-debug enabled useDialog></umb-debug>
|
||||
<uui-box headline="Published Cache Status">
|
||||
<p>${this._publishedStatusText}</p>
|
||||
<uui-button
|
||||
|
||||
@@ -1,28 +1,39 @@
|
||||
import { UUITextStyles } from '@umbraco-ui/uui-css/lib';
|
||||
import { css, html, LitElement, nothing, TemplateResult } from 'lit';
|
||||
import { css, html, nothing, TemplateResult } from 'lit';
|
||||
import { customElement, property, state } from 'lit/decorators.js';
|
||||
import { UmbContextDebugRequest } from '@umbraco-cms/context-api';
|
||||
import { UmbLitElement } from '@umbraco-cms/element';
|
||||
import { UmbModalService, UMB_MODAL_SERVICE_CONTEXT_TOKEN } from '@umbraco-cms/modal';
|
||||
|
||||
@customElement('umb-debug')
|
||||
export class UmbDebug extends LitElement {
|
||||
export class UmbDebug extends UmbLitElement {
|
||||
static styles = [
|
||||
UUITextStyles,
|
||||
css`
|
||||
css`
|
||||
#container {
|
||||
display: block;
|
||||
font-family: monospace;
|
||||
|
||||
z-index: 10000;
|
||||
|
||||
position:relative;
|
||||
width: 100%;
|
||||
padding: 10px 0;
|
||||
}
|
||||
|
||||
uui-badge {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
uui-icon {
|
||||
font-size: 15px;
|
||||
}
|
||||
|
||||
.events {
|
||||
background-color: var(--uui-color-danger);
|
||||
color: var(--uui-color-selected-contrast);
|
||||
max-height: 0;
|
||||
transition: max-height 0.15s ease-out;
|
||||
transition: max-height 0.25s ease-out;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
@@ -44,57 +55,97 @@ export class UmbDebug extends LitElement {
|
||||
@property({ reflect: true, type: Boolean })
|
||||
enabled = false;
|
||||
|
||||
@property({ reflect: true, type: Boolean })
|
||||
useDialog = false;
|
||||
|
||||
@property()
|
||||
contextAliases = new Map();
|
||||
contexts = new Map();
|
||||
|
||||
@state()
|
||||
private _debugPaneOpen = false;
|
||||
|
||||
private _toggleDebugPane() {
|
||||
this._debugPaneOpen = !this._debugPaneOpen;
|
||||
}
|
||||
private _modalService?: UmbModalService;
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
this.consumeContext(UMB_MODAL_SERVICE_CONTEXT_TOKEN, (modalService) => {
|
||||
this._modalService = modalService;
|
||||
});
|
||||
}
|
||||
|
||||
connectedCallback(): void {
|
||||
super.connectedCallback();
|
||||
|
||||
// Dispatch it
|
||||
this.dispatchEvent(
|
||||
new UmbContextDebugRequest((instances: Map<any, any>) => {
|
||||
console.log('I have contexts now', instances);
|
||||
new UmbContextDebugRequest((contexts: Map<any, any>) => {
|
||||
|
||||
this.contextAliases = instances;
|
||||
// The Contexts are collected
|
||||
// When travelling up through the DOM from this element
|
||||
// to the root of <umb-app> which then uses the callback prop
|
||||
// of the this event tha has been raised to assign the contexts
|
||||
// back to this property of the WebComponent
|
||||
this.contexts = contexts;
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
render() {
|
||||
if (this.enabled) {
|
||||
return html`
|
||||
<div id="container">
|
||||
<uui-button color="danger" look="primary" @click="${this._toggleDebugPane}">
|
||||
<uui-icon name="umb:bug"></uui-icon>
|
||||
Debug
|
||||
</uui-button>
|
||||
if (this.enabled) {
|
||||
return this.useDialog ? this._renderDialog() : this._renderPanel();
|
||||
} else {
|
||||
return nothing;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
<div class="events ${this._debugPaneOpen ? 'open' : ''}">
|
||||
<div>
|
||||
<h4>Context Aliases to consume</h4>
|
||||
<ul>
|
||||
${this._renderContextAliases()}
|
||||
</ul>
|
||||
</div>
|
||||
private _toggleDebugPane() {
|
||||
this._debugPaneOpen = !this._debugPaneOpen;
|
||||
}
|
||||
|
||||
private _openDialog() {
|
||||
const modalHandler = this._modalService?.open('umb-debug-modal-layout', { size: 'medium', type: 'sidebar', data:{ contexts: this.contexts }});
|
||||
|
||||
modalHandler?.onClose().then((data) => {
|
||||
// if any data is supplied on close, it will be available here.
|
||||
console.log('modal closed data', data);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
|
||||
private _renderDialog() {
|
||||
return html`
|
||||
<div id="container">
|
||||
<uui-badge color="danger" look="primary" attention @click="${this._openDialog}">
|
||||
<uui-icon name="umb:bug"></uui-icon> Debug
|
||||
</uui-badge>
|
||||
</div>`;
|
||||
}
|
||||
|
||||
private _renderPanel(){
|
||||
return html`
|
||||
<div id="container">
|
||||
<uui-button color="danger" look="primary" @click="${this._toggleDebugPane}">
|
||||
<uui-icon name="umb:bug"></uui-icon>
|
||||
Debug
|
||||
</uui-button>
|
||||
|
||||
<div class="events ${this._debugPaneOpen ? 'open' : ''}">
|
||||
<div>
|
||||
<h4>Context Aliases to consume</h4>
|
||||
<ul>
|
||||
${this._renderContextAliases()}
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
return nothing;
|
||||
</div>`;
|
||||
}
|
||||
|
||||
private _renderContextAliases() {
|
||||
const aliases = [];
|
||||
|
||||
for (const [alias, instance] of this.contextAliases) {
|
||||
for (const [alias, instance] of this.contexts) {
|
||||
aliases.push(
|
||||
html` <li>
|
||||
Context: <strong>${alias}</strong>
|
||||
@@ -124,10 +175,6 @@ export class UmbDebug extends LitElement {
|
||||
if (key.startsWith('_')) {
|
||||
continue;
|
||||
}
|
||||
// Goes KABOOM - if try to loop over the class/object
|
||||
// instanceKeys.push(html`<li>${key} = ${instance[key]}</li>`);
|
||||
|
||||
// console.log(`key: ${key} = ${value} TYPEOF: ${typeof value}`);
|
||||
|
||||
const value = instance[key];
|
||||
if (typeof value === 'string') {
|
||||
|
||||
@@ -0,0 +1,163 @@
|
||||
import { css, html, nothing, TemplateResult } from 'lit';
|
||||
import { customElement, property } from 'lit/decorators.js';
|
||||
import { UUITextStyles } from '@umbraco-ui/uui-css';
|
||||
import { UmbModalHandler, UmbModalLayoutElement } from '@umbraco-cms/modal';
|
||||
|
||||
@customElement('umb-debug-modal-layout')
|
||||
export class UmbDebugModalLayout extends UmbModalLayoutElement {
|
||||
static styles = [
|
||||
UUITextStyles,
|
||||
css`
|
||||
uui-dialog-layout {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: 100%;
|
||||
|
||||
padding: var(--uui-size-space-5);
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
uui-scroll-container {
|
||||
overflow-y: scroll;
|
||||
max-height: 100%;
|
||||
min-height: 0;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
uui-icon {
|
||||
vertical-align: text-top;
|
||||
color: var(--uui-color-danger);
|
||||
}
|
||||
|
||||
.context {
|
||||
padding:15px 0;
|
||||
border-bottom:1px solid var(--uui-color-danger-emphasis);
|
||||
}
|
||||
|
||||
h3 {
|
||||
margin-top: 0;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
h3 > span {
|
||||
border-radius: var(--uui-size-4);
|
||||
background-color: var(--uui-color-danger);
|
||||
color: var(--uui-color-danger-contrast);
|
||||
padding: 8px;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
|
||||
ul {
|
||||
margin-top: 0;
|
||||
}
|
||||
`,
|
||||
];
|
||||
|
||||
|
||||
// the modal handler will be injected into the element when the modal is opened.
|
||||
@property({ attribute: false })
|
||||
modalHandler?: UmbModalHandler;
|
||||
|
||||
private _handleClose() {
|
||||
/* Optional data of any type can be applied to the close method to pass it
|
||||
to the modal parent through the onClose promise. */
|
||||
//this.modalHandler?.close('MY DATA');
|
||||
this.modalHandler?.close();
|
||||
}
|
||||
|
||||
render() {
|
||||
return html`
|
||||
<uui-dialog-layout>
|
||||
<span slot="headline">
|
||||
<uui-icon name="umb:bug"></uui-icon> Debug: Contexts
|
||||
</span>
|
||||
<uui-scroll-container id="field-settings">
|
||||
${this._renderContextAliases()}
|
||||
</uui-scroll-container>
|
||||
<uui-button slot="actions" look="primary" label="Close sidebar" @click="${this._handleClose}">Close</uui-button>
|
||||
</uui-dialog-layout>
|
||||
`;
|
||||
}
|
||||
|
||||
private _renderContextAliases() {
|
||||
if(!this.data) {
|
||||
return nothing;
|
||||
}
|
||||
|
||||
const aliases = [];
|
||||
for (const [alias, instance] of this.data.contexts) {
|
||||
aliases.push(
|
||||
html`
|
||||
<div class="context">
|
||||
<h3>${alias} <span>${typeof instance}</span></h3>
|
||||
${this._renderInstance(instance)}
|
||||
</div>`
|
||||
);
|
||||
}
|
||||
|
||||
return aliases;
|
||||
}
|
||||
|
||||
private _renderInstance(instance: any) {
|
||||
const instanceKeys: TemplateResult[] = [];
|
||||
|
||||
if (typeof instance === 'function') {
|
||||
return instanceKeys.push(html`<li>Callable Function</li>`);
|
||||
} else if (typeof instance === 'object') {
|
||||
const methodNames = this.getClassMethodNames(instance);
|
||||
if (methodNames.length) {
|
||||
instanceKeys.push(
|
||||
html`
|
||||
<h4>Methods</h4>
|
||||
<ul>
|
||||
${methodNames.map((methodName) => html`<li>${methodName}</li>`)}
|
||||
</ul>
|
||||
`);
|
||||
}
|
||||
|
||||
instanceKeys.push(html`<h4>Properties</h4>`);
|
||||
|
||||
for (const key in instance) {
|
||||
if (key.startsWith('_')) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const value = instance[key];
|
||||
if (typeof value === 'string') {
|
||||
instanceKeys.push(html`<li>${key} = ${value}</li>`);
|
||||
} else {
|
||||
instanceKeys.push(html`<li>${key} Type (${typeof value})</li>`);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
instanceKeys.push(html`<li>Context is a primitive with value: ${instance}</li>`);
|
||||
}
|
||||
|
||||
return instanceKeys;
|
||||
}
|
||||
|
||||
|
||||
private getClassMethodNames(klass: any) {
|
||||
const isGetter = (x: any, name: string): boolean => !!(Object.getOwnPropertyDescriptor(x, name) || {}).get;
|
||||
const isFunction = (x: any, name: string): boolean => typeof x[name] === 'function';
|
||||
const deepFunctions = (x: any): any =>
|
||||
x !== Object.prototype &&
|
||||
Object.getOwnPropertyNames(x)
|
||||
.filter((name) => isGetter(x, name) || isFunction(x, name))
|
||||
.concat(deepFunctions(Object.getPrototypeOf(x)) || []);
|
||||
const distinctDeepFunctions = (klass: any) => Array.from(new Set(deepFunctions(klass)));
|
||||
|
||||
const allMethods =
|
||||
typeof klass.prototype === 'undefined'
|
||||
? distinctDeepFunctions(klass)
|
||||
: Object.getOwnPropertyNames(klass.prototype);
|
||||
return allMethods.filter((name: any) => name !== 'constructor' && !name.startsWith('_'));
|
||||
}
|
||||
}
|
||||
|
||||
declare global {
|
||||
interface HTMLElementTagNameMap {
|
||||
'umb-debug-modal-layout': UmbDebugModalLayout;
|
||||
}
|
||||
}
|
||||
@@ -31,4 +31,5 @@ import './input-document-picker/input-document-picker.element';
|
||||
import './empty-state/empty-state.element';
|
||||
import './color-picker/color-picker.element';
|
||||
|
||||
import './debug/debug.element';
|
||||
import './debug/debug.element';
|
||||
import './debug/debug.modal.element';
|
||||
Reference in New Issue
Block a user