Migrate developer events tools to LitElement (#17869)

This commit is contained in:
Simon Lamon 2023-09-28 16:58:16 +02:00 committed by GitHub
parent 44748df3ac
commit 13a691606f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 268 additions and 292 deletions

View File

@ -1,219 +0,0 @@
import "@material/mwc-button";
import "@polymer/iron-flex-layout/iron-flex-layout-classes";
import { html } from "@polymer/polymer/lib/utils/html-tag";
/* eslint-plugin-disable lit */
import { PolymerElement } from "@polymer/polymer/polymer-element";
import { load } from "js-yaml";
import "../../../components/ha-code-editor";
import "../../../components/ha-textfield";
import { showAlertDialog } from "../../../dialogs/generic/show-dialog-box";
import { EventsMixin } from "../../../mixins/events-mixin";
import LocalizeMixin from "../../../mixins/localize-mixin";
import "../../../styles/polymer-ha-style";
import { documentationUrl } from "../../../util/documentation-url";
import "./event-subscribe-card";
import "./events-list";
const ERROR_SENTINEL = {};
/*
* @appliesMixin EventsMixin
* @appliesMixin LocalizeMixin
*/
class HaPanelDevEvent extends EventsMixin(LocalizeMixin(PolymerElement)) {
static get template() {
return html`
<style include="ha-style iron-flex iron-positioning"></style>
<style>
.content {
padding: 16px;
padding: max(16px, env(safe-area-inset-top))
max(16px, env(safe-area-inset-right))
max(16px, env(safe-area-inset-bottom))
max(16px, env(safe-area-inset-left));
max-width: 1200px;
margin: auto;
}
:host {
-ms-user-select: initial;
-webkit-user-select: initial;
-moz-user-select: initial;
@apply --paper-font-body1;
display: block;
}
.inputs {
max-width: 400px;
}
mwc-button {
margin-top: 8px;
}
ha-textfield {
display: block;
}
.code-editor {
margin-right: 16px;
margin-inline-start: initial;
margin-inline-end: 16px;
direction: var(--direction);
}
.header {
@apply --paper-font-title;
}
event-subscribe-card {
display: block;
margin: 16px 16px 0 0;
margin-inline-start: initial;
margin-inline-end: 16px;
direction: var(--direction);
}
a {
color: var(--primary-color);
}
</style>
<div class$="[[computeFormClasses(narrow)]]">
<div class="flex">
<p>
[[localize( 'ui.panel.developer-tools.tabs.events.description' )]]
<a
href="[[_computeDocumentationUrl(hass)]]"
target="_blank"
rel="noreferrer"
>
[[localize( 'ui.panel.developer-tools.tabs.events.documentation'
)]]
</a>
</p>
<div class="inputs">
<ha-textfield
label="[[localize(
'ui.panel.developer-tools.tabs.events.type'
)]]"
autofocus
required
value="[[eventType]]"
on-change="eventTypeChanged"
></ha-textfield>
<p>[[localize( 'ui.panel.developer-tools.tabs.events.data' )]]</p>
</div>
<div class="code-editor">
<ha-code-editor
mode="yaml"
value="[[eventData]]"
error="[[!validJSON]]"
on-value-changed="_yamlChanged"
dir="ltr"
></ha-code-editor>
</div>
<mwc-button on-click="fireEvent" raised disabled="[[!validJSON]]"
>[[localize( 'ui.panel.developer-tools.tabs.events.fire_event'
)]]</mwc-button
>
<event-subscribe-card hass="[[hass]]"></event-subscribe-card>
</div>
<div>
<div class="header">
[[localize( 'ui.panel.developer-tools.tabs.events.active_listeners'
)]]
</div>
<events-list
on-event-selected="eventSelected"
hass="[[hass]]"
></events-list>
</div>
</div>
`;
}
static get properties() {
return {
hass: {
type: Object,
},
eventType: {
type: String,
value: "",
},
eventData: {
type: String,
value: "",
},
parsedJSON: {
type: Object,
computed: "_computeParsedEventData(eventData)",
},
validJSON: {
type: Boolean,
computed: "_computeValidJSON(parsedJSON)",
},
};
}
eventSelected(ev) {
this.eventType = ev.detail.eventType;
}
eventTypeChanged(ev) {
this.eventType = ev.target.value;
}
_computeParsedEventData(eventData) {
try {
return eventData.trim() ? load(eventData) : {};
} catch (err) {
return ERROR_SENTINEL;
}
}
_computeDocumentationUrl(hass) {
return documentationUrl(hass, "/docs/configuration/events/");
}
_computeValidJSON(parsedJSON) {
return parsedJSON !== ERROR_SENTINEL;
}
_yamlChanged(ev) {
this.eventData = ev.detail.value;
}
fireEvent() {
if (!this.eventType) {
showAlertDialog(this, {
text: this.hass.localize(
"ui.panel.developer-tools.tabs.events.alert_event_type"
),
});
return;
}
this.hass
.callApi("POST", "events/" + this.eventType, this.parsedJSON)
.then(() => {
this.fire("hass-notification", {
message: this.hass.localize(
"ui.panel.developer-tools.tabs.events.notification_event_fired",
"type",
this.eventType
),
});
});
}
computeFormClasses(narrow) {
return narrow ? "content" : "content layout horizontal";
}
}
customElements.define("developer-tools-event", HaPanelDevEvent);

View File

@ -0,0 +1,184 @@
import { CSSResultGroup, LitElement, TemplateResult, css, html } from "lit";
import { customElement, property, state } from "lit/decorators";
import "@material/mwc-button";
import "../../../components/ha-yaml-editor";
import "../../../components/ha-textfield";
import { showAlertDialog } from "../../../dialogs/generic/show-dialog-box";
import { documentationUrl } from "../../../util/documentation-url";
import "./event-subscribe-card";
import "./events-list";
import { haStyle } from "../../../resources/styles";
import { HomeAssistant } from "../../../types";
import { fireEvent } from "../../../common/dom/fire_event";
@customElement("developer-tools-event")
class HaPanelDevEvent extends LitElement {
@property({ attribute: false }) public hass!: HomeAssistant;
@property({ type: Boolean }) public narrow!: boolean;
@state() private _eventType: string = "";
@state() private _eventData: object = {};
@state() private _isValid: boolean = true;
protected render(): TemplateResult {
return html`
<div class=${this.narrow ? "content" : "content layout horizontal"}>
<div class="flex">
<p>
${this.hass.localize(
"ui.panel.developer-tools.tabs.events.description"
)}
<a
href=${documentationUrl(this.hass, "/docs/configuration/events/")}
target="_blank"
rel="noreferrer"
>
${this.hass.localize(
"ui.panel.developer-tools.tabs.events.documentation"
)}
</a>
</p>
<div class="inputs">
<ha-textfield
.label=${this.hass.localize(
"ui.panel.developer-tools.tabs.events.type"
)}
autofocus
required
.value=${this._eventType}
@change=${this._eventTypeChanged}
></ha-textfield>
<p>
${this.hass.localize("ui.panel.developer-tools.tabs.events.data")}
</p>
</div>
<div class="code-editor">
<ha-yaml-editor
.value=${this._eventData}
.error=${!this._isValid}
@value-changed=${this._yamlChanged}
></ha-yaml-editor>
</div>
<mwc-button
@click=${this._fireEvent}
raised
.disabled=${!this._isValid}
>${this.hass.localize(
"ui.panel.developer-tools.tabs.events.fire_event"
)}</mwc-button
>
<event-subscribe-card .hass=${this.hass}></event-subscribe-card>
</div>
<div>
<div class="header">
${this.hass.localize(
"ui.panel.developer-tools.tabs.events.active_listeners"
)}
</div>
<events-list
@event-selected=${this._eventSelected}
.hass=${this.hass}
></events-list>
</div>
</div>
`;
}
private _eventSelected(ev) {
this._eventType = ev.detail.eventType;
}
private _eventTypeChanged(ev) {
this._eventType = ev.target.value;
}
private _yamlChanged(ev) {
this._eventData = ev.detail.value;
this._isValid = ev.detail.isValid;
}
private async _fireEvent() {
if (!this._eventType) {
showAlertDialog(this, {
text: this.hass.localize(
"ui.panel.developer-tools.tabs.events.alert_event_type"
),
});
return;
}
await this.hass.callApi(
"POST",
`events/${this._eventType}`,
this._eventData
);
fireEvent(this, "hass-notification", {
message: this.hass.localize(
"ui.panel.developer-tools.tabs.events.notification_event_fired",
{ type: this._eventType }
),
});
}
static get styles(): CSSResultGroup {
return [
haStyle,
css`
.content {
padding: 16px;
padding: max(16px, env(safe-area-inset-top))
max(16px, env(safe-area-inset-right))
max(16px, env(safe-area-inset-bottom))
max(16px, env(safe-area-inset-left));
max-width: 1200px;
margin: auto;
}
:host {
-ms-user-select: initial;
-webkit-user-select: initial;
-moz-user-select: initial;
@apply --paper-font-body1;
display: block;
}
.inputs {
max-width: 400px;
}
mwc-button {
margin-top: 8px;
}
ha-textfield {
display: block;
}
.header {
@apply --paper-font-title;
}
event-subscribe-card {
display: block;
margin: 16px 16px 0 0;
margin-inline-start: initial;
margin-inline-end: 16px;
direction: var(--direction);
}
a {
color: var(--primary-color);
}
`,
];
}
}
declare global {
interface HTMLElementTagNameMap {
"developer-tools-event": HaPanelDevEvent;
}
}

View File

@ -1,73 +0,0 @@
import { html } from "@polymer/polymer/lib/utils/html-tag";
/* eslint-plugin-disable lit */
import { PolymerElement } from "@polymer/polymer/polymer-element";
import { stringCompare } from "../../../common/string/compare";
import { EventsMixin } from "../../../mixins/events-mixin";
import LocalizeMixin from "../../../mixins/localize-mixin";
/*
* @appliesMixin EventsMixin
* @appliesMixin LocalizeMixin
*/
class EventsList extends EventsMixin(LocalizeMixin(PolymerElement)) {
static get template() {
return html`
<style>
ul {
margin: 0;
padding: 0;
}
li {
list-style: none;
line-height: 2em;
}
a {
color: var(--primary-color);
}
</style>
<ul>
<template is="dom-repeat" items="[[events]]" as="event">
<li>
<a href="#" on-click="eventSelected">{{event.event}}</a>
<span>
[[localize(
"ui.panel.developer-tools.tabs.events.count_listeners", "count",
event.listener_count )]]</span
>
</li>
</template>
</ul>
`;
}
static get properties() {
return {
hass: {
type: Object,
},
events: {
type: Array,
},
};
}
connectedCallback() {
super.connectedCallback();
this.hass.callApi("GET", "events").then((events) => {
this.events = events.sort((e1, e2) =>
stringCompare(e1.event, e2.event, this.hass.locale.language)
);
});
}
eventSelected(ev) {
ev.preventDefault();
this.fire("event-selected", { eventType: ev.model.event.event });
}
}
customElements.define("events-list", EventsList);

View File

@ -0,0 +1,84 @@
import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit";
import { customElement, property } from "lit/decorators";
import { stringCompare } from "../../../common/string/compare";
import { fireEvent } from "../../../common/dom/fire_event";
import { HomeAssistant } from "../../../types";
interface EventListenerCount {
event: string;
listener_count: number;
}
@customElement("events-list")
class EventsList extends LitElement {
@property({ attribute: false }) public hass!: HomeAssistant;
@property() public events: EventListenerCount[] = [];
protected render(): TemplateResult {
return html`
<ul>
${this.events.map(
(event) => html`
<li>
<a href="#" @click=${this._eventSelected} .event=${event.event}
>${event.event}</a
>
<span>
${this.hass.localize(
"ui.panel.developer-tools.tabs.events.count_listeners",
{
count: event.listener_count,
}
)}</span
>
</li>
`
)}
</ul>
`;
}
protected async firstUpdated() {
const events = await this.hass.callApi<EventListenerCount[]>(
"GET",
"events"
);
this.events = events.sort((e1, e2) =>
stringCompare(e1.event, e2.event, this.hass.locale.language)
);
}
private _eventSelected(ev: Event) {
ev.preventDefault();
const event: string = (ev.currentTarget! as any).event;
fireEvent(this, "event-selected", { eventType: event });
}
static get styles(): CSSResultGroup {
return css`
ul {
margin: 0;
padding: 0;
}
li {
list-style: none;
line-height: 2em;
}
a {
color: var(--primary-color);
}
`;
}
}
declare global {
interface HTMLElementTagNameMap {
"events-list": EventsList;
}
interface HASSDomEvents {
"event-selected": { eventType: string };
}
}