mirror of
https://github.com/home-assistant/frontend.git
synced 2025-07-23 17:26:42 +00:00
Fix mwc-list/menu actions (#6442)
* Fix mwc-list/menu actions Fix double actions when using request-selected * Update ha-button-menu.ts * Automation menu styling * Update src/panels/lovelace/hui-root.ts Co-authored-by: Zack Arnett <arnett.zackary@gmail.com> * Move Co-authored-by: Zack Arnett <arnett.zackary@gmail.com>
This commit is contained in:
parent
e08c10315e
commit
4404a1173b
@ -25,6 +25,7 @@ import { HomeAssistant, Route } from "../../../src/types";
|
||||
import { showRepositoriesDialog } from "../dialogs/repositories/show-dialog-repositories";
|
||||
import { supervisorTabs } from "../hassio-tabs";
|
||||
import "./hassio-addon-repository";
|
||||
import { ActionDetail } from "@material/mwc-list/mwc-list-foundation";
|
||||
|
||||
const sortRepos = (a: HassioAddonRepository, b: HassioAddonRepository) => {
|
||||
if (a.slug === "local") {
|
||||
@ -97,14 +98,18 @@ class HassioAddonStore extends LitElement {
|
||||
.tabs=${supervisorTabs}
|
||||
>
|
||||
<span slot="header">Add-on store</span>
|
||||
<ha-button-menu corner="BOTTOM_START" slot="toolbar-icon">
|
||||
<ha-button-menu
|
||||
corner="BOTTOM_START"
|
||||
slot="toolbar-icon"
|
||||
@action=${this._handleAction}
|
||||
>
|
||||
<mwc-icon-button slot="trigger" alt="menu">
|
||||
<ha-svg-icon path=${mdiDotsVertical}></ha-svg-icon>
|
||||
</mwc-icon-button>
|
||||
<mwc-list-item @request-selected=${this._manageRepositories}>
|
||||
<mwc-list-item>
|
||||
Repositories
|
||||
</mwc-list-item>
|
||||
<mwc-list-item @request-selected=${this.refreshData}>
|
||||
<mwc-list-item>
|
||||
Reload
|
||||
</mwc-list-item>
|
||||
</ha-button-menu>
|
||||
@ -143,6 +148,17 @@ class HassioAddonStore extends LitElement {
|
||||
this._loadData();
|
||||
}
|
||||
|
||||
private _handleAction(ev: CustomEvent<ActionDetail>) {
|
||||
switch (ev.detail.index) {
|
||||
case 0:
|
||||
this._manageRepositories();
|
||||
break;
|
||||
case 1:
|
||||
this.refreshData();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private apiCalled(ev) {
|
||||
if (ev.detail.success) {
|
||||
this._loadData();
|
||||
|
14
src/common/mwc/handle-request-selected-event.ts
Normal file
14
src/common/mwc/handle-request-selected-event.ts
Normal file
@ -0,0 +1,14 @@
|
||||
import {
|
||||
RequestSelectedDetail,
|
||||
ListItem,
|
||||
} from "@material/mwc-list/mwc-list-item";
|
||||
|
||||
export const shouldHandleRequestSelectedEvent = (
|
||||
ev: CustomEvent<RequestSelectedDetail>
|
||||
): boolean => {
|
||||
if (!ev.detail.selected && ev.detail.source !== "property") {
|
||||
return false;
|
||||
}
|
||||
(ev.target as ListItem).selected = false;
|
||||
return true;
|
||||
};
|
@ -18,14 +18,30 @@ import "./ha-icon-button";
|
||||
export class HaButtonMenu extends LitElement {
|
||||
@property() public corner: Corner = "TOP_START";
|
||||
|
||||
@property({ type: Boolean }) public multi = false;
|
||||
|
||||
@property({ type: Boolean }) public activatable = false;
|
||||
|
||||
@query("mwc-menu") private _menu?: Menu;
|
||||
|
||||
public get items() {
|
||||
return this._menu?.items;
|
||||
}
|
||||
|
||||
public get selected() {
|
||||
return this._menu?.selected;
|
||||
}
|
||||
|
||||
protected render(): TemplateResult {
|
||||
return html`
|
||||
<div @click=${this._handleClick}>
|
||||
<slot name="trigger"></slot>
|
||||
</div>
|
||||
<mwc-menu .corner=${this.corner}>
|
||||
<mwc-menu
|
||||
.corner=${this.corner}
|
||||
.multi=${this.multi}
|
||||
.activatable=${this.activatable}
|
||||
>
|
||||
<slot></slot>
|
||||
</mwc-menu>
|
||||
`;
|
||||
|
@ -18,6 +18,7 @@ import "@polymer/paper-input/paper-input";
|
||||
import "@material/mwc-list/mwc-list";
|
||||
import "./date-range-picker";
|
||||
import { computeRTLDirection } from "../common/util/compute_rtl";
|
||||
import { ActionDetail } from "@material/mwc-list/mwc-list-foundation";
|
||||
|
||||
export interface DateRangePickerRanges {
|
||||
[key: string]: [Date, Date];
|
||||
@ -85,15 +86,9 @@ export class HaDateRangePicker extends LitElement {
|
||||
class="date-range-ranges"
|
||||
.dir=${this._rtlDirection}
|
||||
>
|
||||
<mwc-list @request-selected=${this._setDateRange}>
|
||||
${Object.entries(this.ranges).map(
|
||||
([name, dates]) => html`<mwc-list-item
|
||||
.activated=${this.startDate.getTime() ===
|
||||
dates[0].getTime() &&
|
||||
this.endDate.getTime() === dates[1].getTime()}
|
||||
.startDate=${dates[0]}
|
||||
.endDate=${dates[1]}
|
||||
>
|
||||
<mwc-list @action=${this._setDateRange} activatable>
|
||||
${Object.keys(this.ranges).map(
|
||||
(name) => html`<mwc-list-item>
|
||||
${name}
|
||||
</mwc-list-item>`
|
||||
)}
|
||||
@ -124,12 +119,10 @@ export class HaDateRangePicker extends LitElement {
|
||||
);
|
||||
}
|
||||
|
||||
private _setDateRange(ev: Event) {
|
||||
const target = ev.target as any;
|
||||
const startDate = target.startDate;
|
||||
const endDate = target.endDate;
|
||||
private _setDateRange(ev: CustomEvent<ActionDetail>) {
|
||||
const dateRange = Object.values(this.ranges!)[ev.detail.index];
|
||||
const dateRangePicker = this._dateRangePicker;
|
||||
dateRangePicker.clickRange([startDate, endDate]);
|
||||
dateRangePicker.clickRange(dateRange);
|
||||
dateRangePicker.clickedApply();
|
||||
}
|
||||
|
||||
|
@ -29,8 +29,9 @@ import "./types/ha-automation-action-event";
|
||||
import "./types/ha-automation-action-scene";
|
||||
import "./types/ha-automation-action-service";
|
||||
import "./types/ha-automation-action-wait_template";
|
||||
import type { RequestSelectedDetail } from "@material/mwc-list/mwc-list-item";
|
||||
import { handleStructError } from "../../../lovelace/common/structs/handle-errors";
|
||||
import { ActionDetail } from "@material/mwc-list/mwc-list-foundation";
|
||||
import { haStyle } from "../../../../resources/styles";
|
||||
|
||||
const OPTIONS = [
|
||||
"condition",
|
||||
@ -134,17 +135,14 @@ export default class HaAutomationActionRow extends LitElement {
|
||||
</mwc-icon-button>
|
||||
`
|
||||
: ""}
|
||||
<ha-button-menu corner="BOTTOM_START">
|
||||
<ha-button-menu corner="BOTTOM_START" @action=${this._handleAction}>
|
||||
<mwc-icon-button
|
||||
slot="trigger"
|
||||
.title=${this.hass.localize("ui.common.menu")}
|
||||
.label=${this.hass.localize("ui.common.overflow_menu")}
|
||||
><ha-svg-icon path=${mdiDotsVertical}></ha-svg-icon>
|
||||
</mwc-icon-button>
|
||||
<mwc-list-item
|
||||
@request-selected=${this._switchYamlMode}
|
||||
.disabled=${!this._uiModeAvailable}
|
||||
>
|
||||
<mwc-list-item .disabled=${!this._uiModeAvailable}>
|
||||
${yamlMode
|
||||
? this.hass.localize(
|
||||
"ui.panel.config.automation.editor.edit_ui"
|
||||
@ -158,7 +156,7 @@ export default class HaAutomationActionRow extends LitElement {
|
||||
"ui.panel.config.automation.editor.actions.duplicate"
|
||||
)}
|
||||
</mwc-list-item>
|
||||
<mwc-list-item @request-selected=${this._onDelete}>
|
||||
<mwc-list-item>
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.automation.editor.actions.delete"
|
||||
)}
|
||||
@ -177,21 +175,20 @@ export default class HaAutomationActionRow extends LitElement {
|
||||
: ""}
|
||||
${yamlMode
|
||||
? html`
|
||||
<div style="margin-right: 24px;">
|
||||
${selected === -1
|
||||
? html`
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.automation.editor.actions.unsupported_action",
|
||||
"action",
|
||||
type
|
||||
)}
|
||||
`
|
||||
: ""}
|
||||
<ha-yaml-editor
|
||||
.defaultValue=${this.action}
|
||||
@value-changed=${this._onYamlChange}
|
||||
></ha-yaml-editor>
|
||||
</div>
|
||||
${selected === -1
|
||||
? html`
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.automation.editor.actions.unsupported_action",
|
||||
"action",
|
||||
type
|
||||
)}
|
||||
`
|
||||
: ""}
|
||||
<h2>Edit in YAML</h2>
|
||||
<ha-yaml-editor
|
||||
.defaultValue=${this.action}
|
||||
@value-changed=${this._onYamlChange}
|
||||
></ha-yaml-editor>
|
||||
`
|
||||
: html`
|
||||
<paper-dropdown-menu-light
|
||||
@ -243,6 +240,19 @@ export default class HaAutomationActionRow extends LitElement {
|
||||
fireEvent(this, "move-action", { direction: "down" });
|
||||
}
|
||||
|
||||
private _handleAction(ev: CustomEvent<ActionDetail>) {
|
||||
switch (ev.detail.index) {
|
||||
case 0:
|
||||
this._switchYamlMode();
|
||||
break;
|
||||
case 1:
|
||||
break;
|
||||
case 2:
|
||||
this._onDelete();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private _onDelete() {
|
||||
showConfirmationDialog(this, {
|
||||
text: this.hass.localize(
|
||||
@ -288,40 +298,34 @@ export default class HaAutomationActionRow extends LitElement {
|
||||
fireEvent(this, "value-changed", { value: ev.detail.value });
|
||||
}
|
||||
|
||||
private _switchYamlMode(ev: CustomEvent<RequestSelectedDetail>) {
|
||||
if (ev.detail.source !== "interaction") {
|
||||
return;
|
||||
}
|
||||
private _switchYamlMode() {
|
||||
this._yamlMode = !this._yamlMode;
|
||||
}
|
||||
|
||||
static get styles(): CSSResult {
|
||||
return css`
|
||||
.card-menu {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
z-index: 3;
|
||||
--mdc-theme-text-primary-on-background: var(--primary-text-color);
|
||||
}
|
||||
.rtl .card-menu {
|
||||
right: auto;
|
||||
left: 0;
|
||||
}
|
||||
ha-button-menu {
|
||||
margin: 8px;
|
||||
}
|
||||
mwc-list-item[disabled] {
|
||||
--mdc-theme-text-primary-on-background: var(--disabled-text-color);
|
||||
}
|
||||
.warning {
|
||||
color: var(--warning-color);
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
.warning ul {
|
||||
margin: 4px 0;
|
||||
}
|
||||
`;
|
||||
static get styles(): CSSResult[] {
|
||||
return [
|
||||
haStyle,
|
||||
css`
|
||||
.card-menu {
|
||||
float: right;
|
||||
z-index: 3;
|
||||
--mdc-theme-text-primary-on-background: var(--primary-text-color);
|
||||
}
|
||||
.rtl .card-menu {
|
||||
float: left;
|
||||
}
|
||||
mwc-list-item[disabled] {
|
||||
--mdc-theme-text-primary-on-background: var(--disabled-text-color);
|
||||
}
|
||||
.warning {
|
||||
color: var(--warning-color);
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
.warning ul {
|
||||
margin: 4px 0;
|
||||
}
|
||||
`,
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2,7 +2,13 @@ import "@polymer/paper-dropdown-menu/paper-dropdown-menu-light";
|
||||
import "@polymer/paper-item/paper-item";
|
||||
import "@polymer/paper-listbox/paper-listbox";
|
||||
import type { PaperListboxElement } from "@polymer/paper-listbox/paper-listbox";
|
||||
import { customElement, html, LitElement, property } from "lit-element";
|
||||
import {
|
||||
customElement,
|
||||
html,
|
||||
LitElement,
|
||||
property,
|
||||
CSSResult,
|
||||
} from "lit-element";
|
||||
import { dynamicElement } from "../../../../common/dom/dynamic-element-directive";
|
||||
import { fireEvent } from "../../../../common/dom/fire_event";
|
||||
import "../../../../components/ha-card";
|
||||
@ -19,6 +25,7 @@ import "./types/ha-automation-condition-sun";
|
||||
import "./types/ha-automation-condition-template";
|
||||
import "./types/ha-automation-condition-time";
|
||||
import "./types/ha-automation-condition-zone";
|
||||
import { haStyle } from "../../../../resources/styles";
|
||||
|
||||
const OPTIONS = [
|
||||
"device",
|
||||
@ -47,21 +54,20 @@ export default class HaAutomationConditionEditor extends LitElement {
|
||||
return html`
|
||||
${yamlMode
|
||||
? html`
|
||||
<div style="margin-right: 24px;">
|
||||
${selected === -1
|
||||
? html`
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.automation.editor.conditions.unsupported_condition",
|
||||
"condition",
|
||||
this.condition.condition
|
||||
)}
|
||||
`
|
||||
: ""}
|
||||
<ha-yaml-editor
|
||||
.defaultValue=${this.condition}
|
||||
@value-changed=${this._onYamlChange}
|
||||
></ha-yaml-editor>
|
||||
</div>
|
||||
${selected === -1
|
||||
? html`
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.automation.editor.conditions.unsupported_condition",
|
||||
"condition",
|
||||
this.condition.condition
|
||||
)}
|
||||
`
|
||||
: ""}
|
||||
<h2>Edit in YAML</h2>
|
||||
<ha-yaml-editor
|
||||
.defaultValue=${this.condition}
|
||||
@value-changed=${this._onYamlChange}
|
||||
></ha-yaml-editor>
|
||||
`
|
||||
: html`
|
||||
<paper-dropdown-menu-light
|
||||
@ -123,6 +129,10 @@ export default class HaAutomationConditionEditor extends LitElement {
|
||||
}
|
||||
fireEvent(this, "value-changed", { value: ev.detail.value });
|
||||
}
|
||||
|
||||
static get styles(): CSSResult {
|
||||
return haStyle;
|
||||
}
|
||||
}
|
||||
|
||||
declare global {
|
||||
|
@ -18,7 +18,7 @@ import { Condition } from "../../../../data/automation";
|
||||
import { showConfirmationDialog } from "../../../../dialogs/generic/show-dialog-box";
|
||||
import { HomeAssistant } from "../../../../types";
|
||||
import "./ha-automation-condition-editor";
|
||||
import type { RequestSelectedDetail } from "@material/mwc-list/mwc-list-item";
|
||||
import { ActionDetail } from "@material/mwc-list/mwc-list-foundation";
|
||||
|
||||
export interface ConditionElement extends LitElement {
|
||||
condition: Condition;
|
||||
@ -65,14 +65,14 @@ export default class HaAutomationConditionRow extends LitElement {
|
||||
<ha-card>
|
||||
<div class="card-content">
|
||||
<div class="card-menu">
|
||||
<ha-button-menu corner="BOTTOM_START">
|
||||
<ha-button-menu corner="BOTTOM_START" @action=${this._handleAction}>
|
||||
<mwc-icon-button
|
||||
.title=${this.hass.localize("ui.common.menu")}
|
||||
.label=${this.hass.localize("ui.common.overflow_menu")}
|
||||
slot="trigger"
|
||||
><ha-svg-icon path=${mdiDotsVertical}></ha-svg-icon
|
||||
></mwc-icon-button>
|
||||
<mwc-list-item @request-selected=${this._switchYamlMode}>
|
||||
<mwc-list-item>
|
||||
${this._yamlMode
|
||||
? this.hass.localize(
|
||||
"ui.panel.config.automation.editor.edit_ui"
|
||||
@ -86,7 +86,7 @@ export default class HaAutomationConditionRow extends LitElement {
|
||||
"ui.panel.config.automation.editor.actions.duplicate"
|
||||
)}
|
||||
</mwc-list-item>
|
||||
<mwc-list-item @request-selected=${this._onDelete}>
|
||||
<mwc-list-item>
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.automation.editor.actions.delete"
|
||||
)}
|
||||
@ -103,6 +103,19 @@ export default class HaAutomationConditionRow extends LitElement {
|
||||
`;
|
||||
}
|
||||
|
||||
private _handleAction(ev: CustomEvent<ActionDetail>) {
|
||||
switch (ev.detail.index) {
|
||||
case 0:
|
||||
this._switchYamlMode();
|
||||
break;
|
||||
case 1:
|
||||
break;
|
||||
case 2:
|
||||
this._onDelete();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private _onDelete() {
|
||||
showConfirmationDialog(this, {
|
||||
text: this.hass.localize(
|
||||
@ -116,28 +129,19 @@ export default class HaAutomationConditionRow extends LitElement {
|
||||
});
|
||||
}
|
||||
|
||||
private _switchYamlMode(ev: CustomEvent<RequestSelectedDetail>) {
|
||||
if (ev.detail.source !== "interaction") {
|
||||
return;
|
||||
}
|
||||
private _switchYamlMode() {
|
||||
this._yamlMode = !this._yamlMode;
|
||||
}
|
||||
|
||||
static get styles(): CSSResult {
|
||||
return css`
|
||||
.card-menu {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
float: right;
|
||||
z-index: 3;
|
||||
--mdc-theme-text-primary-on-background: var(--primary-text-color);
|
||||
}
|
||||
.rtl .card-menu {
|
||||
right: auto;
|
||||
left: 0;
|
||||
}
|
||||
ha-button-menu {
|
||||
margin: 8px;
|
||||
float: left;
|
||||
}
|
||||
mwc-list-item[disabled] {
|
||||
--mdc-theme-text-primary-on-background: var(--disabled-text-color);
|
||||
|
@ -34,7 +34,8 @@ import "./types/ha-automation-trigger-time";
|
||||
import "./types/ha-automation-trigger-time_pattern";
|
||||
import "./types/ha-automation-trigger-webhook";
|
||||
import "./types/ha-automation-trigger-zone";
|
||||
import type { RequestSelectedDetail } from "@material/mwc-list/mwc-list-item";
|
||||
import { ActionDetail } from "@material/mwc-list/mwc-list-foundation";
|
||||
import { haStyle } from "../../../../resources/styles";
|
||||
|
||||
const OPTIONS = [
|
||||
"device",
|
||||
@ -94,17 +95,14 @@ export default class HaAutomationTriggerRow extends LitElement {
|
||||
<ha-card>
|
||||
<div class="card-content">
|
||||
<div class="card-menu">
|
||||
<ha-button-menu corner="BOTTOM_START">
|
||||
<ha-button-menu corner="BOTTOM_START" @action=${this._handleAction}>
|
||||
<mwc-icon-button
|
||||
slot="trigger"
|
||||
.title=${this.hass.localize("ui.common.menu")}
|
||||
.label=${this.hass.localize("ui.common.overflow_menu")}
|
||||
><ha-svg-icon path=${mdiDotsVertical}></ha-svg-icon
|
||||
></mwc-icon-button>
|
||||
<mwc-list-item
|
||||
@request-selected=${this._switchYamlMode}
|
||||
.disabled=${selected === -1}
|
||||
>
|
||||
<mwc-list-item .disabled=${selected === -1}>
|
||||
${yamlMode
|
||||
? this.hass.localize(
|
||||
"ui.panel.config.automation.editor.edit_ui"
|
||||
@ -118,7 +116,7 @@ export default class HaAutomationTriggerRow extends LitElement {
|
||||
"ui.panel.config.automation.editor.actions.duplicate"
|
||||
)}
|
||||
</mwc-list-item>
|
||||
<mwc-list-item @request-selected=${this._onDelete}>
|
||||
<mwc-list-item>
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.automation.editor.actions.delete"
|
||||
)}
|
||||
@ -127,21 +125,20 @@ export default class HaAutomationTriggerRow extends LitElement {
|
||||
</div>
|
||||
${yamlMode
|
||||
? html`
|
||||
<div style="margin-right: 24px;">
|
||||
${selected === -1
|
||||
? html`
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.automation.editor.triggers.unsupported_platform",
|
||||
"platform",
|
||||
this.trigger.platform
|
||||
)}
|
||||
`
|
||||
: ""}
|
||||
<ha-yaml-editor
|
||||
.defaultValue=${this.trigger}
|
||||
@value-changed=${this._onYamlChange}
|
||||
></ha-yaml-editor>
|
||||
</div>
|
||||
${selected === -1
|
||||
? html`
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.automation.editor.triggers.unsupported_platform",
|
||||
"platform",
|
||||
this.trigger.platform
|
||||
)}
|
||||
`
|
||||
: ""}
|
||||
<h2>Edit in YAML</h2>
|
||||
<ha-yaml-editor
|
||||
.defaultValue=${this.trigger}
|
||||
@value-changed=${this._onYamlChange}
|
||||
></ha-yaml-editor>
|
||||
`
|
||||
: html`
|
||||
<paper-dropdown-menu-light
|
||||
@ -178,6 +175,19 @@ export default class HaAutomationTriggerRow extends LitElement {
|
||||
`;
|
||||
}
|
||||
|
||||
private _handleAction(ev: CustomEvent<ActionDetail>) {
|
||||
switch (ev.detail.index) {
|
||||
case 0:
|
||||
this._switchYamlMode();
|
||||
break;
|
||||
case 1:
|
||||
break;
|
||||
case 2:
|
||||
this._onDelete();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private _onDelete() {
|
||||
showConfirmationDialog(this, {
|
||||
text: this.hass.localize(
|
||||
@ -219,33 +229,27 @@ export default class HaAutomationTriggerRow extends LitElement {
|
||||
fireEvent(this, "value-changed", { value: ev.detail.value });
|
||||
}
|
||||
|
||||
private _switchYamlMode(ev: CustomEvent<RequestSelectedDetail>) {
|
||||
if (ev.detail.source !== "interaction") {
|
||||
return;
|
||||
}
|
||||
private _switchYamlMode() {
|
||||
this._yamlMode = !this._yamlMode;
|
||||
}
|
||||
|
||||
static get styles(): CSSResult {
|
||||
return css`
|
||||
.card-menu {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
z-index: 3;
|
||||
--mdc-theme-text-primary-on-background: var(--primary-text-color);
|
||||
}
|
||||
.rtl .card-menu {
|
||||
right: auto;
|
||||
left: 0;
|
||||
}
|
||||
ha-button-menu {
|
||||
margin: 8px;
|
||||
}
|
||||
mwc-list-item[disabled] {
|
||||
--mdc-theme-text-primary-on-background: var(--disabled-text-color);
|
||||
}
|
||||
`;
|
||||
static get styles(): CSSResult[] {
|
||||
return [
|
||||
haStyle,
|
||||
css`
|
||||
.card-menu {
|
||||
float: right;
|
||||
z-index: 3;
|
||||
--mdc-theme-text-primary-on-background: var(--primary-text-color);
|
||||
}
|
||||
.rtl .card-menu {
|
||||
float: left;
|
||||
}
|
||||
mwc-list-item[disabled] {
|
||||
--mdc-theme-text-primary-on-background: var(--disabled-text-color);
|
||||
}
|
||||
`,
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -57,6 +57,7 @@ import {
|
||||
showEntityEditorDialog,
|
||||
} from "./show-dialog-entity-editor";
|
||||
import { mdiFilterVariant } from "@mdi/js";
|
||||
import type { RequestSelectedDetail } from "@material/mwc-list/mwc-list-item";
|
||||
|
||||
export interface StateEntity extends EntityRegistryEntry {
|
||||
readonly?: boolean;
|
||||
@ -449,7 +450,7 @@ export class HaConfigEntities extends SubscribeMixin(LitElement) {
|
||||
>
|
||||
</div>`
|
||||
: ""}
|
||||
<ha-button-menu corner="BOTTOM_START">
|
||||
<ha-button-menu corner="BOTTOM_START" multi>
|
||||
<mwc-icon-button
|
||||
slot="trigger"
|
||||
.label=${this.hass!.localize(
|
||||
@ -464,6 +465,7 @@ export class HaConfigEntities extends SubscribeMixin(LitElement) {
|
||||
<mwc-list-item
|
||||
@request-selected="${this._showDisabledChanged}"
|
||||
graphic="control"
|
||||
.selected=${this._showDisabled}
|
||||
>
|
||||
<ha-checkbox
|
||||
slot="graphic"
|
||||
@ -476,6 +478,7 @@ export class HaConfigEntities extends SubscribeMixin(LitElement) {
|
||||
<mwc-list-item
|
||||
@request-selected="${this._showRestoredChanged}"
|
||||
graphic="control"
|
||||
.selected=${this._showUnavailable}
|
||||
>
|
||||
<ha-checkbox
|
||||
slot="graphic"
|
||||
@ -488,6 +491,7 @@ export class HaConfigEntities extends SubscribeMixin(LitElement) {
|
||||
<mwc-list-item
|
||||
@request-selected="${this._showReadOnlyChanged}"
|
||||
graphic="control"
|
||||
.selected=${this._showReadOnly}
|
||||
>
|
||||
<ha-checkbox
|
||||
slot="graphic"
|
||||
@ -579,16 +583,25 @@ export class HaConfigEntities extends SubscribeMixin(LitElement) {
|
||||
}
|
||||
}
|
||||
|
||||
private _showDisabledChanged() {
|
||||
this._showDisabled = !this._showDisabled;
|
||||
private _showDisabledChanged(ev: CustomEvent<RequestSelectedDetail>) {
|
||||
if (ev.detail.source !== "property") {
|
||||
return;
|
||||
}
|
||||
this._showDisabled = ev.detail.selected;
|
||||
}
|
||||
|
||||
private _showRestoredChanged() {
|
||||
this._showUnavailable = !this._showUnavailable;
|
||||
private _showRestoredChanged(ev: CustomEvent<RequestSelectedDetail>) {
|
||||
if (ev.detail.source !== "property") {
|
||||
return;
|
||||
}
|
||||
this._showUnavailable = ev.detail.selected;
|
||||
}
|
||||
|
||||
private _showReadOnlyChanged() {
|
||||
this._showReadOnly = !this._showReadOnly;
|
||||
private _showReadOnlyChanged(ev: CustomEvent<RequestSelectedDetail>) {
|
||||
if (ev.detail.source !== "property") {
|
||||
return;
|
||||
}
|
||||
this._showReadOnly = ev.detail.selected;
|
||||
}
|
||||
|
||||
private _handleSearchChange(ev: CustomEvent) {
|
||||
|
@ -276,7 +276,11 @@ class HaConfigIntegrations extends SubscribeMixin(LitElement) {
|
||||
</div>
|
||||
`
|
||||
: ""}
|
||||
<ha-button-menu corner="BOTTOM_START" slot="toolbar-icon">
|
||||
<ha-button-menu
|
||||
corner="BOTTOM_START"
|
||||
slot="toolbar-icon"
|
||||
@action=${this._toggleShowIgnored}
|
||||
>
|
||||
<mwc-icon-button
|
||||
.title=${this.hass.localize("ui.common.menu")}
|
||||
.label=${this.hass.localize("ui.common.overflow_menu")}
|
||||
@ -284,7 +288,7 @@ class HaConfigIntegrations extends SubscribeMixin(LitElement) {
|
||||
>
|
||||
<ha-svg-icon path=${mdiDotsVertical}></ha-svg-icon>
|
||||
</mwc-icon-button>
|
||||
<mwc-list-item @request-selected=${this._toggleShowIgnored}>
|
||||
<mwc-list-item>
|
||||
${this.hass.localize(
|
||||
this._showIgnored
|
||||
? "ui.panel.config.integrations.ignore.hide_ignored"
|
||||
|
@ -28,6 +28,7 @@ import { haStyle } from "../../../resources/styles";
|
||||
import "../../../components/ha-icon-next";
|
||||
import { fireEvent } from "../../../common/dom/fire_event";
|
||||
import { mdiDotsVertical, mdiOpenInNew } from "@mdi/js";
|
||||
import { ActionDetail } from "@material/mwc-list/mwc-list-foundation";
|
||||
|
||||
export interface ConfigEntryUpdatedEvent {
|
||||
entry: ConfigEntry;
|
||||
@ -223,7 +224,7 @@ export class HaIntegrationCard extends LitElement {
|
||||
`
|
||||
: ""}
|
||||
</div>
|
||||
<ha-button-menu corner="BOTTOM_START">
|
||||
<ha-button-menu corner="BOTTOM_START" @action=${this._handleAction}>
|
||||
<mwc-icon-button
|
||||
.title=${this.hass.localize("ui.common.menu")}
|
||||
.label=${this.hass.localize("ui.common.overflow_menu")}
|
||||
@ -231,7 +232,7 @@ export class HaIntegrationCard extends LitElement {
|
||||
>
|
||||
<ha-svg-icon path=${mdiDotsVertical}></ha-svg-icon>
|
||||
</mwc-icon-button>
|
||||
<mwc-list-item @request-selected=${this._showSystemOptions}>
|
||||
<mwc-list-item>
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.integrations.config_entry.system_options"
|
||||
)}
|
||||
@ -240,7 +241,6 @@ export class HaIntegrationCard extends LitElement {
|
||||
? ""
|
||||
: html`
|
||||
<a
|
||||
class="documentation"
|
||||
href=${this.manifest.documentation}
|
||||
rel="noreferrer"
|
||||
target="_blank"
|
||||
@ -255,10 +255,7 @@ export class HaIntegrationCard extends LitElement {
|
||||
</mwc-list-item>
|
||||
</a>
|
||||
`}
|
||||
<mwc-list-item
|
||||
class="warning"
|
||||
@request-selected=${this._removeIntegration}
|
||||
>
|
||||
<mwc-list-item class="warning">
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.integrations.config_entry.delete"
|
||||
)}
|
||||
@ -308,32 +305,27 @@ export class HaIntegrationCard extends LitElement {
|
||||
showOptionsFlowDialog(this, ev.target.closest("ha-card").configEntry);
|
||||
}
|
||||
|
||||
private _showSystemOptions(ev) {
|
||||
showConfigEntrySystemOptionsDialog(this, {
|
||||
entry: ev.target.closest("ha-card").configEntry,
|
||||
});
|
||||
}
|
||||
|
||||
private async _editEntryName(ev) {
|
||||
const configEntry = ev.target.closest("ha-card").configEntry;
|
||||
const newName = await showPromptDialog(this, {
|
||||
title: this.hass.localize("ui.panel.config.integrations.rename_dialog"),
|
||||
defaultValue: configEntry.title,
|
||||
inputLabel: this.hass.localize(
|
||||
"ui.panel.config.integrations.rename_input_label"
|
||||
),
|
||||
});
|
||||
if (newName === null) {
|
||||
return;
|
||||
private _handleAction(ev: CustomEvent<ActionDetail>) {
|
||||
const configEntry = ((ev.target as HTMLElement).closest("ha-card") as any)
|
||||
.configEntry;
|
||||
switch (ev.detail.index) {
|
||||
case 0:
|
||||
this._showSystemOptions(configEntry);
|
||||
break;
|
||||
case 1:
|
||||
this._removeIntegration(configEntry);
|
||||
break;
|
||||
}
|
||||
const newEntry = await updateConfigEntry(this.hass, configEntry.entry_id, {
|
||||
title: newName,
|
||||
});
|
||||
fireEvent(this, "entry-updated", { entry: newEntry });
|
||||
}
|
||||
|
||||
private async _removeIntegration(ev) {
|
||||
const entryId = ev.target.closest("ha-card").configEntry.entry_id;
|
||||
private _showSystemOptions(configEntry: ConfigEntry) {
|
||||
showConfigEntrySystemOptionsDialog(this, {
|
||||
entry: configEntry,
|
||||
});
|
||||
}
|
||||
|
||||
private async _removeIntegration(configEntry: ConfigEntry) {
|
||||
const entryId = configEntry.entry_id;
|
||||
|
||||
const confirmed = await showConfirmationDialog(this, {
|
||||
text: this.hass.localize(
|
||||
@ -357,6 +349,24 @@ export class HaIntegrationCard extends LitElement {
|
||||
});
|
||||
}
|
||||
|
||||
private async _editEntryName(ev) {
|
||||
const configEntry = ev.target.closest("ha-card").configEntry;
|
||||
const newName = await showPromptDialog(this, {
|
||||
title: this.hass.localize("ui.panel.config.integrations.rename_dialog"),
|
||||
defaultValue: configEntry.title,
|
||||
inputLabel: this.hass.localize(
|
||||
"ui.panel.config.integrations.rename_input_label"
|
||||
),
|
||||
});
|
||||
if (newName === null) {
|
||||
return;
|
||||
}
|
||||
const newEntry = await updateConfigEntry(this.hass, configEntry.entry_id, {
|
||||
title: newName,
|
||||
});
|
||||
fireEvent(this, "entry-updated", { entry: newEntry });
|
||||
}
|
||||
|
||||
static get styles(): CSSResult[] {
|
||||
return [
|
||||
haStyle,
|
||||
@ -389,9 +399,6 @@ export class HaIntegrationCard extends LitElement {
|
||||
align-items: center;
|
||||
padding-right: 5px;
|
||||
}
|
||||
.card-actions .documentation {
|
||||
color: var(--primary-text-color);
|
||||
}
|
||||
.group-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
@ -20,6 +20,7 @@ import { confDeleteCard } from "../editor/delete-card";
|
||||
import { Lovelace, LovelaceCard } from "../types";
|
||||
import { computeCardSize } from "../common/compute-card-size";
|
||||
import { mdiDotsVertical, mdiArrowDown, mdiArrowUp } from "@mdi/js";
|
||||
import { ActionDetail } from "@material/mwc-list/mwc-list-foundation";
|
||||
|
||||
@customElement("hui-card-options")
|
||||
export class HuiCardOptions extends LitElement {
|
||||
@ -65,7 +66,7 @@ export class HuiCardOptions extends LitElement {
|
||||
?disabled=${this.path![1] === 0}
|
||||
><ha-svg-icon path=${mdiArrowUp}></ha-svg-icon
|
||||
></mwc-icon-button>
|
||||
<ha-button-menu corner="BOTTOM_START">
|
||||
<ha-button-menu corner="BOTTOM_START" @action=${this._handleAction}>
|
||||
<mwc-icon-button
|
||||
slot="trigger"
|
||||
aria-label=${this.hass!.localize(
|
||||
@ -78,20 +79,17 @@ export class HuiCardOptions extends LitElement {
|
||||
<ha-svg-icon path=${mdiDotsVertical}></ha-svg-icon>
|
||||
</mwc-icon-button>
|
||||
|
||||
<mwc-list-item @request-selected=${this._moveCard}>
|
||||
<mwc-list-item>
|
||||
${this.hass!.localize(
|
||||
"ui.panel.lovelace.editor.edit_card.move"
|
||||
)}</mwc-list-item
|
||||
>
|
||||
<mwc-list-item @request-selected=${this._duplicateCard}
|
||||
<mwc-list-item
|
||||
>${this.hass!.localize(
|
||||
"ui.panel.lovelace.editor.edit_card.duplicate"
|
||||
)}</mwc-list-item
|
||||
>
|
||||
<mwc-list-item
|
||||
class="delete-item"
|
||||
@request-selected=${this._deleteCard}
|
||||
>
|
||||
<mwc-list-item class="delete-item">
|
||||
${this.hass!.localize(
|
||||
"ui.panel.lovelace.editor.edit_card.delete"
|
||||
)}</mwc-list-item
|
||||
@ -150,6 +148,20 @@ export class HuiCardOptions extends LitElement {
|
||||
`;
|
||||
}
|
||||
|
||||
private _handleAction(ev: CustomEvent<ActionDetail>) {
|
||||
switch (ev.detail.index) {
|
||||
case 0:
|
||||
this._moveCard();
|
||||
break;
|
||||
case 1:
|
||||
this._duplicateCard();
|
||||
break;
|
||||
case 2:
|
||||
this._deleteCard();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private _duplicateCard(): void {
|
||||
const path = this.path!;
|
||||
const cardConfig = this.lovelace!.config.views[path[0]].cards![path[1]];
|
||||
|
@ -58,6 +58,8 @@ import type { Lovelace } from "./types";
|
||||
import "./views/hui-panel-view";
|
||||
import type { HUIPanelView } from "./views/hui-panel-view";
|
||||
import { HUIView } from "./views/hui-view";
|
||||
import type { RequestSelectedDetail } from "@material/mwc-list/mwc-list-item";
|
||||
import { shouldHandleRequestSelectedEvent } from "../../common/mwc/handle-request-selected-event";
|
||||
|
||||
class HUIRoot extends LitElement {
|
||||
@property({ attribute: false }) public hass!: HomeAssistant;
|
||||
@ -133,14 +135,19 @@ class HUIRoot extends LitElement {
|
||||
<ha-svg-icon path=${mdiPencil}></ha-svg-icon>
|
||||
</mwc-icon-button>
|
||||
</div>
|
||||
<mwc-icon-button
|
||||
title="${this.hass!.localize(
|
||||
"ui.panel.lovelace.menu.help"
|
||||
)}"
|
||||
@click="${this._handleHelp}"
|
||||
<a
|
||||
href="https://www.home-assistant.io/lovelace/"
|
||||
rel="noreferrer"
|
||||
target="_blank"
|
||||
>
|
||||
<ha-svg-icon path=${mdiHelpCircle}></ha-svg-icon>
|
||||
</mwc-icon-button>
|
||||
<mwc-icon-button
|
||||
title="${this.hass!.localize(
|
||||
"ui.panel.lovelace.menu.help"
|
||||
)}"
|
||||
>
|
||||
<ha-svg-icon path=${mdiHelpCircle}></ha-svg-icon>
|
||||
</mwc-icon-button>
|
||||
</a>
|
||||
<ha-button-menu corner="BOTTOM_START">
|
||||
<mwc-icon-button
|
||||
slot="trigger"
|
||||
@ -167,9 +174,7 @@ class HUIRoot extends LitElement {
|
||||
)}
|
||||
</mwc-list-item>
|
||||
`}
|
||||
<mwc-list-item
|
||||
@request-selected="${this.lovelace!.enableFullEditMode}"
|
||||
>
|
||||
<mwc-list-item @request-selected="${this._handleRawEditor}">
|
||||
${this.hass!.localize(
|
||||
"ui.panel.lovelace.editor.menu.raw_editor"
|
||||
)}
|
||||
@ -251,7 +256,7 @@ class HUIRoot extends LitElement {
|
||||
aria-label=${this.hass!.localize(
|
||||
"ui.panel.lovelace.menu.configure_ui"
|
||||
)}
|
||||
@request-selected=${this._editModeEnable}
|
||||
@request-selected=${this._handleEnableEditMode}
|
||||
>
|
||||
${this.hass!.localize(
|
||||
"ui.panel.lovelace.menu.configure_ui"
|
||||
@ -259,14 +264,19 @@ class HUIRoot extends LitElement {
|
||||
</mwc-list-item>
|
||||
`
|
||||
: ""}
|
||||
<mwc-list-item
|
||||
aria-label=${this.hass!.localize(
|
||||
"ui.panel.lovelace.menu.help"
|
||||
)}
|
||||
@request-selected=${this._handleHelp}
|
||||
<a
|
||||
href="https://www.home-assistant.io/lovelace/"
|
||||
rel="noreferrer"
|
||||
target="_blank"
|
||||
>
|
||||
${this.hass!.localize("ui.panel.lovelace.menu.help")}
|
||||
</mwc-list-item>
|
||||
<mwc-list-item
|
||||
aria-label=${this.hass!.localize(
|
||||
"ui.panel.lovelace.menu.help"
|
||||
)}
|
||||
>
|
||||
${this.hass!.localize("ui.panel.lovelace.menu.help")}
|
||||
</mwc-list-item>
|
||||
</a>
|
||||
</ha-button-menu>
|
||||
</app-toolbar>
|
||||
`}
|
||||
@ -476,11 +486,17 @@ class HUIRoot extends LitElement {
|
||||
return this.shadowRoot!.getElementById("view") as HTMLDivElement;
|
||||
}
|
||||
|
||||
private _handleRefresh(): void {
|
||||
private _handleRefresh(ev: CustomEvent<RequestSelectedDetail>): void {
|
||||
if (!shouldHandleRequestSelectedEvent(ev)) {
|
||||
return;
|
||||
}
|
||||
fireEvent(this, "config-refresh");
|
||||
}
|
||||
|
||||
private _handleReloadResources(): void {
|
||||
private _handleReloadResources(ev: CustomEvent<RequestSelectedDetail>): void {
|
||||
if (!shouldHandleRequestSelectedEvent(ev)) {
|
||||
return;
|
||||
}
|
||||
this.hass.callService("lovelace", "reload_resources");
|
||||
showConfirmationDialog(this, {
|
||||
title: this.hass!.localize(
|
||||
@ -493,7 +509,17 @@ class HUIRoot extends LitElement {
|
||||
});
|
||||
}
|
||||
|
||||
private _handleUnusedEntities(): void {
|
||||
private _handleRawEditor(ev: CustomEvent<RequestSelectedDetail>): void {
|
||||
if (!shouldHandleRequestSelectedEvent(ev)) {
|
||||
return;
|
||||
}
|
||||
this.lovelace!.enableFullEditMode();
|
||||
}
|
||||
|
||||
private _handleUnusedEntities(ev: CustomEvent<RequestSelectedDetail>): void {
|
||||
if (!shouldHandleRequestSelectedEvent(ev)) {
|
||||
return;
|
||||
}
|
||||
navigate(this, `${this.route?.prefix}/hass-unused-entities`);
|
||||
}
|
||||
|
||||
@ -501,17 +527,20 @@ class HUIRoot extends LitElement {
|
||||
showVoiceCommandDialog(this);
|
||||
}
|
||||
|
||||
private _handleHelp(): void {
|
||||
window.open("https://www.home-assistant.io/lovelace/", "_blank");
|
||||
}
|
||||
|
||||
private _editModeEnable(): void {
|
||||
private _handleEnableEditMode(ev: CustomEvent<RequestSelectedDetail>): void {
|
||||
if (!shouldHandleRequestSelectedEvent(ev)) {
|
||||
return;
|
||||
}
|
||||
if (this._yamlMode) {
|
||||
showAlertDialog(this, {
|
||||
text: "The edit UI is not available when in YAML mode.",
|
||||
});
|
||||
return;
|
||||
}
|
||||
this._enableEditMode();
|
||||
}
|
||||
|
||||
private _enableEditMode(): void {
|
||||
this.lovelace!.setEditMode(true);
|
||||
}
|
||||
|
||||
@ -616,7 +645,7 @@ class HUIRoot extends LitElement {
|
||||
const viewConfig = this.config.views[viewIndex];
|
||||
|
||||
if (!viewConfig) {
|
||||
this._editModeEnable();
|
||||
this._enableEditMode();
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -83,14 +83,14 @@ class HaPanelShoppingList extends LocalizeMixin(PolymerElement) {
|
||||
icon="hass:microphone"
|
||||
on-click="_showVoiceCommandDialog"
|
||||
></ha-icon-button>
|
||||
<ha-button-menu corner="BOTTOM_START">
|
||||
<ha-button-menu corner="BOTTOM_START" on-action="_clearCompleted">
|
||||
<ha-icon-button
|
||||
icon="hass:dots-vertical"
|
||||
label="Menu"
|
||||
slot="trigger"
|
||||
>
|
||||
</ha-icon-button>
|
||||
<mwc-list-item on-request-selected="_clearCompleted">
|
||||
<mwc-list-item>
|
||||
[[localize('ui.panel.shopping-list.clear_completed')]]
|
||||
</mwc-list-item>
|
||||
</ha-button-menu>
|
||||
|
Loading…
x
Reference in New Issue
Block a user