mirror of
https://github.com/home-assistant/frontend.git
synced 2026-08-06 06:26:25 +00:00
Compare commits
21 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 68bdb6d229 | |||
| 3d540709aa | |||
| 69a0bc214c | |||
| 9ca04290bf | |||
| 5b55b408e6 | |||
| d5c64b78d9 | |||
| 60b09dd57d | |||
| abfec31cfe | |||
| 90e3112ae1 | |||
| 380509cf57 | |||
| 88139f64ab | |||
| f90e04274b | |||
| 886d14bcf6 | |||
| 64c831e91f | |||
| 8e53019cf2 | |||
| daab076bc1 | |||
| 37a970f195 | |||
| c5ffb4cb4e | |||
| 8c28fa747d | |||
| 322d01196f | |||
| 9ec77c88b1 |
@@ -1,12 +0,0 @@
|
||||
diff --git a/mwc-icon-button-base.js b/mwc-icon-button-base.js
|
||||
index 45cdaab93ccc0a6daaaaabc01266dcdc32e46bfd..b3ea5b541597308d85f86ce6c23fd00785fda835 100644
|
||||
--- a/mwc-icon-button-base.js
|
||||
+++ b/mwc-icon-button-base.js
|
||||
@@ -63,7 +63,6 @@ export class IconButtonBase extends LitElement {
|
||||
@touchend="${this.handleRippleDeactivate}"
|
||||
@touchcancel="${this.handleRippleDeactivate}"
|
||||
>${this.renderRipple()}
|
||||
- <i class="material-icons">${this.icon}</i>
|
||||
<span
|
||||
><slot></slot
|
||||
></span>
|
||||
@@ -1,55 +1,177 @@
|
||||
import { mdiHomeAssistant } from "@mdi/js";
|
||||
import "../../../src/components/ha-switch";
|
||||
import "../../../src/components/ha-formfield";
|
||||
import { mdiClose, mdiHomeAssistant } from "@mdi/js";
|
||||
import { css, html, LitElement, TemplateResult } from "lit";
|
||||
import { customElement } from "lit/decorators";
|
||||
import { customElement, state } from "lit/decorators";
|
||||
import "../../../src/components/ha-card";
|
||||
import "../../../src/components/ha-chip";
|
||||
import "../../../src/components/ha-chip-set";
|
||||
import type { HaChipSetItem } from "../../../src/components/ha-chip-set";
|
||||
import "../../../src/components/ha-svg-icon";
|
||||
|
||||
const chips: {
|
||||
icon?: string;
|
||||
content?: string;
|
||||
}[] = [
|
||||
const chips: HaChipSetItem[] = [
|
||||
{
|
||||
leadingIcon: mdiHomeAssistant,
|
||||
},
|
||||
{
|
||||
label: "Demo chip",
|
||||
},
|
||||
{
|
||||
leadingIcon: mdiHomeAssistant,
|
||||
label: "Demo chip",
|
||||
},
|
||||
{
|
||||
leadingIcon: mdiHomeAssistant,
|
||||
label: "Demo chip",
|
||||
active: true,
|
||||
},
|
||||
{},
|
||||
{
|
||||
icon: mdiHomeAssistant,
|
||||
trailingIcon: mdiClose,
|
||||
label: "Demo chip",
|
||||
},
|
||||
{
|
||||
content: "Content",
|
||||
label: "Automation",
|
||||
},
|
||||
{
|
||||
icon: mdiHomeAssistant,
|
||||
content: "Content",
|
||||
label: "Blueprint",
|
||||
},
|
||||
{
|
||||
label: "Script",
|
||||
},
|
||||
{
|
||||
label: "Scene",
|
||||
},
|
||||
{
|
||||
label: "Person",
|
||||
},
|
||||
];
|
||||
|
||||
@customElement("demo-ha-chip")
|
||||
export class DemoHaChip extends LitElement {
|
||||
@state() standaloneIsDisabled = false;
|
||||
|
||||
@state() standaloneIsOutlined = false;
|
||||
|
||||
@state() standaloneIsActive = false;
|
||||
|
||||
protected render(): TemplateResult {
|
||||
return html`
|
||||
<ha-card header="ha-chip demo">
|
||||
<div class="filters">
|
||||
<ha-formfield label="Disable standalone chips">
|
||||
<ha-switch @change=${this._toggleDisable}></ha-switch>
|
||||
</ha-formfield>
|
||||
<ha-formfield label="Outline standalone chips">
|
||||
<ha-switch @change=${this._toggleOutline}></ha-switch>
|
||||
</ha-formfield>
|
||||
<ha-formfield label="Activate standalone chips">
|
||||
<ha-switch @change=${this._toggleActive}></ha-switch>
|
||||
</ha-formfield>
|
||||
</div>
|
||||
<ha-card header="Standalone ha-chip demo">
|
||||
<div class="card-content">
|
||||
${chips.map(
|
||||
(chip) => html`
|
||||
<ha-chip .hasIcon=${chip.icon !== undefined}>
|
||||
${chip.icon
|
||||
? html`<ha-svg-icon slot="icon" .path=${chip.icon}>
|
||||
</ha-svg-icon>`
|
||||
: ""}
|
||||
${chip.content}
|
||||
</ha-chip>
|
||||
`
|
||||
)}
|
||||
<div class="standalone">
|
||||
<span>Simple:</span>
|
||||
<ha-chip
|
||||
.active=${this.standaloneIsActive}
|
||||
.outlined=${this.standaloneIsOutlined}
|
||||
?disabled=${this.standaloneIsDisabled}
|
||||
>Demo chip</ha-chip
|
||||
>
|
||||
</div>
|
||||
|
||||
<div class="standalone">
|
||||
<span>Label property:</span>
|
||||
<ha-chip
|
||||
.active=${this.standaloneIsActive}
|
||||
.outlined=${this.standaloneIsOutlined}
|
||||
?disabled=${this.standaloneIsDisabled}
|
||||
label="Demo chip"
|
||||
></ha-chip>
|
||||
</div>
|
||||
|
||||
<div class="standalone">
|
||||
<span>With leadingIcon:</span>
|
||||
<ha-chip
|
||||
.active=${this.standaloneIsActive}
|
||||
.leadingIcon=${mdiHomeAssistant}
|
||||
.outlined=${this.standaloneIsOutlined}
|
||||
?disabled=${this.standaloneIsDisabled}
|
||||
>Demo chip</ha-chip
|
||||
>
|
||||
</div>
|
||||
|
||||
<div class="standalone">
|
||||
<span>With trailingIcon property:</span>
|
||||
<ha-chip
|
||||
.active=${this.standaloneIsActive}
|
||||
.trailingIcon=${mdiHomeAssistant}
|
||||
.outlined=${this.standaloneIsOutlined}
|
||||
?disabled=${this.standaloneIsDisabled}
|
||||
>Demo chip</ha-chip
|
||||
>
|
||||
</div>
|
||||
|
||||
<div class="standalone">
|
||||
<span>With trailing-icon slot:</span>
|
||||
<ha-chip
|
||||
.active=${this.standaloneIsActive}
|
||||
.outlined=${this.standaloneIsOutlined}
|
||||
?disabled=${this.standaloneIsDisabled}
|
||||
>
|
||||
Demo chip
|
||||
<ha-svg-icon
|
||||
slot="trailing-icon"
|
||||
class="trailing"
|
||||
.path=${mdiHomeAssistant}
|
||||
></ha-svg-icon>
|
||||
</ha-chip>
|
||||
</div>
|
||||
</div>
|
||||
</ha-card>
|
||||
|
||||
<ha-card header="ha-chip-set demo">
|
||||
<div class="card-content">
|
||||
<ha-chip-set .items=${chips}> </ha-chip-set>
|
||||
<ha-chip-set
|
||||
.items=${chips.map((chip) => ({ ...chip, outlined: true }))}
|
||||
>
|
||||
</ha-chip-set>
|
||||
</div>
|
||||
</ha-card>
|
||||
`;
|
||||
}
|
||||
|
||||
private _toggleActive() {
|
||||
this.standaloneIsActive = !this.standaloneIsActive;
|
||||
}
|
||||
|
||||
private _toggleDisable() {
|
||||
this.standaloneIsDisabled = !this.standaloneIsDisabled;
|
||||
}
|
||||
|
||||
private _toggleOutline() {
|
||||
this.standaloneIsOutlined = !this.standaloneIsOutlined;
|
||||
}
|
||||
|
||||
static get styles() {
|
||||
return css`
|
||||
ha-card {
|
||||
max-width: 600px;
|
||||
margin: 24px auto;
|
||||
}
|
||||
.standalone {
|
||||
margin: 4px 0;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
.filters {
|
||||
margin: 16px;
|
||||
}
|
||||
ha-formfield {
|
||||
margin: 12px 0;
|
||||
display: block;
|
||||
}
|
||||
`;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -181,6 +181,24 @@ class HaGallery extends PolymerElement {
|
||||
this.$.notifications.showDialog({ message: "Alert action clicked" })
|
||||
);
|
||||
|
||||
this.addEventListener("chip-clicked", (ev) =>
|
||||
this.$.notifications.showDialog({
|
||||
message: `Chip ${ev.detail.index} clicked `,
|
||||
})
|
||||
);
|
||||
|
||||
this.addEventListener("chip-clicked", () =>
|
||||
this.$.notifications.showDialog({
|
||||
message: "Chip clicked",
|
||||
})
|
||||
);
|
||||
|
||||
this.addEventListener("chip-clicked-trailing", () =>
|
||||
this.$.notifications.showDialog({
|
||||
message: "Chip trailing icon clicked",
|
||||
})
|
||||
);
|
||||
|
||||
this.addEventListener("hass-more-info", (ev) => {
|
||||
if (ev.detail.entityId) {
|
||||
this.$.notifications.showDialog({
|
||||
|
||||
@@ -31,7 +31,7 @@ import "../../../../src/components/buttons/ha-call-api-button";
|
||||
import "../../../../src/components/buttons/ha-progress-button";
|
||||
import "../../../../src/components/ha-alert";
|
||||
import "../../../../src/components/ha-card";
|
||||
import "../../../../src/components/ha-chip";
|
||||
import "../../../../src/components/ha-chip-set";
|
||||
import "../../../../src/components/ha-markdown";
|
||||
import "../../../../src/components/ha-settings-row";
|
||||
import "../../../../src/components/ha-svg-icon";
|
||||
@@ -125,6 +125,137 @@ class HassioAddonInfo extends LitElement {
|
||||
)}`,
|
||||
},
|
||||
];
|
||||
const capabilities = [
|
||||
{
|
||||
id: "rating",
|
||||
icon: RATING_ICON[this.addon.rating],
|
||||
class: [6, 5].includes(Number(this.addon.rating))
|
||||
? "green"
|
||||
: [3, 4].includes(Number(this.addon.rating))
|
||||
? "yellow"
|
||||
: "red",
|
||||
label: this.supervisor.localize(
|
||||
"addon.dashboard.capability.label.rating"
|
||||
),
|
||||
},
|
||||
];
|
||||
|
||||
if (this.addon.stage !== "stable") {
|
||||
capabilities.push({
|
||||
id: "rating",
|
||||
icon: STAGE_ICON[this.addon.stage],
|
||||
class:
|
||||
this.addon.stage === "experimental"
|
||||
? "yellow"
|
||||
: this.addon.stage === "deprecated"
|
||||
? "red"
|
||||
: "",
|
||||
label: this.supervisor.localize(
|
||||
`addon.dashboard.capability.stages.${this.addon.stage}`
|
||||
),
|
||||
});
|
||||
}
|
||||
|
||||
if (this.addon.host_network) {
|
||||
capabilities.push({
|
||||
id: "host_network",
|
||||
icon: mdiNetwork,
|
||||
class: "",
|
||||
label: this.supervisor.localize(
|
||||
"addon.dashboard.capability.label.host"
|
||||
),
|
||||
});
|
||||
}
|
||||
|
||||
if (this.addon.full_access) {
|
||||
capabilities.push({
|
||||
id: "full_access",
|
||||
icon: mdiChip,
|
||||
class: "",
|
||||
label: this.supervisor.localize(
|
||||
"addon.dashboard.capability.label.hardware"
|
||||
),
|
||||
});
|
||||
}
|
||||
|
||||
if (this.addon.homeassistant_api) {
|
||||
capabilities.push({
|
||||
id: "homeassistant_api",
|
||||
icon: mdiHomeAssistant,
|
||||
class: "",
|
||||
label: this.supervisor.localize(
|
||||
"addon.dashboard.capability.label.core"
|
||||
),
|
||||
});
|
||||
}
|
||||
|
||||
if (this._computeHassioApi) {
|
||||
capabilities.push({
|
||||
id: "hassio_api",
|
||||
icon: mdiHomeAssistant,
|
||||
class: "",
|
||||
label:
|
||||
this.supervisor.localize(
|
||||
`addon.dashboard.capability.role.${this.addon.hassio_role}`
|
||||
) || this.addon.hassio_role,
|
||||
});
|
||||
}
|
||||
|
||||
if (this.addon.docker_api) {
|
||||
capabilities.push({
|
||||
id: "docker_api",
|
||||
icon: mdiDocker,
|
||||
class: "",
|
||||
label: this.supervisor.localize(
|
||||
"addon.dashboard.capability.label.docker"
|
||||
),
|
||||
});
|
||||
}
|
||||
|
||||
if (this.addon.host_pid) {
|
||||
capabilities.push({
|
||||
id: "host_pid",
|
||||
icon: mdiPound,
|
||||
class: "",
|
||||
label: this.supervisor.localize(
|
||||
"addon.dashboard.capability.label.host_pid"
|
||||
),
|
||||
});
|
||||
}
|
||||
|
||||
if (this.addon.apparmor !== "default") {
|
||||
capabilities.push({
|
||||
id: "apparmor",
|
||||
icon: mdiShield,
|
||||
class: this._computeApparmorClassName,
|
||||
label: this.supervisor.localize(
|
||||
"addon.dashboard.capability.label.apparmor"
|
||||
),
|
||||
});
|
||||
}
|
||||
|
||||
if (this.addon.auth_api) {
|
||||
capabilities.push({
|
||||
id: "auth_api",
|
||||
icon: mdiKey,
|
||||
class: "",
|
||||
label: this.supervisor.localize(
|
||||
"addon.dashboard.capability.label.auth"
|
||||
),
|
||||
});
|
||||
}
|
||||
|
||||
if (this.addon.ingress) {
|
||||
capabilities.push({
|
||||
id: "ingress",
|
||||
icon: mdiCursorDefaultClickOutline,
|
||||
class: "",
|
||||
label: this.supervisor.localize(
|
||||
"addon.dashboard.capability.label.ingress"
|
||||
),
|
||||
});
|
||||
}
|
||||
|
||||
return html`
|
||||
${this.addon.update_available
|
||||
? html`
|
||||
@@ -262,160 +393,18 @@ class HassioAddonInfo extends LitElement {
|
||||
</div>
|
||||
|
||||
<div class="capabilities">
|
||||
${this.addon.stage !== "stable"
|
||||
? html` <ha-chip
|
||||
hasIcon
|
||||
class=${classMap({
|
||||
yellow: this.addon.stage === "experimental",
|
||||
red: this.addon.stage === "deprecated",
|
||||
})}
|
||||
<ha-chip-set>
|
||||
${capabilities.map(
|
||||
(capability) => html`<ha-chip
|
||||
@click=${this._showMoreInfo}
|
||||
id="stage"
|
||||
>
|
||||
<ha-svg-icon
|
||||
slot="icon"
|
||||
.path=${STAGE_ICON[this.addon.stage]}
|
||||
>
|
||||
</ha-svg-icon>
|
||||
${this.supervisor.localize(
|
||||
`addon.dashboard.capability.stages.${this.addon.stage}`
|
||||
)}
|
||||
</ha-chip>`
|
||||
: ""}
|
||||
|
||||
<ha-chip
|
||||
hasIcon
|
||||
class=${classMap({
|
||||
green: [5, 6].includes(Number(this.addon.rating)),
|
||||
yellow: [3, 4].includes(Number(this.addon.rating)),
|
||||
red: [1, 2].includes(Number(this.addon.rating)),
|
||||
})}
|
||||
@click=${this._showMoreInfo}
|
||||
id="rating"
|
||||
>
|
||||
<ha-svg-icon slot="icon" .path=${RATING_ICON[this.addon.rating]}>
|
||||
</ha-svg-icon>
|
||||
|
||||
${this.supervisor.localize(
|
||||
"addon.dashboard.capability.label.rating"
|
||||
.leadingIcon=${capability.icon}
|
||||
.label=${capability.label}
|
||||
.id=${capability.id}
|
||||
class=${capability.class}
|
||||
outlined
|
||||
></ha-chip>`
|
||||
)}
|
||||
</ha-chip>
|
||||
${this.addon.host_network
|
||||
? html`
|
||||
<ha-chip
|
||||
hasIcon
|
||||
@click=${this._showMoreInfo}
|
||||
id="host_network"
|
||||
>
|
||||
<ha-svg-icon slot="icon" .path=${mdiNetwork}> </ha-svg-icon>
|
||||
${this.supervisor.localize(
|
||||
"addon.dashboard.capability.label.host"
|
||||
)}
|
||||
</ha-chip>
|
||||
`
|
||||
: ""}
|
||||
${this.addon.full_access
|
||||
? html`
|
||||
<ha-chip
|
||||
hasIcon
|
||||
@click=${this._showMoreInfo}
|
||||
id="full_access"
|
||||
>
|
||||
<ha-svg-icon slot="icon" .path=${mdiChip}></ha-svg-icon>
|
||||
${this.supervisor.localize(
|
||||
"addon.dashboard.capability.label.hardware"
|
||||
)}
|
||||
</ha-chip>
|
||||
`
|
||||
: ""}
|
||||
${this.addon.homeassistant_api
|
||||
? html`
|
||||
<ha-chip
|
||||
hasIcon
|
||||
@click=${this._showMoreInfo}
|
||||
id="homeassistant_api"
|
||||
>
|
||||
<ha-svg-icon
|
||||
slot="icon"
|
||||
.path=${mdiHomeAssistant}
|
||||
></ha-svg-icon>
|
||||
${this.supervisor.localize(
|
||||
"addon.dashboard.capability.label.core"
|
||||
)}
|
||||
</ha-chip>
|
||||
`
|
||||
: ""}
|
||||
${this._computeHassioApi
|
||||
? html`
|
||||
<ha-chip hasIcon @click=${this._showMoreInfo} id="hassio_api">
|
||||
<ha-svg-icon
|
||||
slot="icon"
|
||||
.path=${mdiHomeAssistant}
|
||||
></ha-svg-icon>
|
||||
${this.supervisor.localize(
|
||||
`addon.dashboard.capability.role.${this.addon.hassio_role}`
|
||||
) || this.addon.hassio_role}
|
||||
</ha-chip>
|
||||
`
|
||||
: ""}
|
||||
${this.addon.docker_api
|
||||
? html`
|
||||
<ha-chip hasIcon @click=${this._showMoreInfo} id="docker_api">
|
||||
<ha-svg-icon slot="icon" .path=${mdiDocker}></ha-svg-icon>
|
||||
${this.supervisor.localize(
|
||||
"addon.dashboard.capability.label.docker"
|
||||
)}
|
||||
</ha-chip>
|
||||
`
|
||||
: ""}
|
||||
${this.addon.host_pid
|
||||
? html`
|
||||
<ha-chip hasIcon @click=${this._showMoreInfo} id="host_pid">
|
||||
<ha-svg-icon slot="icon" .path=${mdiPound}></ha-svg-icon>
|
||||
${this.supervisor.localize(
|
||||
"addon.dashboard.capability.label.host_pid"
|
||||
)}
|
||||
</ha-chip>
|
||||
`
|
||||
: ""}
|
||||
${this.addon.apparmor !== "default"
|
||||
? html`
|
||||
<ha-chip
|
||||
hasIcon
|
||||
@click=${this._showMoreInfo}
|
||||
class=${this._computeApparmorClassName}
|
||||
id="apparmor"
|
||||
>
|
||||
<ha-svg-icon slot="icon" .path=${mdiShield}></ha-svg-icon>
|
||||
${this.supervisor.localize(
|
||||
"addon.dashboard.capability.label.apparmor"
|
||||
)}
|
||||
</ha-chip>
|
||||
`
|
||||
: ""}
|
||||
${this.addon.auth_api
|
||||
? html`
|
||||
<ha-chip hasIcon @click=${this._showMoreInfo} id="auth_api">
|
||||
<ha-svg-icon slot="icon" .path=${mdiKey}></ha-svg-icon>
|
||||
${this.supervisor.localize(
|
||||
"addon.dashboard.capability.label.auth"
|
||||
)}
|
||||
</ha-chip>
|
||||
`
|
||||
: ""}
|
||||
${this.addon.ingress
|
||||
? html`
|
||||
<ha-chip hasIcon @click=${this._showMoreInfo} id="ingress">
|
||||
<ha-svg-icon
|
||||
slot="icon"
|
||||
.path=${mdiCursorDefaultClickOutline}
|
||||
></ha-svg-icon>
|
||||
${this.supervisor.localize(
|
||||
"addon.dashboard.capability.label.ingress"
|
||||
)}
|
||||
</ha-chip>
|
||||
`
|
||||
: ""}
|
||||
</ha-chip-set>
|
||||
</div>
|
||||
|
||||
<div class="description light-color">
|
||||
@@ -1183,8 +1172,6 @@ class HassioAddonInfo extends LitElement {
|
||||
}
|
||||
ha-chip {
|
||||
text-transform: capitalize;
|
||||
--ha-chip-text-color: var(--text-primary-color);
|
||||
--ha-chip-background-color: var(--primary-color);
|
||||
}
|
||||
|
||||
.red {
|
||||
@@ -1200,7 +1187,7 @@ class HassioAddonInfo extends LitElement {
|
||||
--ha-chip-background-color: var(--label-badge-yellow, #f4b400);
|
||||
}
|
||||
.capabilities {
|
||||
margin-bottom: 16px;
|
||||
margin: -16px 0 8px;
|
||||
}
|
||||
.card-actions {
|
||||
justify-content: space-between;
|
||||
|
||||
+42
-42
@@ -22,23 +22,23 @@
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"@braintree/sanitize-url": "^5.0.2",
|
||||
"@codemirror/commands": "^0.19.5",
|
||||
"@codemirror/gutter": "^0.19.3",
|
||||
"@codemirror/highlight": "^0.19.6",
|
||||
"@codemirror/commands": "^0.19.2",
|
||||
"@codemirror/gutter": "^0.19.1",
|
||||
"@codemirror/highlight": "^0.19.2",
|
||||
"@codemirror/history": "^0.19.0",
|
||||
"@codemirror/legacy-modes": "^0.19.0",
|
||||
"@codemirror/rectangular-selection": "^0.19.1",
|
||||
"@codemirror/search": "^0.19.2",
|
||||
"@codemirror/state": "^0.19.2",
|
||||
"@codemirror/stream-parser": "^0.19.2",
|
||||
"@codemirror/text": "^0.19.4",
|
||||
"@codemirror/view": "^0.19.9",
|
||||
"@formatjs/intl-datetimeformat": "^4.2.5",
|
||||
"@formatjs/intl-getcanonicallocales": "^1.8.0",
|
||||
"@formatjs/intl-locale": "^2.4.40",
|
||||
"@formatjs/intl-numberformat": "^7.2.5",
|
||||
"@formatjs/intl-pluralrules": "^4.1.5",
|
||||
"@formatjs/intl-relativetimeformat": "^9.3.2",
|
||||
"@codemirror/rectangular-selection": "^0.19.0",
|
||||
"@codemirror/search": "^0.19.0",
|
||||
"@codemirror/state": "^0.19.1",
|
||||
"@codemirror/stream-parser": "^0.19.1",
|
||||
"@codemirror/text": "^0.19.2",
|
||||
"@codemirror/view": "^0.19.4",
|
||||
"@formatjs/intl-datetimeformat": "^4.2.4",
|
||||
"@formatjs/intl-getcanonicallocales": "^1.7.3",
|
||||
"@formatjs/intl-locale": "^2.4.38",
|
||||
"@formatjs/intl-numberformat": "^7.2.4",
|
||||
"@formatjs/intl-pluralrules": "^4.1.4",
|
||||
"@formatjs/intl-relativetimeformat": "^9.3.1",
|
||||
"@formatjs/intl-utils": "^3.8.4",
|
||||
"@fullcalendar/common": "5.9.0",
|
||||
"@fullcalendar/core": "5.9.0",
|
||||
@@ -46,27 +46,27 @@
|
||||
"@fullcalendar/interaction": "5.9.0",
|
||||
"@fullcalendar/list": "5.9.0",
|
||||
"@lit-labs/virtualizer": "patch:@lit-labs/virtualizer@0.6.0#./.yarn/patches/@lit-labs/virtualizer/0.7.0.patch",
|
||||
"@material/chips": "14.0.0-canary.261f2db59.0",
|
||||
"@material/data-table": "14.0.0-canary.261f2db59.0",
|
||||
"@material/mwc-button": "0.25.3",
|
||||
"@material/mwc-checkbox": "0.25.3",
|
||||
"@material/mwc-circular-progress": "0.25.3",
|
||||
"@material/mwc-dialog": "0.25.3",
|
||||
"@material/mwc-fab": "0.25.3",
|
||||
"@material/mwc-formfield": "0.25.3",
|
||||
"@material/mwc-icon-button": "patch:@material/mwc-icon-button@0.25.3#./.yarn/patches/@material/mwc-icon-button/remove-icon.patch",
|
||||
"@material/mwc-linear-progress": "0.25.3",
|
||||
"@material/mwc-list": "0.25.3",
|
||||
"@material/mwc-menu": "0.25.3",
|
||||
"@material/mwc-radio": "0.25.3",
|
||||
"@material/mwc-ripple": "0.25.3",
|
||||
"@material/mwc-select": "0.25.3",
|
||||
"@material/mwc-slider": "0.25.3",
|
||||
"@material/mwc-switch": "0.25.3",
|
||||
"@material/mwc-tab": "0.25.3",
|
||||
"@material/mwc-tab-bar": "0.25.3",
|
||||
"@material/mwc-textfield": "0.25.3",
|
||||
"@material/top-app-bar": "14.0.0-canary.261f2db59.0",
|
||||
"@material/chips": "14.0.0-canary.353ca7e9f.0",
|
||||
"@material/data-table": "14.0.0-canary.353ca7e9f.0",
|
||||
"@material/mwc-button": "0.25.2",
|
||||
"@material/mwc-checkbox": "0.25.2",
|
||||
"@material/mwc-circular-progress": "0.25.2",
|
||||
"@material/mwc-dialog": "0.25.2",
|
||||
"@material/mwc-fab": "0.25.2",
|
||||
"@material/mwc-formfield": "0.25.2",
|
||||
"@material/mwc-icon-button": "0.25.2",
|
||||
"@material/mwc-linear-progress": "0.25.2",
|
||||
"@material/mwc-list": "0.25.2",
|
||||
"@material/mwc-menu": "0.25.2",
|
||||
"@material/mwc-radio": "0.25.2",
|
||||
"@material/mwc-ripple": "0.25.2",
|
||||
"@material/mwc-select": "0.25.2",
|
||||
"@material/mwc-slider": "0.25.2",
|
||||
"@material/mwc-switch": "0.25.2",
|
||||
"@material/mwc-tab": "0.25.2",
|
||||
"@material/mwc-tab-bar": "0.25.2",
|
||||
"@material/mwc-textfield": "0.25.2",
|
||||
"@material/top-app-bar": "14.0.0-canary.353ca7e9f.0",
|
||||
"@mdi/js": "6.4.95",
|
||||
"@mdi/svg": "6.4.95",
|
||||
"@polymer/app-layout": "^3.1.0",
|
||||
@@ -108,7 +108,7 @@
|
||||
"js-yaml": "^4.1.0",
|
||||
"leaflet": "^1.7.1",
|
||||
"leaflet-draw": "^1.0.4",
|
||||
"lit": "^2.0.2",
|
||||
"lit": "^2.0.0",
|
||||
"lit-vaadin-helpers": "^0.2.1",
|
||||
"marked": "^3.0.2",
|
||||
"memoize-one": "^5.2.1",
|
||||
@@ -180,7 +180,7 @@
|
||||
"eslint-import-resolver-webpack": "^0.13.1",
|
||||
"eslint-plugin-disable": "^2.0.1",
|
||||
"eslint-plugin-import": "^2.24.2",
|
||||
"eslint-plugin-lit": "^1.6.1",
|
||||
"eslint-plugin-lit": "^1.5.1",
|
||||
"eslint-plugin-prettier": "^4.0.0",
|
||||
"eslint-plugin-unused-imports": "^1.1.5",
|
||||
"eslint-plugin-wc": "^1.3.2",
|
||||
@@ -230,10 +230,10 @@
|
||||
"resolutions": {
|
||||
"@polymer/polymer": "patch:@polymer/polymer@3.4.1#./.yarn/patches/@polymer/polymer/pr-5569.patch",
|
||||
"@webcomponents/webcomponentsjs": "^2.2.10",
|
||||
"lit": "^2.0.2",
|
||||
"lit-html": "2.0.1",
|
||||
"lit-element": "3.0.1",
|
||||
"@lit/reactive-element": "1.0.1"
|
||||
"lit": "^2.0.0",
|
||||
"lit-html": "2.0.0",
|
||||
"lit-element": "3.0.0",
|
||||
"@lit/reactive-element": "1.0.0"
|
||||
},
|
||||
"main": "src/home-assistant.js",
|
||||
"husky": {
|
||||
|
||||
@@ -2,7 +2,7 @@ from setuptools import setup, find_packages
|
||||
|
||||
setup(
|
||||
name="home-assistant-frontend",
|
||||
version="20211026.0",
|
||||
version="20211020.0",
|
||||
description="The Home Assistant frontend",
|
||||
url="https://github.com/home-assistant/frontend",
|
||||
author="The Home Assistant Authors",
|
||||
|
||||
@@ -7,10 +7,9 @@ import {
|
||||
PropertyValues,
|
||||
TemplateResult,
|
||||
} from "lit";
|
||||
import "./ha-password-manager-polyfill";
|
||||
import { property, state } from "lit/decorators";
|
||||
import "../components/ha-checkbox";
|
||||
import "../components/ha-form/ha-form";
|
||||
import "../components/ha-formfield";
|
||||
import "../components/ha-markdown";
|
||||
import "../components/ha-alert";
|
||||
import { AuthProvider } from "../data/auth";
|
||||
@@ -20,7 +19,6 @@ import {
|
||||
} from "../data/data_entry_flow";
|
||||
import { litLocalizeLiteMixin } from "../mixins/lit-localize-lite-mixin";
|
||||
import { computeInitialHaFormData } from "../components/ha-form/compute-initial-ha-form-data";
|
||||
import "./ha-password-manager-polyfill";
|
||||
|
||||
type State = "loading" | "error" | "step";
|
||||
|
||||
@@ -43,8 +41,6 @@ class HaAuthFlow extends litLocalizeLiteMixin(LitElement) {
|
||||
|
||||
@state() private _submitting = false;
|
||||
|
||||
@state() private _storeToken = false;
|
||||
|
||||
willUpdate(changedProps: PropertyValues) {
|
||||
super.willUpdate(changedProps);
|
||||
|
||||
@@ -174,9 +170,6 @@ class HaAuthFlow extends litLocalizeLiteMixin(LitElement) {
|
||||
}
|
||||
|
||||
private _renderStep(step: DataEntryFlowStep): TemplateResult {
|
||||
const clientIdOrigin = this.clientId
|
||||
? new URL(this.clientId).origin
|
||||
: undefined;
|
||||
switch (step.type) {
|
||||
case "abort":
|
||||
return html`
|
||||
@@ -208,29 +201,12 @@ class HaAuthFlow extends litLocalizeLiteMixin(LitElement) {
|
||||
.computeError=${this._computeErrorCallback(step)}
|
||||
@value-changed=${this._stepDataChanged}
|
||||
></ha-form>
|
||||
${clientIdOrigin === window.location.origin && step.step_id !== "mfa"
|
||||
? html`
|
||||
<ha-formfield
|
||||
class="store-token"
|
||||
.label=${this.localize("ui.panel.page-authorize.store_token")}
|
||||
>
|
||||
<ha-checkbox
|
||||
.checked=${this._storeToken}
|
||||
@change=${this._storeTokenChanged}
|
||||
></ha-checkbox>
|
||||
</ha-formfield>
|
||||
`
|
||||
: ""}
|
||||
`;
|
||||
default:
|
||||
return html``;
|
||||
}
|
||||
}
|
||||
|
||||
private _storeTokenChanged(e: CustomEvent<HTMLInputElement>) {
|
||||
this._storeToken = (e.currentTarget as HTMLInputElement).checked;
|
||||
}
|
||||
|
||||
private async _providerChanged(newProvider?: AuthProvider) {
|
||||
if (this._step && this._step.type === "form") {
|
||||
fetch(`/auth/login_flow/${this._step.flow_id}`, {
|
||||
@@ -298,9 +274,6 @@ class HaAuthFlow extends litLocalizeLiteMixin(LitElement) {
|
||||
if (this.oauth2State) {
|
||||
url += `&state=${encodeURIComponent(this.oauth2State)}`;
|
||||
}
|
||||
if (this._storeToken) {
|
||||
url += `&storeToken=true`;
|
||||
}
|
||||
|
||||
document.location.assign(url);
|
||||
}
|
||||
@@ -384,11 +357,6 @@ class HaAuthFlow extends litLocalizeLiteMixin(LitElement) {
|
||||
margin: 24px 0 8px;
|
||||
text-align: center;
|
||||
}
|
||||
/* Align with the rest of the form. */
|
||||
.store-token {
|
||||
margin-top: 10px;
|
||||
margin-left: -16px;
|
||||
}
|
||||
`;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,14 +30,6 @@ export function askWrite() {
|
||||
|
||||
export function saveTokens(tokens: AuthData | null) {
|
||||
tokenCache.tokens = tokens;
|
||||
|
||||
if (
|
||||
!tokenCache.writeEnabled &&
|
||||
new URLSearchParams(window.location.search).get("storeToken") === "true"
|
||||
) {
|
||||
tokenCache.writeEnabled = true;
|
||||
}
|
||||
|
||||
if (tokenCache.writeEnabled) {
|
||||
try {
|
||||
storage.hassTokens = JSON.stringify(tokens);
|
||||
@@ -53,6 +45,7 @@ export function enableWrite() {
|
||||
saveTokens(tokenCache.tokens);
|
||||
}
|
||||
}
|
||||
|
||||
export function loadTokens() {
|
||||
if (tokenCache.tokens === undefined) {
|
||||
try {
|
||||
|
||||
@@ -70,7 +70,7 @@ export interface DataTableSortColumnData {
|
||||
|
||||
export interface DataTableColumnData extends DataTableSortColumnData {
|
||||
title: TemplateResult | string;
|
||||
type?: "numeric" | "icon" | "icon-button" | "overflow-menu";
|
||||
type?: "numeric" | "icon" | "icon-button";
|
||||
template?: <T>(data: any, row: T) => TemplateResult | string;
|
||||
width?: string;
|
||||
maxWidth?: string;
|
||||
@@ -281,13 +281,15 @@ export class HaDataTable extends LitElement {
|
||||
}
|
||||
const sorted = key === this._sortColumn;
|
||||
const classes = {
|
||||
"mdc-data-table__header-cell--numeric":
|
||||
column.type === "numeric",
|
||||
"mdc-data-table__header-cell--icon": column.type === "icon",
|
||||
"mdc-data-table__header-cell--icon-button":
|
||||
column.type === "icon-button",
|
||||
"mdc-data-table__header-cell--overflow-menu":
|
||||
column.type === "overflow-menu",
|
||||
"mdc-data-table__header-cell--numeric": Boolean(
|
||||
column.type === "numeric"
|
||||
),
|
||||
"mdc-data-table__header-cell--icon": Boolean(
|
||||
column.type === "icon"
|
||||
),
|
||||
"mdc-data-table__header-cell--icon-button": Boolean(
|
||||
column.type === "icon-button"
|
||||
),
|
||||
sortable: Boolean(column.sortable),
|
||||
"not-sorted": Boolean(column.sortable && !sorted),
|
||||
grows: Boolean(column.grows),
|
||||
@@ -403,14 +405,14 @@ export class HaDataTable extends LitElement {
|
||||
<div
|
||||
role="cell"
|
||||
class="mdc-data-table__cell ${classMap({
|
||||
"mdc-data-table__cell--numeric":
|
||||
column.type === "numeric",
|
||||
"mdc-data-table__cell--icon":
|
||||
column.type === "icon",
|
||||
"mdc-data-table__cell--numeric": Boolean(
|
||||
column.type === "numeric"
|
||||
),
|
||||
"mdc-data-table__cell--icon": Boolean(
|
||||
column.type === "icon"
|
||||
),
|
||||
"mdc-data-table__cell--icon-button":
|
||||
column.type === "icon-button",
|
||||
"mdc-data-table__cell--overflow-menu":
|
||||
column.type === "overflow-menu",
|
||||
Boolean(column.type === "icon-button"),
|
||||
grows: Boolean(column.grows),
|
||||
forceLTR: Boolean(column.forceLTR),
|
||||
})}"
|
||||
@@ -767,65 +769,40 @@ export class HaDataTable extends LitElement {
|
||||
margin-left: -8px;
|
||||
}
|
||||
|
||||
.mdc-data-table__cell--overflow-menu,
|
||||
.mdc-data-table__header-cell--overflow-menu,
|
||||
.mdc-data-table__header-cell--icon-button,
|
||||
.mdc-data-table__cell--icon-button {
|
||||
padding: 8px;
|
||||
}
|
||||
|
||||
.mdc-data-table__header-cell--icon-button,
|
||||
.mdc-data-table__cell--icon-button {
|
||||
width: 56px;
|
||||
padding: 8px;
|
||||
}
|
||||
|
||||
.mdc-data-table__cell--overflow-menu,
|
||||
.mdc-data-table__cell--icon-button {
|
||||
color: var(--secondary-text-color);
|
||||
text-overflow: clip;
|
||||
}
|
||||
|
||||
.mdc-data-table__header-cell--icon-button:first-child,
|
||||
.mdc-data-table__cell--icon-button:first-child,
|
||||
.mdc-data-table__cell--icon-button:first-child {
|
||||
width: 64px;
|
||||
padding-left: 16px;
|
||||
}
|
||||
:host([dir="rtl"])
|
||||
.mdc-data-table__header-cell--icon-button:first-child,
|
||||
:host([dir="rtl"]) .mdc-data-table__cell--icon-button:first-child {
|
||||
padding-left: auto;
|
||||
padding-right: 16px;
|
||||
}
|
||||
|
||||
.mdc-data-table__header-cell--icon-button:last-child,
|
||||
.mdc-data-table__cell--icon-button:last-child {
|
||||
width: 64px;
|
||||
}
|
||||
|
||||
.mdc-data-table__cell--overflow-menu:first-child,
|
||||
.mdc-data-table__header-cell--overflow-menu:first-child,
|
||||
.mdc-data-table__header-cell--icon-button:first-child,
|
||||
.mdc-data-table__cell--icon-button:first-child {
|
||||
padding-left: 16px;
|
||||
}
|
||||
:host([dir="rtl"])
|
||||
.mdc-data-table__header-cell--overflow-menu:first-child,
|
||||
:host([dir="rtl"]) .mdc-data-table__cell--overflow-menu:first-child,
|
||||
:host([dir="rtl"])
|
||||
.mdc-data-table__header-cell--overflow-menu:first-child,
|
||||
:host([dir="rtl"]) .mdc-data-table__cell--overflow-menu:first-child {
|
||||
padding-left: 8px;
|
||||
padding-right: 16px;
|
||||
}
|
||||
|
||||
.mdc-data-table__cell--overflow-menu:last-child,
|
||||
.mdc-data-table__header-cell--overflow-menu:last-child,
|
||||
.mdc-data-table__header-cell--icon-button:last-child,
|
||||
.mdc-data-table__cell--icon-button:last-child {
|
||||
padding-right: 16px;
|
||||
}
|
||||
:host([dir="rtl"])
|
||||
.mdc-data-table__header-cell--overflow-menu:last-child,
|
||||
:host([dir="rtl"]) .mdc-data-table__cell--overflow-menu:last-child,
|
||||
:host([dir="rtl"]) .mdc-data-table__header-cell--icon-button:last-child,
|
||||
:host([dir="rtl"]) .mdc-data-table__cell--icon-button:last-child {
|
||||
padding-right: 8px;
|
||||
padding-right: auto;
|
||||
padding-left: 16px;
|
||||
}
|
||||
.mdc-data-table__cell--overflow-menu,
|
||||
.mdc-data-table__header-cell--overflow-menu {
|
||||
overflow: initial;
|
||||
}
|
||||
|
||||
.mdc-data-table__cell--icon-button a {
|
||||
color: var(--secondary-text-color);
|
||||
}
|
||||
|
||||
@@ -102,12 +102,7 @@ export class HaStatisticPicker extends LitElement {
|
||||
</style>
|
||||
<ha-svg-icon .path=${mdiCheck}></ha-svg-icon>
|
||||
<paper-icon-item>
|
||||
${item.state
|
||||
? html`<state-badge
|
||||
slot="item-icon"
|
||||
.stateObj=${item.state}
|
||||
></state-badge>`
|
||||
: ""}
|
||||
<state-badge slot="item-icon" .stateObj=${item.state}></state-badge>
|
||||
<paper-item-body two-line="">
|
||||
${item.name}
|
||||
<span secondary
|
||||
@@ -158,10 +153,7 @@ export class HaStatisticPicker extends LitElement {
|
||||
const entityState = this.hass.states[meta.statistic_id];
|
||||
if (!entityState) {
|
||||
if (!entitiesOnly) {
|
||||
output.push({
|
||||
id: meta.statistic_id,
|
||||
name: meta.name || meta.statistic_id,
|
||||
});
|
||||
output.push({ id: meta.statistic_id, name: meta.statistic_id });
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -9,49 +9,47 @@ import {
|
||||
unsafeCSS,
|
||||
} from "lit";
|
||||
import { customElement, property } from "lit/decorators";
|
||||
import { fireEvent } from "../common/dom/fire_event";
|
||||
import "./ha-chip";
|
||||
|
||||
declare global {
|
||||
// for fire event
|
||||
interface HASSDomEvents {
|
||||
"chip-clicked": { index: string };
|
||||
}
|
||||
export interface HaChipSetItem {
|
||||
label?: string;
|
||||
leadingIcon?: string;
|
||||
trailingIcon?: string;
|
||||
outlined?: boolean;
|
||||
active?: boolean;
|
||||
}
|
||||
|
||||
@customElement("ha-chip-set")
|
||||
export class HaChipSet extends LitElement {
|
||||
@property() public items = [];
|
||||
@property({ attribute: false }) public items?: HaChipSetItem[];
|
||||
|
||||
protected render(): TemplateResult {
|
||||
if (this.items.length === 0) {
|
||||
return html``;
|
||||
}
|
||||
return html`
|
||||
<div class="mdc-chip-set">
|
||||
${this.items.map(
|
||||
(item, idx) =>
|
||||
html`
|
||||
<ha-chip .index=${idx} @click=${this._handleClick}>
|
||||
${item}
|
||||
</ha-chip>
|
||||
`
|
||||
)}
|
||||
${this.items
|
||||
? this.items.map(
|
||||
(item, idx) =>
|
||||
html`
|
||||
<ha-chip
|
||||
.index=${idx}
|
||||
.active=${item.active || false}
|
||||
.label=${item.label}
|
||||
.leadingIcon=${item.leadingIcon}
|
||||
.trailingIcon=${item.trailingIcon}
|
||||
?outlined=${item.outlined}
|
||||
>
|
||||
</ha-chip>
|
||||
`
|
||||
)
|
||||
: html`<slot></slot>`}
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
private _handleClick(ev): void {
|
||||
fireEvent(this, "chip-clicked", {
|
||||
index: ev.currentTarget.index,
|
||||
});
|
||||
}
|
||||
|
||||
static get styles(): CSSResultGroup {
|
||||
return css`
|
||||
${unsafeCSS(chipStyles)}
|
||||
|
||||
ha-chip {
|
||||
.mdc-chip-set > ha-chip, slot::slotted(ha-chip) {
|
||||
margin: 4px;
|
||||
}
|
||||
`;
|
||||
|
||||
+137
-19
@@ -1,4 +1,5 @@
|
||||
// @ts-ignore
|
||||
import "./ha-circular-progress";
|
||||
import "./ha-svg-icon"; // @ts-ignore
|
||||
import chipStyles from "@material/chips/dist/mdc.chips.min.css";
|
||||
import {
|
||||
css,
|
||||
@@ -9,56 +10,173 @@ import {
|
||||
unsafeCSS,
|
||||
} from "lit";
|
||||
import { customElement, property } from "lit/decorators";
|
||||
import { fireEvent } from "../common/dom/fire_event";
|
||||
|
||||
declare global {
|
||||
// for fire event
|
||||
interface HASSDomEvents {
|
||||
"chip-clicked": { index: string };
|
||||
"chip-clicked": { index: number | undefined };
|
||||
"chip-clicked-trailing": { index: number | undefined };
|
||||
}
|
||||
}
|
||||
|
||||
@customElement("ha-chip")
|
||||
export class HaChip extends LitElement {
|
||||
@property() public index = 0;
|
||||
@property({ type: Number }) public index?: number;
|
||||
|
||||
@property({ type: Boolean }) public hasIcon = false;
|
||||
@property({ type: Boolean }) public outlined = false;
|
||||
|
||||
@property({ type: Boolean }) public active = false;
|
||||
|
||||
@property() public label?: string;
|
||||
|
||||
@property() public leadingIcon?: string;
|
||||
|
||||
@property() public trailingIcon?: string;
|
||||
|
||||
protected render(): TemplateResult {
|
||||
return html`
|
||||
<div class="mdc-chip" .index=${this.index}>
|
||||
${this.hasIcon
|
||||
? html`<div class="mdc-chip__icon mdc-chip__icon--leading">
|
||||
<slot name="icon"></slot>
|
||||
</div>`
|
||||
: null}
|
||||
<div
|
||||
class="mdc-chip ${this.outlined ? "outlined" : ""}"
|
||||
@click=${this._handleClick}
|
||||
>
|
||||
${this.leadingIcon
|
||||
? html`<span role="gridcell">
|
||||
<span role="button" tabindex="0" class="mdc-chip__primary-action">
|
||||
${this.active
|
||||
? html`<ha-circular-progress alt="active" size="tiny" active>
|
||||
</ha-circular-progress>`
|
||||
: html`<ha-svg-icon
|
||||
class="mdc-chip__icon mdc-chip__icon--leading"
|
||||
.path=${this.leadingIcon}
|
||||
>
|
||||
</ha-svg-icon>`}
|
||||
</span>
|
||||
</span>`
|
||||
: ""}
|
||||
<div class="mdc-chip__ripple"></div>
|
||||
<span role="gridcell">
|
||||
<span role="button" tabindex="0" class="mdc-chip__primary-action">
|
||||
<span class="mdc-chip__text"><slot></slot></span>
|
||||
<span role="row" tabindex="0" class="mdc-chip__primary-action">
|
||||
<span class="mdc-chip__text">
|
||||
${this.label || html`<slot></slot>`}
|
||||
</span>
|
||||
</span>
|
||||
</span>
|
||||
<span role="gridcell">
|
||||
<span role="button" tabindex="-1" class="mdc-chip__primary-action">
|
||||
${this.trailingIcon
|
||||
? html`<ha-svg-icon
|
||||
@click=${this._handleTrailingClick}
|
||||
class="mdc-chip__icon mdc-chip__icon--trailing"
|
||||
.path=${this.trailingIcon}
|
||||
>
|
||||
</ha-svg-icon>`
|
||||
: html`<slot name="trailing-icon"></slot>`}
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
private _handleClick(): void {
|
||||
fireEvent(this, "chip-clicked", { index: this.index });
|
||||
}
|
||||
|
||||
private _handleTrailingClick(): void {
|
||||
fireEvent(this, "chip-clicked-trailing", {
|
||||
index: this.index,
|
||||
});
|
||||
}
|
||||
|
||||
static get styles(): CSSResultGroup {
|
||||
return css`
|
||||
${unsafeCSS(chipStyles)}
|
||||
.mdc-chip {
|
||||
background-color: var(
|
||||
--ha-chip-background-color,
|
||||
rgba(var(--rgb-primary-text-color), 0.15)
|
||||
);
|
||||
color: var(--ha-chip-text-color, var(--primary-text-color));
|
||||
background-color: var(--ha-chip-background-color, var(--primary-color));
|
||||
color: var(--ha-chip-text-color, var(--text-primary-color));
|
||||
}
|
||||
|
||||
.mdc-chip:hover {
|
||||
color: var(--ha-chip-text-color, var(--primary-text-color));
|
||||
color: var(--ha-chip-text-color, var(--text-primary-color));
|
||||
}
|
||||
|
||||
.mdc-chip.outlined {
|
||||
margin: 0 -1px !important;
|
||||
border: 1px solid var(--ha-chip-background-color, var(--primary-color));
|
||||
background-color: var(
|
||||
--ha-chip-outlined-background-color,
|
||||
var(--card-background-color)
|
||||
);
|
||||
color: var(--ha-chip-outlined-text-color, var(--primary-text-color));
|
||||
}
|
||||
|
||||
.mdc-chip:not(.outlined) .mdc-chip__icon.mdc-chip__icon--leading {
|
||||
margin-left: -12px !important;
|
||||
margin-right: -2px;
|
||||
color: var(--ha-chip-icon-color, var(--text-primary-color));
|
||||
}
|
||||
|
||||
ha-circular-progress {
|
||||
--mdc-theme-primary: var(
|
||||
--ha-chip-icon-color,
|
||||
var(--text-primary-color)
|
||||
);
|
||||
padding: 8px;
|
||||
margin-left: -12px !important;
|
||||
margin-right: -2px;
|
||||
}
|
||||
|
||||
.mdc-chip.outlined ha-circular-progress {
|
||||
border-radius: 50%;
|
||||
margin-right: 4px;
|
||||
background-color: var(--ha-chip-background-color, var(--primary-color));
|
||||
--mdc-theme-primary: var(
|
||||
--ha-chip-icon-color,
|
||||
var(--text-primary-color)
|
||||
);
|
||||
}
|
||||
|
||||
.mdc-chip.outlined ha-svg-icon,
|
||||
slot[name="trailing-icon"]::slotted(ha-svg-icon) {
|
||||
border-radius: 50%;
|
||||
background-color: var(--ha-chip-background-color, var(--primary-color));
|
||||
color: var(--ha-chip-icon-color, var(--text-primary-color));
|
||||
}
|
||||
|
||||
.mdc-chip.outlined .mdc-chip__icon.mdc-chip__icon--leading {
|
||||
margin-left: -13px !important;
|
||||
color: var(--ha-chip-icon-color, var(--text-primary-color));
|
||||
}
|
||||
|
||||
.mdc-chip__icon.mdc-chip__icon--trailing,
|
||||
slot[name="trailing-icon"]::slotted(ha-svg-icon) {
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
font-size: 18px;
|
||||
padding: 2px;
|
||||
color: var(--ha-chip-icon-color, var(--text-primary-color));
|
||||
margin-right: -8px;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
--mdc-icon-size: 12px;
|
||||
}
|
||||
|
||||
slot[name="trailing-icon"]::slotted(ha-svg-icon) {
|
||||
margin-left: 4px;
|
||||
}
|
||||
|
||||
.mdc-chip__icon--leading {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
color: inherit;
|
||||
border-radius: 50%;
|
||||
padding: 6px;
|
||||
--mdc-icon-size: 20px;
|
||||
color: var(--ha-chip-icon-color, var(--ha-chip-text-color));
|
||||
}
|
||||
:host([disabled]) .mdc-chip {
|
||||
opacity: var(--light-disabled-opacity);
|
||||
pointer-events: none;
|
||||
}
|
||||
`;
|
||||
}
|
||||
|
||||
@@ -1,119 +0,0 @@
|
||||
import { css, html, LitElement, TemplateResult } from "lit";
|
||||
import { customElement, property } from "lit/decorators";
|
||||
import "./ha-button-menu";
|
||||
import "@material/mwc-list/mwc-list-item";
|
||||
import "@material/mwc-icon-button";
|
||||
import "./ha-svg-icon";
|
||||
import { mdiDotsVertical } from "@mdi/js";
|
||||
import { HomeAssistant } from "../types";
|
||||
import "@polymer/paper-tooltip/paper-tooltip";
|
||||
|
||||
export interface IconOverflowMenuItem {
|
||||
[key: string]: any;
|
||||
path: string;
|
||||
label: string;
|
||||
narrowOnly?: boolean;
|
||||
disabled?: boolean;
|
||||
tooltip?: string;
|
||||
onClick: CallableFunction;
|
||||
}
|
||||
|
||||
@customElement("ha-icon-overflow-menu")
|
||||
export class HaIconOverflowMenu extends LitElement {
|
||||
@property({ attribute: false }) public hass!: HomeAssistant;
|
||||
|
||||
@property({ type: Array }) public items: IconOverflowMenuItem[] = [];
|
||||
|
||||
@property({ type: Boolean }) public narrow = false;
|
||||
|
||||
protected render(): TemplateResult {
|
||||
return html`
|
||||
${this.narrow
|
||||
? html` <!-- Collapsed Representation for Small Screens -->
|
||||
<ha-button-menu
|
||||
@click=${this._handleIconOverflowMenuOpened}
|
||||
@closed=${this._handleIconOverflowMenuClosed}
|
||||
class="ha-icon-overflow-menu-overflow"
|
||||
corner="BOTTOM_START"
|
||||
absolute
|
||||
>
|
||||
<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>
|
||||
|
||||
${this.items.map(
|
||||
(item) => html`
|
||||
<mwc-list-item
|
||||
graphic="icon"
|
||||
.disabled=${item.disabled}
|
||||
@click=${item.action}
|
||||
>
|
||||
<div slot="graphic">
|
||||
<ha-svg-icon .path=${item.path}></ha-svg-icon>
|
||||
</div>
|
||||
${item.label}
|
||||
</mwc-list-item>
|
||||
`
|
||||
)}
|
||||
</ha-button-menu>`
|
||||
: html`
|
||||
<!-- Icon Representation for Big Screens -->
|
||||
|
||||
${this.items.map((item) =>
|
||||
item.narrowOnly
|
||||
? ""
|
||||
: html`<div>
|
||||
${item.tooltip
|
||||
? html`<paper-tooltip animation-delay="0" position="left">
|
||||
${item.tooltip}
|
||||
</paper-tooltip>`
|
||||
: ""}
|
||||
<mwc-icon-button
|
||||
@click=${item.action}
|
||||
.label=${item.label}
|
||||
.disabled=${item.disabled}
|
||||
>
|
||||
<ha-svg-icon .path=${item.path}></ha-svg-icon>
|
||||
</mwc-icon-button>
|
||||
</div> `
|
||||
)}
|
||||
`}
|
||||
`;
|
||||
}
|
||||
|
||||
protected _handleIconOverflowMenuOpened() {
|
||||
// If this component is used inside a data table, the z-index of the row
|
||||
// needs to be increased. Otherwise the ha-button-menu would be displayed
|
||||
// underneath the next row in the table.
|
||||
const row = this.closest(".mdc-data-table__row") as HTMLDivElement | null;
|
||||
if (row) {
|
||||
row.style.zIndex = "1";
|
||||
}
|
||||
}
|
||||
|
||||
protected _handleIconOverflowMenuClosed() {
|
||||
const row = this.closest(".mdc-data-table__row") as HTMLDivElement | null;
|
||||
if (row) {
|
||||
row.style.zIndex = "";
|
||||
}
|
||||
}
|
||||
|
||||
static get styles() {
|
||||
return css`
|
||||
:host {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
}
|
||||
`;
|
||||
}
|
||||
}
|
||||
|
||||
declare global {
|
||||
interface HTMLElementTagNameMap {
|
||||
"ha-icon-overflow-menu": HaIconOverflowMenu;
|
||||
}
|
||||
}
|
||||
+103
-190
@@ -1,5 +1,3 @@
|
||||
// @ts-ignore
|
||||
import chipStyles from "@material/chips/dist/mdc.chips.min.css";
|
||||
import "@material/mwc-button/mwc-button";
|
||||
import {
|
||||
mdiClose,
|
||||
@@ -14,13 +12,13 @@ import {
|
||||
HassServiceTarget,
|
||||
UnsubscribeFunc,
|
||||
} from "home-assistant-js-websocket";
|
||||
import { css, CSSResultGroup, html, LitElement, unsafeCSS } from "lit";
|
||||
import { css, CSSResultGroup, html, LitElement } from "lit";
|
||||
import { customElement, property, query, state } from "lit/decorators";
|
||||
import { classMap } from "lit/directives/class-map";
|
||||
import { fireEvent } from "../common/dom/fire_event";
|
||||
import { ensureArray } from "../common/ensure-array";
|
||||
import { computeDomain } from "../common/entity/compute_domain";
|
||||
import { computeStateName } from "../common/entity/compute_state_name";
|
||||
import { stateIconPath } from "../common/entity/state_icon_path";
|
||||
import {
|
||||
AreaRegistryEntry,
|
||||
subscribeAreaRegistry,
|
||||
@@ -41,6 +39,7 @@ import type { HaDevicePickerDeviceFilterFunc } from "./device/ha-device-picker";
|
||||
import "./entity/ha-entity-picker";
|
||||
import type { HaEntityPickerEntityFilterFunc } from "./entity/ha-entity-picker";
|
||||
import "./ha-area-picker";
|
||||
import "./ha-chip-set";
|
||||
import "./ha-icon-button";
|
||||
import "./ha-svg-icon";
|
||||
|
||||
@@ -114,7 +113,7 @@ export class HaTargetPicker extends SubscribeMixin(LitElement) {
|
||||
if (!this._areas || !this._devices || !this._entities) {
|
||||
return html``;
|
||||
}
|
||||
return html`<div class="mdc-chip-set items">
|
||||
return html`<ha-chip-set>
|
||||
${this.value?.area_id
|
||||
? ensureArray(this.value.area_id).map((area_id) => {
|
||||
const area = this._areas![area_id];
|
||||
@@ -150,70 +149,39 @@ export class HaTargetPicker extends SubscribeMixin(LitElement) {
|
||||
);
|
||||
})
|
||||
: ""}
|
||||
</div>
|
||||
</ha-chip-set>
|
||||
${this._renderPicker()}
|
||||
<div class="mdc-chip-set">
|
||||
<div
|
||||
class="mdc-chip area_id add"
|
||||
<ha-chip-set>
|
||||
<ha-chip
|
||||
class="area_id add"
|
||||
.type=${"area_id"}
|
||||
@click=${this._showPicker}
|
||||
.leadingIcon=${mdiPlus}
|
||||
.label=${this.hass.localize(
|
||||
"ui.components.target-picker.add_area_id"
|
||||
)}
|
||||
>
|
||||
<div class="mdc-chip__ripple"></div>
|
||||
<ha-svg-icon
|
||||
class="mdc-chip__icon mdc-chip__icon--leading"
|
||||
.path=${mdiPlus}
|
||||
></ha-svg-icon>
|
||||
<span role="gridcell">
|
||||
<span role="button" tabindex="0" class="mdc-chip__primary-action">
|
||||
<span class="mdc-chip__text"
|
||||
>${this.hass.localize(
|
||||
"ui.components.target-picker.add_area_id"
|
||||
)}</span
|
||||
>
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
<div
|
||||
class="mdc-chip device_id add"
|
||||
</ha-chip>
|
||||
<ha-chip
|
||||
class="device_id add"
|
||||
.type=${"device_id"}
|
||||
@click=${this._showPicker}
|
||||
.leadingIcon=${mdiPlus}
|
||||
.label=${this.hass.localize(
|
||||
"ui.components.target-picker.add_device_id"
|
||||
)}
|
||||
>
|
||||
<div class="mdc-chip__ripple"></div>
|
||||
<ha-svg-icon
|
||||
class="mdc-chip__icon mdc-chip__icon--leading"
|
||||
.path=${mdiPlus}
|
||||
></ha-svg-icon>
|
||||
<span role="gridcell">
|
||||
<span role="button" tabindex="0" class="mdc-chip__primary-action">
|
||||
<span class="mdc-chip__text"
|
||||
>${this.hass.localize(
|
||||
"ui.components.target-picker.add_device_id"
|
||||
)}</span
|
||||
>
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
<div
|
||||
class="mdc-chip entity_id add"
|
||||
</ha-chip>
|
||||
<ha-chip
|
||||
class="entity_id add"
|
||||
.type=${"entity_id"}
|
||||
@click=${this._showPicker}
|
||||
>
|
||||
<div class="mdc-chip__ripple"></div>
|
||||
<ha-svg-icon
|
||||
class="mdc-chip__icon mdc-chip__icon--leading"
|
||||
.path=${mdiPlus}
|
||||
></ha-svg-icon>
|
||||
<span role="gridcell">
|
||||
<span role="button" tabindex="0" class="mdc-chip__primary-action">
|
||||
<span class="mdc-chip__text"
|
||||
>${this.hass.localize(
|
||||
"ui.components.target-picker.add_entity_id"
|
||||
)}</span
|
||||
>
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
</div>`;
|
||||
.leadingIcon=${mdiPlus}
|
||||
.label=${this.hass.localize(
|
||||
"ui.components.target-picker.add_entity_id"
|
||||
)}
|
||||
></ha-chip>
|
||||
</ha-chip-set>`;
|
||||
}
|
||||
|
||||
private async _showPicker(ev) {
|
||||
@@ -233,69 +201,59 @@ export class HaTargetPicker extends SubscribeMixin(LitElement) {
|
||||
iconPath?: string
|
||||
) {
|
||||
return html`
|
||||
<div
|
||||
class="mdc-chip ${classMap({
|
||||
[type]: true,
|
||||
})}"
|
||||
<ha-chip
|
||||
class=${type}
|
||||
.id=${id}
|
||||
.leadingIcon=${iconPath ||
|
||||
entityState?.attributes.icon ||
|
||||
stateIconPath(entityState)}
|
||||
.label=${name}
|
||||
outlined
|
||||
>
|
||||
${iconPath
|
||||
? html`<ha-svg-icon
|
||||
class="mdc-chip__icon mdc-chip__icon--leading"
|
||||
.path=${iconPath}
|
||||
></ha-svg-icon>`
|
||||
: ""}
|
||||
${entityState
|
||||
? html`<ha-state-icon
|
||||
class="mdc-chip__icon mdc-chip__icon--leading"
|
||||
.state=${entityState}
|
||||
></ha-state-icon>`
|
||||
: ""}
|
||||
<span role="gridcell">
|
||||
<span role="button" tabindex="0" class="mdc-chip__primary-action">
|
||||
<span class="mdc-chip__text">${name}</span>
|
||||
<div slot="trailing-icon">
|
||||
${type === "entity_id"
|
||||
? ""
|
||||
: html`
|
||||
<span>
|
||||
<ha-icon-button
|
||||
class="expand-btn"
|
||||
tabindex="-1"
|
||||
role="button"
|
||||
.label=${this.hass.localize(
|
||||
"ui.components.target-picker.expand"
|
||||
)}
|
||||
.path=${mdiUnfoldMoreVertical}
|
||||
hideTitle
|
||||
.id=${id}
|
||||
.type=${type}
|
||||
@click=${this._handleExpand}
|
||||
></ha-icon-button>
|
||||
<paper-tooltip class="expand" animation-delay="0"
|
||||
>${this.hass.localize(
|
||||
`ui.components.target-picker.expand_${type}`
|
||||
)}</paper-tooltip
|
||||
>
|
||||
</span>
|
||||
`}
|
||||
<span>
|
||||
<ha-icon-button
|
||||
tabindex="-1"
|
||||
role="button"
|
||||
.label=${this.hass.localize("ui.components.target-picker.expand")}
|
||||
.path=${mdiClose}
|
||||
hideTitle
|
||||
.id=${id}
|
||||
.type=${type}
|
||||
@click=${this._handleRemove}
|
||||
></ha-icon-button>
|
||||
<paper-tooltip animation-delay="0"
|
||||
>${this.hass.localize(
|
||||
`ui.components.target-picker.remove_${type}`
|
||||
)}</paper-tooltip
|
||||
>
|
||||
</span>
|
||||
</span>
|
||||
${type === "entity_id"
|
||||
? ""
|
||||
: html` <span role="gridcell">
|
||||
<ha-icon-button
|
||||
class="expand-btn mdc-chip__icon mdc-chip__icon--trailing"
|
||||
tabindex="-1"
|
||||
role="button"
|
||||
.label=${this.hass.localize(
|
||||
"ui.components.target-picker.expand"
|
||||
)}
|
||||
.path=${mdiUnfoldMoreVertical}
|
||||
hideTooltip
|
||||
.id=${id}
|
||||
.type=${type}
|
||||
@click=${this._handleExpand}
|
||||
></ha-icon-button>
|
||||
<paper-tooltip class="expand" animation-delay="0"
|
||||
>${this.hass.localize(
|
||||
`ui.components.target-picker.expand_${type}`
|
||||
)}</paper-tooltip
|
||||
>
|
||||
</span>`}
|
||||
<span role="gridcell">
|
||||
<ha-icon-button
|
||||
class="mdc-chip__icon mdc-chip__icon--trailing"
|
||||
tabindex="-1"
|
||||
role="button"
|
||||
.label=${this.hass.localize("ui.components.target-picker.expand")}
|
||||
.path=${mdiClose}
|
||||
hideTooltip
|
||||
.id=${id}
|
||||
.type=${type}
|
||||
@click=${this._handleRemove}
|
||||
></ha-icon-button>
|
||||
<paper-tooltip animation-delay="0"
|
||||
>${this.hass.localize(
|
||||
`ui.components.target-picker.remove_${type}`
|
||||
)}</paper-tooltip
|
||||
>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</ha-chip>
|
||||
`;
|
||||
}
|
||||
|
||||
@@ -528,84 +486,39 @@ export class HaTargetPicker extends SubscribeMixin(LitElement) {
|
||||
|
||||
static get styles(): CSSResultGroup {
|
||||
return css`
|
||||
${unsafeCSS(chipStyles)}
|
||||
.mdc-chip {
|
||||
color: var(--primary-text-color);
|
||||
}
|
||||
.items {
|
||||
z-index: 2;
|
||||
}
|
||||
.mdc-chip-set {
|
||||
padding: 4px 0;
|
||||
}
|
||||
.mdc-chip.add {
|
||||
color: rgba(0, 0, 0, 0.87);
|
||||
}
|
||||
.mdc-chip:not(.add) {
|
||||
cursor: default;
|
||||
}
|
||||
.mdc-chip ha-icon-button {
|
||||
--mdc-icon-button-size: 24px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
outline: none;
|
||||
}
|
||||
.mdc-chip ha-icon-button ha-svg-icon {
|
||||
border-radius: 50%;
|
||||
background: var(--secondary-text-color);
|
||||
}
|
||||
.mdc-chip__icon.mdc-chip__icon--trailing {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
--mdc-icon-size: 14px;
|
||||
color: var(--secondary-text-color);
|
||||
}
|
||||
.mdc-chip__icon--leading {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
--mdc-icon-size: 20px;
|
||||
border-radius: 50%;
|
||||
padding: 6px;
|
||||
margin-left: -14px !important;
|
||||
}
|
||||
.expand-btn {
|
||||
margin-right: 0;
|
||||
}
|
||||
.mdc-chip.area_id:not(.add) {
|
||||
border: 2px solid #fed6a4;
|
||||
background: var(--card-background-color);
|
||||
ha-chip {
|
||||
--ha-chip-icon-color: var(--secondary-text-color);
|
||||
--ha-chip-text-color: var(--primary-text-color);
|
||||
}
|
||||
.mdc-chip.area_id:not(.add) .mdc-chip__icon--leading,
|
||||
.mdc-chip.area_id.add {
|
||||
background: #fed6a4;
|
||||
}
|
||||
.mdc-chip.device_id:not(.add) {
|
||||
border: 2px solid #a8e1fb;
|
||||
background: var(--card-background-color);
|
||||
}
|
||||
.mdc-chip.device_id:not(.add) .mdc-chip__icon--leading,
|
||||
.mdc-chip.device_id.add {
|
||||
background: #a8e1fb;
|
||||
}
|
||||
.mdc-chip.entity_id:not(.add) {
|
||||
border: 2px solid #d2e7b9;
|
||||
background: var(--card-background-color);
|
||||
}
|
||||
.mdc-chip.entity_id:not(.add) .mdc-chip__icon--leading,
|
||||
.mdc-chip.entity_id.add {
|
||||
background: #d2e7b9;
|
||||
}
|
||||
.mdc-chip:hover {
|
||||
ha-chip:hover {
|
||||
z-index: 5;
|
||||
}
|
||||
ha-icon-button {
|
||||
--mdc-icon-size: 18px;
|
||||
--mdc-icon-button-size: 24px;
|
||||
color: var(--secondary-text-color);
|
||||
outline: none;
|
||||
}
|
||||
ha-chip > div {
|
||||
margin-right: -8px;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
}
|
||||
ha-chip.area_id {
|
||||
--ha-chip-background-color: #fed6a4;
|
||||
}
|
||||
ha-chip.device_id {
|
||||
--ha-chip-background-color: #a8e1fb;
|
||||
}
|
||||
ha-chip.entity_id {
|
||||
--ha-chip-background-color: #d2e7b9;
|
||||
}
|
||||
paper-tooltip.expand {
|
||||
min-width: 200px;
|
||||
}
|
||||
:host([disabled]) .mdc-chip {
|
||||
opacity: var(--light-disabled-opacity);
|
||||
pointer-events: none;
|
||||
}
|
||||
`;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -74,8 +74,6 @@ export interface StatisticValue {
|
||||
export interface StatisticsMetaData {
|
||||
unit_of_measurement: string;
|
||||
statistic_id: string;
|
||||
source: string;
|
||||
name?: string | null;
|
||||
}
|
||||
|
||||
export type StatisticsValidationResult =
|
||||
|
||||
+49
-55
@@ -2,7 +2,6 @@ import { HassEntity } from "home-assistant-js-websocket";
|
||||
import { BINARY_STATE_OFF, BINARY_STATE_ON } from "../common/const";
|
||||
import { computeDomain } from "../common/entity/compute_domain";
|
||||
import { computeStateDisplay } from "../common/entity/compute_state_display";
|
||||
import { LocalizeFunc } from "../common/translations/localize";
|
||||
import { HomeAssistant } from "../types";
|
||||
import { UNAVAILABLE_STATES } from "./entity";
|
||||
|
||||
@@ -36,11 +35,9 @@ export const getLogbookDataForContext = async (
|
||||
hass: HomeAssistant,
|
||||
startDate: string,
|
||||
contextId?: string
|
||||
): Promise<LogbookEntry[]> => {
|
||||
const localize = await hass.loadBackendTranslation("device_class");
|
||||
return addLogbookMessage(
|
||||
): Promise<LogbookEntry[]> =>
|
||||
addLogbookMessage(
|
||||
hass,
|
||||
localize,
|
||||
await getLogbookDataFromServer(
|
||||
hass,
|
||||
startDate,
|
||||
@@ -50,7 +47,6 @@ export const getLogbookDataForContext = async (
|
||||
contextId
|
||||
)
|
||||
);
|
||||
};
|
||||
|
||||
export const getLogbookData = async (
|
||||
hass: HomeAssistant,
|
||||
@@ -58,11 +54,9 @@ export const getLogbookData = async (
|
||||
endDate: string,
|
||||
entityId?: string,
|
||||
entity_matches_only?: boolean
|
||||
): Promise<LogbookEntry[]> => {
|
||||
const localize = await hass.loadBackendTranslation("device_class");
|
||||
return addLogbookMessage(
|
||||
): Promise<LogbookEntry[]> =>
|
||||
addLogbookMessage(
|
||||
hass,
|
||||
localize,
|
||||
await getLogbookDataCache(
|
||||
hass,
|
||||
startDate,
|
||||
@@ -71,11 +65,9 @@ export const getLogbookData = async (
|
||||
entity_matches_only
|
||||
)
|
||||
);
|
||||
};
|
||||
|
||||
export const addLogbookMessage = (
|
||||
hass: HomeAssistant,
|
||||
localize: LocalizeFunc,
|
||||
logbookData: LogbookEntry[]
|
||||
): LogbookEntry[] => {
|
||||
for (const entry of logbookData) {
|
||||
@@ -83,7 +75,6 @@ export const addLogbookMessage = (
|
||||
if (entry.state && stateObj) {
|
||||
entry.message = getLogbookMessage(
|
||||
hass,
|
||||
localize,
|
||||
entry.state,
|
||||
stateObj,
|
||||
computeDomain(entry.entity_id!)
|
||||
@@ -166,7 +157,6 @@ export const clearLogbookCache = (startDate: string, endDate: string) => {
|
||||
|
||||
export const getLogbookMessage = (
|
||||
hass: HomeAssistant,
|
||||
localize: LocalizeFunc,
|
||||
state: string,
|
||||
stateObj: HassEntity,
|
||||
domain: string
|
||||
@@ -175,17 +165,21 @@ export const getLogbookMessage = (
|
||||
case "device_tracker":
|
||||
case "person":
|
||||
if (state === "not_home") {
|
||||
return localize(`${LOGBOOK_LOCALIZE_PATH}.was_away`);
|
||||
return hass.localize(`${LOGBOOK_LOCALIZE_PATH}.was_away`);
|
||||
}
|
||||
if (state === "home") {
|
||||
return localize(`${LOGBOOK_LOCALIZE_PATH}.was_at_home`);
|
||||
return hass.localize(`${LOGBOOK_LOCALIZE_PATH}.was_at_home`);
|
||||
}
|
||||
return localize(`${LOGBOOK_LOCALIZE_PATH}.was_at_state`, "state", state);
|
||||
return hass.localize(
|
||||
`${LOGBOOK_LOCALIZE_PATH}.was_at_state`,
|
||||
"state",
|
||||
state
|
||||
);
|
||||
|
||||
case "sun":
|
||||
return state === "above_horizon"
|
||||
? localize(`${LOGBOOK_LOCALIZE_PATH}.rose`)
|
||||
: localize(`${LOGBOOK_LOCALIZE_PATH}.set`);
|
||||
? hass.localize(`${LOGBOOK_LOCALIZE_PATH}.rose`)
|
||||
: hass.localize(`${LOGBOOK_LOCALIZE_PATH}.set`);
|
||||
|
||||
case "binary_sensor": {
|
||||
const isOn = state === BINARY_STATE_ON;
|
||||
@@ -195,19 +189,19 @@ export const getLogbookMessage = (
|
||||
switch (device_class) {
|
||||
case "battery":
|
||||
if (isOn) {
|
||||
return localize(`${LOGBOOK_LOCALIZE_PATH}.was_low`);
|
||||
return hass.localize(`${LOGBOOK_LOCALIZE_PATH}.was_low`);
|
||||
}
|
||||
if (isOff) {
|
||||
return localize(`${LOGBOOK_LOCALIZE_PATH}.was_normal`);
|
||||
return hass.localize(`${LOGBOOK_LOCALIZE_PATH}.was_normal`);
|
||||
}
|
||||
break;
|
||||
|
||||
case "connectivity":
|
||||
if (isOn) {
|
||||
return localize(`${LOGBOOK_LOCALIZE_PATH}.was_connected`);
|
||||
return hass.localize(`${LOGBOOK_LOCALIZE_PATH}.was_connected`);
|
||||
}
|
||||
if (isOff) {
|
||||
return localize(`${LOGBOOK_LOCALIZE_PATH}.was_disconnected`);
|
||||
return hass.localize(`${LOGBOOK_LOCALIZE_PATH}.was_disconnected`);
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -216,46 +210,46 @@ export const getLogbookMessage = (
|
||||
case "opening":
|
||||
case "window":
|
||||
if (isOn) {
|
||||
return localize(`${LOGBOOK_LOCALIZE_PATH}.was_opened`);
|
||||
return hass.localize(`${LOGBOOK_LOCALIZE_PATH}.was_opened`);
|
||||
}
|
||||
if (isOff) {
|
||||
return localize(`${LOGBOOK_LOCALIZE_PATH}.was_closed`);
|
||||
return hass.localize(`${LOGBOOK_LOCALIZE_PATH}.was_closed`);
|
||||
}
|
||||
break;
|
||||
|
||||
case "lock":
|
||||
if (isOn) {
|
||||
return localize(`${LOGBOOK_LOCALIZE_PATH}.was_unlocked`);
|
||||
return hass.localize(`${LOGBOOK_LOCALIZE_PATH}.was_unlocked`);
|
||||
}
|
||||
if (isOff) {
|
||||
return localize(`${LOGBOOK_LOCALIZE_PATH}.was_locked`);
|
||||
return hass.localize(`${LOGBOOK_LOCALIZE_PATH}.was_locked`);
|
||||
}
|
||||
break;
|
||||
|
||||
case "plug":
|
||||
if (isOn) {
|
||||
return localize(`${LOGBOOK_LOCALIZE_PATH}.was_plugged_in`);
|
||||
return hass.localize(`${LOGBOOK_LOCALIZE_PATH}.was_plugged_in`);
|
||||
}
|
||||
if (isOff) {
|
||||
return localize(`${LOGBOOK_LOCALIZE_PATH}.was_unplugged`);
|
||||
return hass.localize(`${LOGBOOK_LOCALIZE_PATH}.was_unplugged`);
|
||||
}
|
||||
break;
|
||||
|
||||
case "presence":
|
||||
if (isOn) {
|
||||
return localize(`${LOGBOOK_LOCALIZE_PATH}.was_at_home`);
|
||||
return hass.localize(`${LOGBOOK_LOCALIZE_PATH}.was_at_home`);
|
||||
}
|
||||
if (isOff) {
|
||||
return localize(`${LOGBOOK_LOCALIZE_PATH}.was_away`);
|
||||
return hass.localize(`${LOGBOOK_LOCALIZE_PATH}.was_away`);
|
||||
}
|
||||
break;
|
||||
|
||||
case "safety":
|
||||
if (isOn) {
|
||||
return localize(`${LOGBOOK_LOCALIZE_PATH}.was_unsafe`);
|
||||
return hass.localize(`${LOGBOOK_LOCALIZE_PATH}.was_unsafe`);
|
||||
}
|
||||
if (isOff) {
|
||||
return localize(`${LOGBOOK_LOCALIZE_PATH}.was_safe`);
|
||||
return hass.localize(`${LOGBOOK_LOCALIZE_PATH}.was_safe`);
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -271,27 +265,27 @@ export const getLogbookMessage = (
|
||||
case "sound":
|
||||
case "vibration":
|
||||
if (isOn) {
|
||||
return localize(`${LOGBOOK_LOCALIZE_PATH}.detected_device_class`, {
|
||||
device_class: localize(
|
||||
`component.binary_sensor.device_class.${device_class}`
|
||||
),
|
||||
});
|
||||
return hass.localize(
|
||||
`${LOGBOOK_LOCALIZE_PATH}.detected_device_class`,
|
||||
"device_class",
|
||||
device_class
|
||||
);
|
||||
}
|
||||
if (isOff) {
|
||||
return localize(`${LOGBOOK_LOCALIZE_PATH}.cleared_device_class`, {
|
||||
device_class: localize(
|
||||
`component.binary_sensor.device_class.${device_class}`
|
||||
),
|
||||
});
|
||||
return hass.localize(
|
||||
`${LOGBOOK_LOCALIZE_PATH}.cleared_device_class`,
|
||||
"device_class",
|
||||
device_class
|
||||
);
|
||||
}
|
||||
break;
|
||||
|
||||
case "tamper":
|
||||
if (isOn) {
|
||||
return localize(`${LOGBOOK_LOCALIZE_PATH}.detected_tampering`);
|
||||
return hass.localize(`${LOGBOOK_LOCALIZE_PATH}.detected_tampering`);
|
||||
}
|
||||
if (isOff) {
|
||||
return localize(`${LOGBOOK_LOCALIZE_PATH}.cleared_tampering`);
|
||||
return hass.localize(`${LOGBOOK_LOCALIZE_PATH}.cleared_tampering`);
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -302,43 +296,43 @@ export const getLogbookMessage = (
|
||||
case "cover":
|
||||
switch (state) {
|
||||
case "open":
|
||||
return localize(`${LOGBOOK_LOCALIZE_PATH}.was_opened`);
|
||||
return hass.localize(`${LOGBOOK_LOCALIZE_PATH}.was_opened`);
|
||||
case "opening":
|
||||
return localize(`${LOGBOOK_LOCALIZE_PATH}.is_opening`);
|
||||
return hass.localize(`${LOGBOOK_LOCALIZE_PATH}.is_opening`);
|
||||
case "closing":
|
||||
return localize(`${LOGBOOK_LOCALIZE_PATH}.is_closing`);
|
||||
return hass.localize(`${LOGBOOK_LOCALIZE_PATH}.is_closing`);
|
||||
case "closed":
|
||||
return localize(`${LOGBOOK_LOCALIZE_PATH}.was_closed`);
|
||||
return hass.localize(`${LOGBOOK_LOCALIZE_PATH}.was_closed`);
|
||||
}
|
||||
break;
|
||||
|
||||
case "lock":
|
||||
if (state === "unlocked") {
|
||||
return localize(`${LOGBOOK_LOCALIZE_PATH}.was_unlocked`);
|
||||
return hass.localize(`${LOGBOOK_LOCALIZE_PATH}.was_unlocked`);
|
||||
}
|
||||
if (state === "locked") {
|
||||
return localize(`${LOGBOOK_LOCALIZE_PATH}.was_locked`);
|
||||
return hass.localize(`${LOGBOOK_LOCALIZE_PATH}.was_locked`);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (state === BINARY_STATE_ON) {
|
||||
return localize(`${LOGBOOK_LOCALIZE_PATH}.turned_on`);
|
||||
return hass.localize(`${LOGBOOK_LOCALIZE_PATH}.turned_on`);
|
||||
}
|
||||
|
||||
if (state === BINARY_STATE_OFF) {
|
||||
return localize(`${LOGBOOK_LOCALIZE_PATH}.turned_off`);
|
||||
return hass.localize(`${LOGBOOK_LOCALIZE_PATH}.turned_off`);
|
||||
}
|
||||
|
||||
if (UNAVAILABLE_STATES.includes(state)) {
|
||||
return localize(`${LOGBOOK_LOCALIZE_PATH}.became_unavailable`);
|
||||
return hass.localize(`${LOGBOOK_LOCALIZE_PATH}.became_unavailable`);
|
||||
}
|
||||
|
||||
return hass.localize(
|
||||
`${LOGBOOK_LOCALIZE_PATH}.changed_to_state`,
|
||||
"state",
|
||||
stateObj
|
||||
? computeStateDisplay(localize, stateObj, hass.locale, state)
|
||||
? computeStateDisplay(hass.localize, stateObj, hass.locale, state)
|
||||
: state
|
||||
);
|
||||
};
|
||||
|
||||
+2
-4
@@ -21,9 +21,7 @@ export interface ScriptEntity extends HassEntityBase {
|
||||
};
|
||||
}
|
||||
|
||||
export type ScriptConfig = ManualScriptConfig | BlueprintScriptConfig;
|
||||
|
||||
export interface ManualScriptConfig {
|
||||
export interface ScriptConfig {
|
||||
alias: string;
|
||||
sequence: Action | Action[];
|
||||
icon?: string;
|
||||
@@ -31,7 +29,7 @@ export interface ManualScriptConfig {
|
||||
max?: number;
|
||||
}
|
||||
|
||||
export interface BlueprintScriptConfig extends ManualScriptConfig {
|
||||
export interface BlueprintScriptConfig extends ScriptConfig {
|
||||
use_blueprint: { path: string; input?: BlueprintInput };
|
||||
}
|
||||
|
||||
|
||||
@@ -37,8 +37,7 @@ export type TranslationCategory =
|
||||
| "options"
|
||||
| "device_automation"
|
||||
| "mfa_setup"
|
||||
| "system_health"
|
||||
| "device_class";
|
||||
| "system_health";
|
||||
|
||||
export const fetchTranslationPreferences = (hass: HomeAssistant) =>
|
||||
fetchFrontendUserData(hass.connection, "language");
|
||||
|
||||
@@ -0,0 +1,78 @@
|
||||
import { LitElement, TemplateResult, html, css } from "lit";
|
||||
import { property } from "lit/decorators";
|
||||
import { enableWrite } from "../common/auth/token_storage";
|
||||
import { HomeAssistant } from "../types";
|
||||
import "../components/ha-card";
|
||||
import type { HaCard } from "../components/ha-card";
|
||||
import "@material/mwc-button/mwc-button";
|
||||
|
||||
class HaStoreAuth extends LitElement {
|
||||
@property({ attribute: false }) public hass!: HomeAssistant;
|
||||
|
||||
protected render(): TemplateResult {
|
||||
return html`
|
||||
<ha-card>
|
||||
<div class="card-content">
|
||||
${this.hass.localize("ui.auth_store.ask")}
|
||||
</div>
|
||||
<div class="card-actions">
|
||||
<mwc-button @click=${this._dismiss}>
|
||||
${this.hass.localize("ui.auth_store.decline")}
|
||||
</mwc-button>
|
||||
<mwc-button raised @click=${this._save}>
|
||||
${this.hass.localize("ui.auth_store.confirm")}
|
||||
</mwc-button>
|
||||
</div>
|
||||
</ha-card>
|
||||
`;
|
||||
}
|
||||
|
||||
firstUpdated() {
|
||||
this.classList.toggle("small", window.innerWidth < 600);
|
||||
}
|
||||
|
||||
private _save(): void {
|
||||
enableWrite();
|
||||
this._dismiss();
|
||||
}
|
||||
|
||||
private _dismiss(): void {
|
||||
const card = this.shadowRoot!.querySelector("ha-card") as HaCard;
|
||||
card.style.bottom = `-${card.offsetHeight + 8}px`;
|
||||
setTimeout(() => this.parentNode!.removeChild(this), 300);
|
||||
}
|
||||
|
||||
static get styles() {
|
||||
return css`
|
||||
ha-card {
|
||||
position: fixed;
|
||||
padding: 8px 0;
|
||||
bottom: 16px;
|
||||
right: 16px;
|
||||
transition: bottom 0.25s;
|
||||
--ha-card-box-shadow: 0px 3px 5px -1px rgba(0, 0, 0, 0.2),
|
||||
0px 6px 10px 0px rgba(0, 0, 0, 0.14),
|
||||
0px 1px 18px 0px rgba(0, 0, 0, 0.12);
|
||||
}
|
||||
|
||||
.card-actions {
|
||||
text-align: right;
|
||||
border-top: 0;
|
||||
}
|
||||
|
||||
:host(.small) ha-card {
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
}
|
||||
`;
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define("ha-store-auth-card", HaStoreAuth);
|
||||
|
||||
declare global {
|
||||
interface HTMLElementTagNameMap {
|
||||
"ha-store-auth-card": HaStoreAuth;
|
||||
}
|
||||
}
|
||||
@@ -1,19 +1,12 @@
|
||||
import { css, html, LitElement, PropertyValues, TemplateResult } from "lit";
|
||||
import { html, LitElement, PropertyValues, TemplateResult } from "lit";
|
||||
import { customElement, property, state } from "lit/decorators";
|
||||
import { isComponentLoaded } from "../../common/config/is_component_loaded";
|
||||
import { fireEvent } from "../../common/dom/fire_event";
|
||||
import { throttle } from "../../common/util/throttle";
|
||||
import "../../components/chart/state-history-charts";
|
||||
import { getRecentWithCache } from "../../data/cached-history";
|
||||
import { HistoryResult } from "../../data/history";
|
||||
import { HomeAssistant } from "../../types";
|
||||
|
||||
declare global {
|
||||
interface HASSDomEvents {
|
||||
closed: undefined;
|
||||
}
|
||||
}
|
||||
|
||||
@customElement("ha-more-info-history")
|
||||
export class MoreInfoHistory extends LitElement {
|
||||
@property({ attribute: false }) public hass!: HomeAssistant;
|
||||
@@ -31,26 +24,14 @@ export class MoreInfoHistory extends LitElement {
|
||||
return html``;
|
||||
}
|
||||
|
||||
const href = "/history?entity_id=" + this.entityId;
|
||||
|
||||
return html`${isComponentLoaded(this.hass, "history")
|
||||
? html` <div class="header">
|
||||
<div class="title">
|
||||
${this.hass.localize("ui.dialogs.more_info_control.history")}
|
||||
</div>
|
||||
<a href=${href} @click=${this._close}
|
||||
>${this.hass.localize(
|
||||
"ui.dialogs.more_info_control.show_more"
|
||||
)}</a
|
||||
>
|
||||
</div>
|
||||
<state-history-charts
|
||||
up-to-now
|
||||
.hass=${this.hass}
|
||||
.historyData=${this._stateHistory}
|
||||
.isLoadingData=${!this._stateHistory}
|
||||
></state-history-charts>`
|
||||
: ""}`;
|
||||
? html`<state-history-charts
|
||||
up-to-now
|
||||
.hass=${this.hass}
|
||||
.historyData=${this._stateHistory}
|
||||
.isLoadingData=${!this._stateHistory}
|
||||
></state-history-charts>`
|
||||
: ""} `;
|
||||
}
|
||||
|
||||
protected updated(changedProps: PropertyValues): void {
|
||||
@@ -97,38 +78,6 @@ export class MoreInfoHistory extends LitElement {
|
||||
this.hass!.language
|
||||
);
|
||||
}
|
||||
|
||||
private _close(): void {
|
||||
setTimeout(() => fireEvent(this, "closed"), 500);
|
||||
}
|
||||
|
||||
static get styles() {
|
||||
return [
|
||||
css`
|
||||
.header {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
.header > a,
|
||||
a:visited {
|
||||
color: var(--primary-color);
|
||||
}
|
||||
.title {
|
||||
font-family: var(--paper-font-title_-_font-family);
|
||||
-webkit-font-smoothing: var(
|
||||
--paper-font-title_-_-webkit-font-smoothing
|
||||
);
|
||||
font-size: var(--paper-font-subhead_-_font-size);
|
||||
font-weight: var(--paper-font-title_-_font-weight);
|
||||
letter-spacing: var(--paper-font-title_-_letter-spacing);
|
||||
line-height: var(--paper-font-title_-_line-height);
|
||||
}
|
||||
`,
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
declare global {
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
import { css, html, LitElement, PropertyValues, TemplateResult } from "lit";
|
||||
import { customElement, property, state } from "lit/decorators";
|
||||
import { isComponentLoaded } from "../../common/config/is_component_loaded";
|
||||
import { fireEvent } from "../../common/dom/fire_event";
|
||||
import { computeStateDomain } from "../../common/entity/compute_state_domain";
|
||||
import { throttle } from "../../common/util/throttle";
|
||||
import "../../components/ha-circular-progress";
|
||||
import { fetchUsers } from "../../data/user";
|
||||
import { getLogbookData, LogbookEntry } from "../../data/logbook";
|
||||
import { loadTraceContexts, TraceContexts } from "../../data/trace";
|
||||
import { fetchUsers } from "../../data/user";
|
||||
import "../../panels/logbook/ha-logbook";
|
||||
import { haStyle } from "../../resources/styles";
|
||||
import { HomeAssistant } from "../../types";
|
||||
import { closeDialog } from "../make-dialog-manager";
|
||||
|
||||
@customElement("ha-more-info-logbook")
|
||||
export class MoreInfoLogbook extends LitElement {
|
||||
@@ -44,8 +44,6 @@ export class MoreInfoLogbook extends LitElement {
|
||||
return html``;
|
||||
}
|
||||
|
||||
const href = "/logbook?entity_id=" + this.entityId;
|
||||
|
||||
return html`
|
||||
${isComponentLoaded(this.hass, "logbook")
|
||||
? this._error
|
||||
@@ -63,16 +61,6 @@ export class MoreInfoLogbook extends LitElement {
|
||||
`
|
||||
: this._logbookEntries.length
|
||||
? html`
|
||||
<div class="header">
|
||||
<div class="title">
|
||||
${this.hass.localize("ui.dialogs.more_info_control.logbook")}
|
||||
</div>
|
||||
<a href=${href} @click=${this._close}
|
||||
>${this.hass.localize(
|
||||
"ui.dialogs.more_info_control.show_more"
|
||||
)}</a
|
||||
>
|
||||
</div>
|
||||
<ha-logbook
|
||||
narrow
|
||||
no-icon
|
||||
@@ -93,6 +81,11 @@ export class MoreInfoLogbook extends LitElement {
|
||||
|
||||
protected firstUpdated(): void {
|
||||
this._fetchUserPromise = this._fetchUserNames();
|
||||
this.addEventListener("click", (ev) => {
|
||||
if ((ev.composedPath()[0] as HTMLElement).tagName === "A") {
|
||||
setTimeout(() => closeDialog("ha-more-info-dialog"), 500);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
protected updated(changedProps: PropertyValues): void {
|
||||
@@ -189,10 +182,6 @@ export class MoreInfoLogbook extends LitElement {
|
||||
this._userIdToName = userIdToName;
|
||||
}
|
||||
|
||||
private _close(): void {
|
||||
setTimeout(() => fireEvent(this, "closed"), 500);
|
||||
}
|
||||
|
||||
static get styles() {
|
||||
return [
|
||||
haStyle,
|
||||
@@ -214,27 +203,6 @@ export class MoreInfoLogbook extends LitElement {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
}
|
||||
.header {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
.header > a,
|
||||
a:visited {
|
||||
color: var(--primary-color);
|
||||
}
|
||||
.title {
|
||||
font-family: var(--paper-font-title_-_font-family);
|
||||
-webkit-font-smoothing: var(
|
||||
--paper-font-title_-_-webkit-font-smoothing
|
||||
);
|
||||
font-size: var(--paper-font-subhead_-_font-size);
|
||||
font-weight: var(--paper-font-title_-_font-weight);
|
||||
letter-spacing: var(--paper-font-title_-_letter-spacing);
|
||||
line-height: var(--paper-font-title_-_line-height);
|
||||
}
|
||||
`,
|
||||
];
|
||||
}
|
||||
|
||||
@@ -269,23 +269,15 @@ export class QuickBar extends LitElement {
|
||||
class="command-item"
|
||||
hasMeta
|
||||
>
|
||||
<span>
|
||||
<span class="command-entry">
|
||||
<ha-chip
|
||||
.label=${item.categoryText}
|
||||
hasIcon
|
||||
.leadingIcon=${item.iconPath}
|
||||
class="command-category ${item.categoryKey}"
|
||||
>
|
||||
${item.iconPath
|
||||
? html`<ha-svg-icon
|
||||
.path=${item.iconPath}
|
||||
slot="icon"
|
||||
></ha-svg-icon>`
|
||||
: ""}
|
||||
${item.categoryText}</ha-chip
|
||||
>
|
||||
</ha-chip>
|
||||
${item.primaryText}
|
||||
</span>
|
||||
|
||||
<span class="command-text">${item.primaryText}</span>
|
||||
</mwc-list-item>
|
||||
`;
|
||||
}
|
||||
@@ -607,6 +599,10 @@ export class QuickBar extends LitElement {
|
||||
}
|
||||
}
|
||||
|
||||
ha-chip {
|
||||
margin-right: 8px;
|
||||
}
|
||||
|
||||
ha-icon.entity,
|
||||
ha-svg-icon.entity {
|
||||
margin-left: 20px;
|
||||
@@ -623,7 +619,6 @@ export class QuickBar extends LitElement {
|
||||
}
|
||||
|
||||
.command-category {
|
||||
--ha-chip-icon-color: #585858;
|
||||
--ha-chip-text-color: #212121;
|
||||
}
|
||||
|
||||
@@ -639,8 +634,9 @@ export class QuickBar extends LitElement {
|
||||
--ha-chip-background-color: var(--warning-color);
|
||||
}
|
||||
|
||||
span.command-text {
|
||||
margin-left: 8px;
|
||||
span.command-entry {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
mwc-list-item {
|
||||
|
||||
@@ -464,7 +464,7 @@ export class HaAutomationEditor extends KeyboardShortcutMixin(LitElement) {
|
||||
) {
|
||||
return;
|
||||
}
|
||||
// Wait for dialog to complete closing
|
||||
// Wait for dialog to complate closing
|
||||
await new Promise((resolve) => setTimeout(resolve, 0));
|
||||
}
|
||||
showAutomationEditor({
|
||||
|
||||
@@ -4,12 +4,12 @@ import {
|
||||
mdiInformationOutline,
|
||||
mdiPencil,
|
||||
mdiPencilOff,
|
||||
mdiPlayCircleOutline,
|
||||
mdiPlus,
|
||||
} from "@mdi/js";
|
||||
import "@polymer/paper-tooltip/paper-tooltip";
|
||||
import { CSSResultGroup, html, LitElement, TemplateResult } from "lit";
|
||||
import { customElement, property, state } from "lit/decorators";
|
||||
import { ifDefined } from "lit/directives/if-defined";
|
||||
import memoizeOne from "memoize-one";
|
||||
import { isComponentLoaded } from "../../../common/config/is_component_loaded";
|
||||
import { formatDateTime } from "../../../common/datetime/format_date_time";
|
||||
@@ -22,7 +22,6 @@ import "../../../components/ha-button-related-filter-menu";
|
||||
import "../../../components/ha-fab";
|
||||
import "../../../components/ha-icon-button";
|
||||
import "../../../components/ha-svg-icon";
|
||||
import "../../../components/ha-icon-overflow-menu";
|
||||
import {
|
||||
AutomationEntity,
|
||||
triggerAutomationActions,
|
||||
@@ -136,7 +135,7 @@ class HaAutomationPicker extends LitElement {
|
||||
template: (_info, automation: any) => html`
|
||||
<mwc-button
|
||||
.automation=${automation}
|
||||
@click=${this._triggerRunActions}
|
||||
@click=${this._runActions}
|
||||
.disabled=${UNAVAILABLE_STATES.includes(automation.state)}
|
||||
>
|
||||
${this.hass.localize("ui.card.automation.trigger")}
|
||||
@@ -144,73 +143,78 @@ class HaAutomationPicker extends LitElement {
|
||||
`,
|
||||
};
|
||||
}
|
||||
columns.actions = {
|
||||
columns.info = {
|
||||
title: "",
|
||||
type: "overflow-menu",
|
||||
type: "icon-button",
|
||||
template: (_info, automation) => html`
|
||||
<ha-icon-button
|
||||
.automation=${automation}
|
||||
@click=${this._showInfo}
|
||||
.label=${this.hass.localize(
|
||||
"ui.panel.config.automation.picker.show_info_automation"
|
||||
)}
|
||||
.path=${mdiInformationOutline}
|
||||
></ha-icon-button>
|
||||
`,
|
||||
};
|
||||
columns.trace = {
|
||||
title: "",
|
||||
type: "icon-button",
|
||||
template: (_info, automation: any) => html`
|
||||
<ha-icon-overflow-menu
|
||||
.hass=${this.hass}
|
||||
.narrow=${this.narrow}
|
||||
.items=${[
|
||||
// Info Button
|
||||
{
|
||||
path: mdiInformationOutline,
|
||||
label: this.hass.localize(
|
||||
"ui.panel.config.automation.picker.show_info_automation"
|
||||
),
|
||||
action: () => this._showInfo(automation),
|
||||
},
|
||||
// Trigger Button
|
||||
{
|
||||
path: mdiPlayCircleOutline,
|
||||
label: this.hass.localize("ui.card.automation.trigger"),
|
||||
narrowOnly: true,
|
||||
action: () => this._runActions(automation),
|
||||
},
|
||||
// Trace Button
|
||||
{
|
||||
path: mdiHistory,
|
||||
disabled: !automation.attributes.id,
|
||||
label: this.hass.localize(
|
||||
"ui.panel.config.automation.picker.dev_automation"
|
||||
),
|
||||
tooltip: !automation.attributes.id
|
||||
? this.hass.localize(
|
||||
"ui.panel.config.automation.picker.dev_only_editable"
|
||||
)
|
||||
: "",
|
||||
action: () => {
|
||||
if (automation.attributes.id) {
|
||||
navigate(
|
||||
`/config/automation/trace/${automation.attributes.id}`
|
||||
);
|
||||
}
|
||||
},
|
||||
},
|
||||
// Edit Button
|
||||
{
|
||||
path: automation.attributes.id ? mdiPencil : mdiPencilOff,
|
||||
disabled: !automation.attributes.id,
|
||||
label: this.hass.localize(
|
||||
"ui.panel.config.automation.picker.edit_automation"
|
||||
),
|
||||
tooltip: !automation.attributes.id
|
||||
? this.hass.localize(
|
||||
"ui.panel.config.automation.picker.dev_only_editable"
|
||||
)
|
||||
: "",
|
||||
action: () => {
|
||||
if (automation.attributes.id) {
|
||||
navigate(
|
||||
`/config/automation/edit/${automation.attributes.id}`
|
||||
);
|
||||
}
|
||||
},
|
||||
},
|
||||
]}
|
||||
style="color: var(--secondary-text-color)"
|
||||
<a
|
||||
href=${ifDefined(
|
||||
automation.attributes.id
|
||||
? `/config/automation/trace/${automation.attributes.id}`
|
||||
: undefined
|
||||
)}
|
||||
>
|
||||
</ha-icon-overflow-menu>
|
||||
<ha-icon-button
|
||||
.label=${this.hass.localize(
|
||||
"ui.panel.config.automation.picker.dev_automation"
|
||||
)}
|
||||
.path=${mdiHistory}
|
||||
.disabled=${!automation.attributes.id}
|
||||
></ha-icon-button>
|
||||
</a>
|
||||
${!automation.attributes.id
|
||||
? html`
|
||||
<paper-tooltip animation-delay="0" position="left">
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.automation.picker.dev_only_editable"
|
||||
)}
|
||||
</paper-tooltip>
|
||||
`
|
||||
: ""}
|
||||
`,
|
||||
};
|
||||
columns.edit = {
|
||||
title: "",
|
||||
type: "icon-button",
|
||||
template: (_info, automation: any) => html`
|
||||
<a
|
||||
href=${ifDefined(
|
||||
automation.attributes.id
|
||||
? `/config/automation/edit/${automation.attributes.id}`
|
||||
: undefined
|
||||
)}
|
||||
>
|
||||
<ha-icon-button
|
||||
.disabled=${!automation.attributes.id}
|
||||
.label=${this.hass.localize(
|
||||
"ui.panel.config.automation.picker.edit_automation"
|
||||
)}
|
||||
.path=${automation.attributes.id ? mdiPencil : mdiPencilOff}
|
||||
></ha-icon-button>
|
||||
</a>
|
||||
${!automation.attributes.id
|
||||
? html`
|
||||
<paper-tooltip animation-delay="0" position="left">
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.automation.picker.only_editable"
|
||||
)}
|
||||
</paper-tooltip>
|
||||
`
|
||||
: ""}
|
||||
`,
|
||||
};
|
||||
return columns;
|
||||
@@ -281,8 +285,9 @@ class HaAutomationPicker extends LitElement {
|
||||
this._filterValue = undefined;
|
||||
}
|
||||
|
||||
private _showInfo(automation: AutomationEntity) {
|
||||
const entityId = automation.entity_id;
|
||||
private _showInfo(ev) {
|
||||
ev.stopPropagation();
|
||||
const entityId = ev.currentTarget.automation.entity_id;
|
||||
fireEvent(this, "hass-more-info", { entityId });
|
||||
}
|
||||
|
||||
@@ -306,12 +311,9 @@ class HaAutomationPicker extends LitElement {
|
||||
});
|
||||
}
|
||||
|
||||
private _triggerRunActions = (ev) => {
|
||||
this._runActions(ev.currentTarget.automation);
|
||||
};
|
||||
|
||||
private _runActions = (automation: AutomationEntity) => {
|
||||
triggerAutomationActions(this.hass, automation.entity_id);
|
||||
private _runActions = (ev) => {
|
||||
const entityId = ev.currentTarget.automation.entity_id;
|
||||
triggerAutomationActions(this.hass, entityId);
|
||||
};
|
||||
|
||||
private _createNew() {
|
||||
|
||||
@@ -29,7 +29,6 @@ import {
|
||||
Blueprints,
|
||||
deleteBlueprint,
|
||||
} from "../../../data/blueprint";
|
||||
import { showScriptEditor } from "../../../data/script";
|
||||
import {
|
||||
showAlertDialog,
|
||||
showConfirmationDialog,
|
||||
@@ -53,12 +52,6 @@ const createNewFunctions = {
|
||||
use_blueprint: { path: blueprintMeta.path },
|
||||
});
|
||||
},
|
||||
script: (blueprintMeta: BlueprintMetaDataPath) => {
|
||||
showScriptEditor({
|
||||
alias: blueprintMeta.name,
|
||||
use_blueprint: { path: blueprintMeta.path },
|
||||
});
|
||||
},
|
||||
};
|
||||
|
||||
@customElement("ha-blueprint-overview")
|
||||
@@ -69,38 +62,27 @@ class HaBlueprintOverview extends LitElement {
|
||||
|
||||
@property({ type: Boolean }) public narrow!: boolean;
|
||||
|
||||
@property({ attribute: false }) public route!: Route;
|
||||
@property() public route!: Route;
|
||||
|
||||
@property({ attribute: false }) public blueprints!: Record<
|
||||
string,
|
||||
Blueprints
|
||||
>;
|
||||
@property() public blueprints!: Blueprints;
|
||||
|
||||
private _processedBlueprints = memoizeOne(
|
||||
(blueprints: Record<string, Blueprints>) => {
|
||||
const result: any[] = [];
|
||||
Object.entries(blueprints).forEach(([type, typeBlueprints]) =>
|
||||
Object.entries(typeBlueprints).forEach(([path, blueprint]) => {
|
||||
if ("error" in blueprint) {
|
||||
result.push({
|
||||
name: blueprint.error,
|
||||
type,
|
||||
error: true,
|
||||
path,
|
||||
});
|
||||
} else {
|
||||
result.push({
|
||||
...blueprint.metadata,
|
||||
type,
|
||||
error: false,
|
||||
path,
|
||||
});
|
||||
}
|
||||
})
|
||||
);
|
||||
return result;
|
||||
}
|
||||
);
|
||||
private _processedBlueprints = memoizeOne((blueprints: Blueprints) => {
|
||||
const result = Object.entries(blueprints).map(([path, blueprint]) => {
|
||||
if ("error" in blueprint) {
|
||||
return {
|
||||
name: blueprint.error,
|
||||
error: true,
|
||||
path,
|
||||
};
|
||||
}
|
||||
return {
|
||||
...blueprint.metadata,
|
||||
error: false,
|
||||
path,
|
||||
};
|
||||
});
|
||||
return result;
|
||||
});
|
||||
|
||||
private _columns = memoizeOne(
|
||||
(narrow, _language): DataTableColumnContainer => ({
|
||||
@@ -120,20 +102,6 @@ class HaBlueprintOverview extends LitElement {
|
||||
`
|
||||
: undefined,
|
||||
},
|
||||
type: {
|
||||
title: this.hass.localize(
|
||||
"ui.panel.config.blueprint.overview.headers.type"
|
||||
),
|
||||
template: (type: string) =>
|
||||
html`${this.hass.localize(
|
||||
`ui.panel.config.blueprint.overview.types.${type}`
|
||||
)}`,
|
||||
sortable: true,
|
||||
filterable: true,
|
||||
hidden: narrow,
|
||||
direction: "asc",
|
||||
width: "10%",
|
||||
},
|
||||
path: {
|
||||
title: this.hass.localize(
|
||||
"ui.panel.config.blueprint.overview.headers.file_name"
|
||||
@@ -146,27 +114,25 @@ class HaBlueprintOverview extends LitElement {
|
||||
},
|
||||
create: {
|
||||
title: "",
|
||||
width: narrow ? undefined : "20%",
|
||||
type: narrow ? "icon-button" : undefined,
|
||||
template: (_, blueprint: any) =>
|
||||
blueprint.error
|
||||
? ""
|
||||
: narrow
|
||||
? html`<ha-icon-button
|
||||
? html` <ha-icon-button
|
||||
.blueprint=${blueprint}
|
||||
.label=${this.hass.localize(
|
||||
`ui.panel.config.blueprint.overview.create_${blueprint.domain}`
|
||||
"ui.panel.config.blueprint.overview.use_blueprint"
|
||||
)}
|
||||
@click=${this._createNew}
|
||||
.path=${mdiRobot}
|
||||
>
|
||||
</ha-icon-button>`
|
||||
@click=${this._createNew}
|
||||
></ha-icon-button>`
|
||||
: html`<mwc-button
|
||||
.blueprint=${blueprint}
|
||||
@click=${this._createNew}
|
||||
>
|
||||
${this.hass.localize(
|
||||
`ui.panel.config.blueprint.overview.create_${blueprint.domain}`
|
||||
"ui.panel.config.blueprint.overview.use_blueprint"
|
||||
)}
|
||||
</mwc-button>`,
|
||||
},
|
||||
|
||||
@@ -25,7 +25,7 @@ class HaConfigBlueprint extends HassRouterPage {
|
||||
|
||||
@property() public showAdvanced!: boolean;
|
||||
|
||||
@property() public blueprints: Record<string, Blueprints> = {};
|
||||
@property() public blueprints: Blueprints = {};
|
||||
|
||||
protected routerOptions: RouterOptions = {
|
||||
defaultPage: "dashboard",
|
||||
@@ -41,11 +41,7 @@ class HaConfigBlueprint extends HassRouterPage {
|
||||
};
|
||||
|
||||
private async _getBlueprints() {
|
||||
const [automation, script] = await Promise.all([
|
||||
fetchBlueprints(this.hass, "automation"),
|
||||
fetchBlueprints(this.hass, "script"),
|
||||
]);
|
||||
this.blueprints = { automation, script };
|
||||
this.blueprints = await fetchBlueprints(this.hass, "automation");
|
||||
}
|
||||
|
||||
protected firstUpdated(changedProps) {
|
||||
|
||||
@@ -57,9 +57,9 @@ export abstract class HaDeviceAutomationCard<
|
||||
<div class="content">
|
||||
<ha-chip-set
|
||||
@chip-clicked=${this._handleAutomationClicked}
|
||||
.items=${this.automations.map((automation) =>
|
||||
this._localizeDeviceAutomation(this.hass, automation)
|
||||
)}
|
||||
.items=${this.automations.map((automation) => ({
|
||||
label: this._localizeDeviceAutomation(this.hass, automation),
|
||||
}))}
|
||||
>
|
||||
</ha-chip-set>
|
||||
</div>
|
||||
|
||||
@@ -105,8 +105,14 @@ export class HaDeviceEntitiesCard extends LitElement {
|
||||
</div>
|
||||
`
|
||||
: html`
|
||||
<div class="empty card-content">
|
||||
${this.hass.localize("ui.panel.config.devices.entities.none")}
|
||||
<div class="config-entry-row">
|
||||
<paper-item-body two-line>
|
||||
<div>
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.devices.entities.none"
|
||||
)}
|
||||
</div>
|
||||
</paper-item-body>
|
||||
</div>
|
||||
`}
|
||||
</ha-card>
|
||||
@@ -181,8 +187,7 @@ export class HaDeviceEntitiesCard extends LitElement {
|
||||
this.hass,
|
||||
this.entities
|
||||
.filter((entity) => !entity.disabled_by)
|
||||
.map((entity) => entity.entity_id),
|
||||
this.deviceName
|
||||
.map((entity) => entity.entity_id)
|
||||
);
|
||||
}
|
||||
|
||||
@@ -222,9 +227,6 @@ export class HaDeviceEntitiesCard extends LitElement {
|
||||
.name {
|
||||
font-size: 14px;
|
||||
}
|
||||
.empty {
|
||||
text-align: center;
|
||||
}
|
||||
button.show-more {
|
||||
color: var(--primary-color);
|
||||
text-align: left;
|
||||
|
||||
@@ -52,7 +52,6 @@ import {
|
||||
loadDeviceRegistryDetailDialog,
|
||||
showDeviceRegistryDetailDialog,
|
||||
} from "./device-registry-detail/show-dialog-device-registry-detail";
|
||||
import { computeDomain } from "../../../common/entity/compute_domain";
|
||||
|
||||
export interface EntityRegistryStateEntry extends EntityRegistryEntry {
|
||||
stateName?: string | null;
|
||||
@@ -118,19 +117,14 @@ export class HaConfigDevicePage extends LitElement {
|
||||
|
||||
private _entitiesByCategory = memoizeOne(
|
||||
(entities: EntityRegistryEntry[]) => {
|
||||
const result = groupBy(entities, (entry) =>
|
||||
entry.entity_category
|
||||
? entry.entity_category
|
||||
: ["sensor", "binary_sensor"].includes(computeDomain(entry.entity_id))
|
||||
? "sensor"
|
||||
: "control"
|
||||
const result = groupBy(
|
||||
entities,
|
||||
(entry) => entry.entity_category || "state"
|
||||
) as Record<
|
||||
| "control"
|
||||
| "sensor"
|
||||
| NonNullable<EntityRegistryEntry["entity_category"]>,
|
||||
"state" | NonNullable<EntityRegistryEntry["entity_category"]>,
|
||||
EntityRegistryStateEntry[]
|
||||
>;
|
||||
for (const key of ["control", "sensor", "diagnostic", "config"]) {
|
||||
for (const key of ["state", "diagnostic", "config"]) {
|
||||
if (!(key in result)) {
|
||||
result[key] = [];
|
||||
}
|
||||
@@ -201,13 +195,6 @@ export class HaConfigDevicePage extends LitElement {
|
||||
: undefined;
|
||||
const area = this._computeArea(this.areas, device);
|
||||
|
||||
const configurationUrlIsHomeAssistant =
|
||||
device.configuration_url?.startsWith("homeassistant://") || false;
|
||||
|
||||
const configurationUrl = configurationUrlIsHomeAssistant
|
||||
? device.configuration_url!.replace("homeassistant://", "/")
|
||||
: device.configuration_url;
|
||||
|
||||
return html`
|
||||
<hass-tabs-subpage
|
||||
.hass=${this.hass}
|
||||
@@ -329,15 +316,13 @@ export class HaConfigDevicePage extends LitElement {
|
||||
: html``
|
||||
}
|
||||
${
|
||||
configurationUrl
|
||||
device.configuration_url
|
||||
? html`
|
||||
<div class="card-actions" slot="actions">
|
||||
<a
|
||||
href=${configurationUrl}
|
||||
href=${device.configuration_url}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
.target=${configurationUrlIsHomeAssistant
|
||||
? "_self"
|
||||
: "_blank"}
|
||||
>
|
||||
<mwc-button>
|
||||
${this.hass.localize(
|
||||
@@ -357,13 +342,11 @@ export class HaConfigDevicePage extends LitElement {
|
||||
}
|
||||
${this._renderIntegrationInfo(device, integrations)}
|
||||
</ha-device-info-card>
|
||||
</div>
|
||||
<div class="column">
|
||||
${["control", "sensor", "config", "diagnostic"].map((category) =>
|
||||
// Make sure we render controls if no other cards will be rendered
|
||||
entitiesByCategory[category].length > 0 ||
|
||||
(entities.length === 0 && category === "control")
|
||||
? html`
|
||||
|
||||
${["state", "config", "diagnostic"].map((category) =>
|
||||
!entitiesByCategory[category].length
|
||||
? ""
|
||||
: html`
|
||||
<ha-device-entities-card
|
||||
.hass=${this.hass}
|
||||
.header=${this.hass.localize(
|
||||
@@ -375,10 +358,10 @@ export class HaConfigDevicePage extends LitElement {
|
||||
>
|
||||
</ha-device-entities-card>
|
||||
`
|
||||
: ""
|
||||
)}
|
||||
|
||||
</div>
|
||||
<div class="column">
|
||||
<div class="column">
|
||||
${
|
||||
isComponentLoaded(this.hass, "automation")
|
||||
? html`
|
||||
@@ -451,76 +434,86 @@ export class HaConfigDevicePage extends LitElement {
|
||||
`
|
||||
: ""
|
||||
}
|
||||
</div>
|
||||
<div class="column">
|
||||
${
|
||||
isComponentLoaded(this.hass, "scene") && entities.length
|
||||
? html`
|
||||
<ha-card>
|
||||
<h1 class="card-header">
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.devices.scene.scenes"
|
||||
)}
|
||||
<h1 class="card-header">
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.devices.scene.scenes"
|
||||
)}
|
||||
|
||||
<ha-icon-button
|
||||
@click=${this._createScene}
|
||||
.disabled=${device.disabled_by}
|
||||
.label=${device.disabled_by
|
||||
? this.hass.localize(
|
||||
"ui.panel.config.devices.scene.create_disabled"
|
||||
)
|
||||
: this.hass.localize(
|
||||
"ui.panel.config.devices.scene.create"
|
||||
)}
|
||||
.path=${mdiPlusCircle}
|
||||
></ha-icon-button>
|
||||
</h1>
|
||||
<ha-icon-button @click=${
|
||||
this._createScene
|
||||
} .disabled=${device.disabled_by}
|
||||
.label=${
|
||||
device.disabled_by
|
||||
? this.hass.localize(
|
||||
"ui.panel.config.devices.scene.create_disabled"
|
||||
)
|
||||
: this.hass.localize(
|
||||
"ui.panel.config.devices.scene.create"
|
||||
)
|
||||
}
|
||||
.path=${mdiPlusCircle}
|
||||
></ha-icon-button>
|
||||
</h1>
|
||||
|
||||
${this._related?.scene?.length
|
||||
? this._related.scene.map((scene) => {
|
||||
const entityState = this.hass.states[scene];
|
||||
return entityState
|
||||
? html`
|
||||
<div>
|
||||
<a
|
||||
href=${ifDefined(
|
||||
entityState.attributes.id
|
||||
? `/config/scene/edit/${entityState.attributes.id}`
|
||||
: undefined
|
||||
)}
|
||||
>
|
||||
<paper-item
|
||||
.scene=${entityState}
|
||||
.disabled=${!entityState.attributes.id}
|
||||
>
|
||||
<paper-item-body>
|
||||
${computeStateName(entityState)}
|
||||
</paper-item-body>
|
||||
<ha-icon-next></ha-icon-next>
|
||||
</paper-item>
|
||||
</a>
|
||||
${!entityState.attributes.id
|
||||
? html`
|
||||
<paper-tooltip animation-delay="0">
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.devices.cant_edit"
|
||||
)}
|
||||
</paper-tooltip>
|
||||
`
|
||||
: ""}
|
||||
</div>
|
||||
`
|
||||
: "";
|
||||
})
|
||||
: html`
|
||||
<div class="card-content">
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.devices.add_prompt",
|
||||
"name",
|
||||
this.hass.localize(
|
||||
"ui.panel.config.devices.scene.scenes"
|
||||
)
|
||||
)}
|
||||
</div>
|
||||
`}
|
||||
${
|
||||
this._related?.scene?.length
|
||||
? this._related.scene.map((scene) => {
|
||||
const entityState = this.hass.states[scene];
|
||||
return entityState
|
||||
? html`
|
||||
<div>
|
||||
<a
|
||||
href=${ifDefined(
|
||||
entityState.attributes.id
|
||||
? `/config/scene/edit/${entityState.attributes.id}`
|
||||
: undefined
|
||||
)}
|
||||
>
|
||||
<paper-item
|
||||
.scene=${entityState}
|
||||
.disabled=${!entityState.attributes
|
||||
.id}
|
||||
>
|
||||
<paper-item-body>
|
||||
${computeStateName(entityState)}
|
||||
</paper-item-body>
|
||||
<ha-icon-next></ha-icon-next>
|
||||
</paper-item>
|
||||
</a>
|
||||
${!entityState.attributes.id
|
||||
? html`
|
||||
<paper-tooltip
|
||||
animation-delay="0"
|
||||
>
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.devices.cant_edit"
|
||||
)}
|
||||
</paper-tooltip>
|
||||
`
|
||||
: ""}
|
||||
</div>
|
||||
`
|
||||
: "";
|
||||
})
|
||||
: html`
|
||||
<div class="card-content">
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.devices.add_prompt",
|
||||
"name",
|
||||
this.hass.localize(
|
||||
"ui.panel.config.devices.scene.scenes"
|
||||
)
|
||||
)}
|
||||
</div>
|
||||
`
|
||||
}
|
||||
</ha-card>
|
||||
</ha-card>
|
||||
`
|
||||
: ""
|
||||
@@ -580,7 +573,7 @@ export class HaConfigDevicePage extends LitElement {
|
||||
: ""
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</ha-config-section>
|
||||
</hass-tabs-subpage> `;
|
||||
}
|
||||
|
||||
@@ -73,6 +73,7 @@ export class DialogEnergyBatterySettings
|
||||
.label=${this.hass.localize(
|
||||
"ui.panel.config.energy.battery.dialog.energy_into_battery"
|
||||
)}
|
||||
entities-only
|
||||
@value-changed=${this._statisticToChanged}
|
||||
></ha-statistic-picker>
|
||||
|
||||
@@ -84,6 +85,7 @@ export class DialogEnergyBatterySettings
|
||||
.label=${this.hass.localize(
|
||||
"ui.panel.config.energy.battery.dialog.energy_out_of_battery"
|
||||
)}
|
||||
entities-only
|
||||
@value-changed=${this._statisticFromChanged}
|
||||
></ha-statistic-picker>
|
||||
|
||||
|
||||
@@ -74,6 +74,7 @@ export class DialogEnergyDeviceSettings
|
||||
.label=${this.hass.localize(
|
||||
"ui.panel.config.energy.device_consumption.dialog.device_consumption_energy"
|
||||
)}
|
||||
entities-only
|
||||
@value-changed=${this._statisticChanged}
|
||||
></ha-statistic-picker>
|
||||
|
||||
|
||||
@@ -106,6 +106,7 @@ export class DialogEnergyGasSettings
|
||||
? "kWh"
|
||||
: "m³"
|
||||
})`}
|
||||
entities-only
|
||||
@value-changed=${this._statisticChanged}
|
||||
></ha-statistic-picker>
|
||||
|
||||
|
||||
@@ -103,6 +103,7 @@ export class DialogEnergyGridFlowSettings
|
||||
.label=${this.hass.localize(
|
||||
`ui.panel.config.energy.grid.flow_dialog.${this._params.direction}.energy_stat`
|
||||
)}
|
||||
entities-only
|
||||
@value-changed=${this._statisticChanged}
|
||||
></ha-statistic-picker>
|
||||
|
||||
|
||||
@@ -85,6 +85,7 @@ export class DialogEnergySolarSettings
|
||||
.label=${this.hass.localize(
|
||||
"ui.panel.config.energy.solar.dialog.solar_production_energy"
|
||||
)}
|
||||
entities-only
|
||||
@value-changed=${this._statisticChanged}
|
||||
></ha-statistic-picker>
|
||||
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
import { mdiClose, mdiContentCopy } from "@mdi/js";
|
||||
import { mdiClose, mdiContentCopy, mdiPackageVariant } from "@mdi/js";
|
||||
import "@polymer/paper-tooltip/paper-tooltip";
|
||||
import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit";
|
||||
import { property, state } from "lit/decorators";
|
||||
import { fireEvent } from "../../../common/dom/fire_event";
|
||||
import { copyToClipboard } from "../../../common/util/copy-clipboard";
|
||||
import "../../../components/ha-alert";
|
||||
import "../../../components/ha-dialog";
|
||||
import "../../../components/ha-header-bar";
|
||||
import "../../../components/ha-icon-button";
|
||||
@@ -97,11 +96,12 @@ class DialogSystemLogDetail extends LitElement {
|
||||
></ha-icon-button>
|
||||
</ha-header-bar>
|
||||
${this.isCustomIntegration
|
||||
? html`<ha-alert alert-type="warning">
|
||||
? html`<div class="custom">
|
||||
<ha-svg-icon .path=${mdiPackageVariant}></ha-svg-icon>
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.logs.error_from_custom_integration"
|
||||
)}
|
||||
</ha-alert>`
|
||||
</div>`
|
||||
: ""}
|
||||
<div class="contents">
|
||||
<p>
|
||||
@@ -215,9 +215,9 @@ class DialogSystemLogDetail extends LitElement {
|
||||
margin-bottom: 0;
|
||||
font-family: var(--code-font-family, monospace);
|
||||
}
|
||||
ha-alert {
|
||||
display: block;
|
||||
margin: -4px 0;
|
||||
.custom {
|
||||
padding: 8px 16px;
|
||||
background-color: var(--warning-color);
|
||||
}
|
||||
.contents {
|
||||
padding: 16px;
|
||||
|
||||
@@ -1,205 +0,0 @@
|
||||
import "@polymer/paper-input/paper-input";
|
||||
import { css, CSSResultGroup, html, LitElement } from "lit";
|
||||
import { customElement, property, state } from "lit/decorators";
|
||||
import { fireEvent } from "../../../common/dom/fire_event";
|
||||
import "../../../components/ha-blueprint-picker";
|
||||
import "../../../components/ha-card";
|
||||
import "../../../components/ha-circular-progress";
|
||||
import "../../../components/ha-markdown";
|
||||
import "../../../components/ha-selector/ha-selector";
|
||||
import "../../../components/ha-settings-row";
|
||||
|
||||
import {
|
||||
BlueprintOrError,
|
||||
Blueprints,
|
||||
fetchBlueprints,
|
||||
} from "../../../data/blueprint";
|
||||
import { BlueprintScriptConfig } from "../../../data/script";
|
||||
import { haStyle } from "../../../resources/styles";
|
||||
import { HomeAssistant } from "../../../types";
|
||||
import "../ha-config-section";
|
||||
|
||||
@customElement("blueprint-script-editor")
|
||||
export class HaBlueprintScriptEditor extends LitElement {
|
||||
@property({ attribute: false }) public hass!: HomeAssistant;
|
||||
|
||||
@property({ type: Boolean }) public isWide!: boolean;
|
||||
|
||||
@property({ reflect: true, type: Boolean }) public narrow!: boolean;
|
||||
|
||||
@property({ attribute: false }) public config!: BlueprintScriptConfig;
|
||||
|
||||
@state() private _blueprints?: Blueprints;
|
||||
|
||||
protected firstUpdated(changedProps) {
|
||||
super.firstUpdated(changedProps);
|
||||
this._getBlueprints();
|
||||
}
|
||||
|
||||
private get _blueprint(): BlueprintOrError | undefined {
|
||||
if (!this._blueprints) {
|
||||
return undefined;
|
||||
}
|
||||
return this._blueprints[this.config.use_blueprint.path];
|
||||
}
|
||||
|
||||
protected render() {
|
||||
const blueprint = this._blueprint;
|
||||
return html` <ha-config-section vertical .isWide=${this.isWide}>
|
||||
<span slot="header"
|
||||
>${this.hass.localize(
|
||||
"ui.panel.config.automation.editor.blueprint.header"
|
||||
)}</span
|
||||
>
|
||||
<ha-card>
|
||||
<div class="blueprint-picker-container">
|
||||
${this._blueprints
|
||||
? Object.keys(this._blueprints).length
|
||||
? html`
|
||||
<ha-blueprint-picker
|
||||
.hass=${this.hass}
|
||||
.label=${this.hass.localize(
|
||||
"ui.panel.config.automation.editor.blueprint.blueprint_to_use"
|
||||
)}
|
||||
.blueprints=${this._blueprints}
|
||||
.value=${this.config.use_blueprint.path}
|
||||
@value-changed=${this._blueprintChanged}
|
||||
></ha-blueprint-picker>
|
||||
`
|
||||
: this.hass.localize(
|
||||
"ui.panel.config.automation.editor.blueprint.no_blueprints"
|
||||
)
|
||||
: html`<ha-circular-progress active></ha-circular-progress>`}
|
||||
</div>
|
||||
|
||||
${this.config.use_blueprint.path
|
||||
? blueprint && "error" in blueprint
|
||||
? html`<p class="warning padding">
|
||||
There is an error in this Blueprint: ${blueprint.error}
|
||||
</p>`
|
||||
: html`${blueprint?.metadata.description
|
||||
? html`<ha-markdown
|
||||
class="card-content"
|
||||
breaks
|
||||
.content=${blueprint.metadata.description}
|
||||
></ha-markdown>`
|
||||
: ""}
|
||||
${blueprint?.metadata?.input &&
|
||||
Object.keys(blueprint.metadata.input).length
|
||||
? Object.entries(blueprint.metadata.input).map(
|
||||
([key, value]) =>
|
||||
html`<ha-settings-row .narrow=${this.narrow}>
|
||||
<span slot="heading">${value?.name || key}</span>
|
||||
<span slot="description">${value?.description}</span>
|
||||
${value?.selector
|
||||
? html`<ha-selector
|
||||
.hass=${this.hass}
|
||||
.selector=${value.selector}
|
||||
.key=${key}
|
||||
.value=${(this.config.use_blueprint.input &&
|
||||
this.config.use_blueprint.input[key]) ??
|
||||
value?.default}
|
||||
@value-changed=${this._inputChanged}
|
||||
></ha-selector>`
|
||||
: html`<paper-input
|
||||
.key=${key}
|
||||
required
|
||||
.value=${(this.config.use_blueprint.input &&
|
||||
this.config.use_blueprint.input[key]) ??
|
||||
value?.default}
|
||||
@value-changed=${this._inputChanged}
|
||||
no-label-float
|
||||
></paper-input>`}
|
||||
</ha-settings-row>`
|
||||
)
|
||||
: html`<p class="padding">
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.automation.editor.blueprint.no_inputs"
|
||||
)}
|
||||
</p>`}`
|
||||
: ""}
|
||||
</ha-card>
|
||||
</ha-config-section>`;
|
||||
}
|
||||
|
||||
private async _getBlueprints() {
|
||||
this._blueprints = await fetchBlueprints(this.hass, "script");
|
||||
}
|
||||
|
||||
private _blueprintChanged(ev) {
|
||||
ev.stopPropagation();
|
||||
if (this.config.use_blueprint.path === ev.detail.value) {
|
||||
return;
|
||||
}
|
||||
fireEvent(this, "value-changed", {
|
||||
value: {
|
||||
...this.config,
|
||||
use_blueprint: {
|
||||
path: ev.detail.value,
|
||||
},
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
private _inputChanged(ev) {
|
||||
ev.stopPropagation();
|
||||
const target = ev.target as any;
|
||||
const key = target.key;
|
||||
const value = ev.detail.value;
|
||||
if (
|
||||
(this.config.use_blueprint.input &&
|
||||
this.config.use_blueprint.input[key] === value) ||
|
||||
(!this.config.use_blueprint.input && value === "")
|
||||
) {
|
||||
return;
|
||||
}
|
||||
const input = { ...this.config.use_blueprint.input, [key]: value };
|
||||
|
||||
if (value === "" || value === undefined) {
|
||||
delete input[key];
|
||||
}
|
||||
|
||||
fireEvent(this, "value-changed", {
|
||||
value: {
|
||||
...this.config,
|
||||
use_blueprint: {
|
||||
...this.config.use_blueprint,
|
||||
input,
|
||||
},
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
static get styles(): CSSResultGroup {
|
||||
return [
|
||||
haStyle,
|
||||
css`
|
||||
.padding {
|
||||
padding: 16px;
|
||||
}
|
||||
.blueprint-picker-container {
|
||||
padding: 16px;
|
||||
}
|
||||
p {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
ha-settings-row {
|
||||
--paper-time-input-justify-content: flex-end;
|
||||
border-top: 1px solid var(--divider-color);
|
||||
}
|
||||
:host(:not([narrow])) ha-settings-row paper-input {
|
||||
width: 60%;
|
||||
}
|
||||
:host(:not([narrow])) ha-settings-row ha-selector {
|
||||
width: 60%;
|
||||
}
|
||||
`,
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
declare global {
|
||||
interface HTMLElementTagNameMap {
|
||||
"blueprint-script-editor": HaBlueprintScriptEditor;
|
||||
}
|
||||
}
|
||||
@@ -38,7 +38,6 @@ import {
|
||||
Action,
|
||||
deleteScript,
|
||||
getScriptEditorInitData,
|
||||
ManualScriptConfig,
|
||||
MODES,
|
||||
MODES_MAX,
|
||||
ScriptConfig,
|
||||
@@ -56,7 +55,6 @@ import "../automation/action/ha-automation-action";
|
||||
import { HaDeviceAction } from "../automation/action/types/ha-automation-action-device_id";
|
||||
import "../ha-config-section";
|
||||
import { configSections } from "../ha-panel-config";
|
||||
import "./blueprint-script-editor";
|
||||
|
||||
export class HaScriptEditor extends KeyboardShortcutMixin(LitElement) {
|
||||
@property({ attribute: false }) public hass!: HomeAssistant;
|
||||
@@ -238,62 +236,60 @@ export class HaScriptEditor extends KeyboardShortcutMixin(LitElement) {
|
||||
>
|
||||
</paper-input>`
|
||||
: ""}
|
||||
${"use_blueprint" in this._config
|
||||
? ""
|
||||
: html`<p>
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.script.editor.modes.description",
|
||||
"documentation_link",
|
||||
html`<a
|
||||
href=${documentationUrl(
|
||||
this.hass,
|
||||
"/integrations/script/#script-modes"
|
||||
)}
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
>${this.hass.localize(
|
||||
"ui.panel.config.script.editor.modes.documentation"
|
||||
)}</a
|
||||
>`
|
||||
)}
|
||||
</p>
|
||||
<paper-dropdown-menu-light
|
||||
.label=${this.hass.localize(
|
||||
"ui.panel.config.script.editor.modes.label"
|
||||
)}
|
||||
no-animations
|
||||
>
|
||||
<paper-listbox
|
||||
slot="dropdown-content"
|
||||
.selected=${this._config.mode
|
||||
? MODES.indexOf(this._config.mode)
|
||||
: 0}
|
||||
@iron-select=${this._modeChanged}
|
||||
>
|
||||
${MODES.map(
|
||||
(mode) => html`
|
||||
<paper-item .mode=${mode}>
|
||||
${this.hass.localize(
|
||||
`ui.panel.config.script.editor.modes.${mode}`
|
||||
) || mode}
|
||||
</paper-item>
|
||||
`
|
||||
)}
|
||||
</paper-listbox>
|
||||
</paper-dropdown-menu-light>
|
||||
${this._config.mode &&
|
||||
MODES_MAX.includes(this._config.mode)
|
||||
? html`<paper-input
|
||||
.label=${this.hass.localize(
|
||||
`ui.panel.config.script.editor.max.${this._config.mode}`
|
||||
)}
|
||||
type="number"
|
||||
name="max"
|
||||
.value=${this._config.max || "10"}
|
||||
@value-changed=${this._valueChanged}
|
||||
>
|
||||
</paper-input>`
|
||||
: html``} `}
|
||||
<p>
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.script.editor.modes.description",
|
||||
"documentation_link",
|
||||
html`<a
|
||||
href=${documentationUrl(
|
||||
this.hass,
|
||||
"/integrations/script/#script-modes"
|
||||
)}
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
>${this.hass.localize(
|
||||
"ui.panel.config.script.editor.modes.documentation"
|
||||
)}</a
|
||||
>`
|
||||
)}
|
||||
</p>
|
||||
<paper-dropdown-menu-light
|
||||
.label=${this.hass.localize(
|
||||
"ui.panel.config.script.editor.modes.label"
|
||||
)}
|
||||
no-animations
|
||||
>
|
||||
<paper-listbox
|
||||
slot="dropdown-content"
|
||||
.selected=${this._config.mode
|
||||
? MODES.indexOf(this._config.mode)
|
||||
: 0}
|
||||
@iron-select=${this._modeChanged}
|
||||
>
|
||||
${MODES.map(
|
||||
(mode) => html`
|
||||
<paper-item .mode=${mode}>
|
||||
${this.hass.localize(
|
||||
`ui.panel.config.script.editor.modes.${mode}`
|
||||
) || mode}
|
||||
</paper-item>
|
||||
`
|
||||
)}
|
||||
</paper-listbox>
|
||||
</paper-dropdown-menu-light>
|
||||
${this._config.mode &&
|
||||
MODES_MAX.includes(this._config.mode)
|
||||
? html`<paper-input
|
||||
.label=${this.hass.localize(
|
||||
`ui.panel.config.script.editor.max.${this._config.mode}`
|
||||
)}
|
||||
type="number"
|
||||
name="max"
|
||||
.value=${this._config.max || "10"}
|
||||
@value-changed=${this._valueChanged}
|
||||
>
|
||||
</paper-input>`
|
||||
: html``}
|
||||
</div>
|
||||
${this.scriptEntityId
|
||||
? html`
|
||||
@@ -327,48 +323,37 @@ export class HaScriptEditor extends KeyboardShortcutMixin(LitElement) {
|
||||
</ha-card>
|
||||
</ha-config-section>
|
||||
|
||||
${"use_blueprint" in this._config
|
||||
? html`<blueprint-script-editor
|
||||
.hass=${this.hass}
|
||||
.narrow=${this.narrow}
|
||||
.isWide=${this.isWide}
|
||||
.config=${this._config}
|
||||
@value-changed=${this._configChanged}
|
||||
></blueprint-script-editor>`
|
||||
: html`<ha-config-section
|
||||
vertical
|
||||
.isWide=${this.isWide}
|
||||
<ha-config-section vertical .isWide=${this.isWide}>
|
||||
<span slot="header">
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.script.editor.sequence"
|
||||
)}
|
||||
</span>
|
||||
<span slot="introduction">
|
||||
<p>
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.script.editor.sequence_sentence"
|
||||
)}
|
||||
</p>
|
||||
<a
|
||||
href=${documentationUrl(
|
||||
this.hass,
|
||||
"/docs/scripts/"
|
||||
)}
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
>
|
||||
<span slot="header">
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.script.editor.sequence"
|
||||
)}
|
||||
</span>
|
||||
<span slot="introduction">
|
||||
<p>
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.script.editor.sequence_sentence"
|
||||
)}
|
||||
</p>
|
||||
<a
|
||||
href=${documentationUrl(
|
||||
this.hass,
|
||||
"/docs/scripts/"
|
||||
)}
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
>
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.script.editor.link_available_actions"
|
||||
)}
|
||||
</a>
|
||||
</span>
|
||||
<ha-automation-action
|
||||
.actions=${this._config.sequence}
|
||||
@value-changed=${this._sequenceChanged}
|
||||
.hass=${this.hass}
|
||||
></ha-automation-action>
|
||||
</ha-config-section>`}
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.script.editor.link_available_actions"
|
||||
)}
|
||||
</a>
|
||||
</span>
|
||||
<ha-automation-action
|
||||
.actions=${this._config.sequence}
|
||||
@value-changed=${this._sequenceChanged}
|
||||
.hass=${this.hass}
|
||||
></ha-automation-action>
|
||||
</ha-config-section>
|
||||
`
|
||||
: ""}
|
||||
</div>
|
||||
@@ -442,7 +427,7 @@ export class HaScriptEditor extends KeyboardShortcutMixin(LitElement) {
|
||||
(!oldScript || oldScript !== this.scriptEntityId)
|
||||
) {
|
||||
this.hass
|
||||
.callApi<ManualScriptConfig>(
|
||||
.callApi<ScriptConfig>(
|
||||
"GET",
|
||||
`config/script/config/${computeObjectId(this.scriptEntityId)}`
|
||||
)
|
||||
@@ -481,16 +466,11 @@ export class HaScriptEditor extends KeyboardShortcutMixin(LitElement) {
|
||||
) {
|
||||
const initData = getScriptEditorInitData();
|
||||
this._dirty = !!initData;
|
||||
const baseConfig: Partial<ScriptConfig> = {
|
||||
alias: this.hass.localize("ui.panel.config.script.editor.default_name"),
|
||||
};
|
||||
if (!initData || !("use_blueprint" in initData)) {
|
||||
baseConfig.sequence = [{ ...HaDeviceAction.defaultConfig }];
|
||||
}
|
||||
this._config = {
|
||||
...baseConfig,
|
||||
alias: this.hass.localize("ui.panel.config.script.editor.default_name"),
|
||||
sequence: [{ ...HaDeviceAction.defaultConfig }],
|
||||
...initData,
|
||||
} as ScriptConfig;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -568,11 +548,6 @@ export class HaScriptEditor extends KeyboardShortcutMixin(LitElement) {
|
||||
this._dirty = true;
|
||||
}
|
||||
|
||||
private _configChanged(ev) {
|
||||
this._config = ev.detail.value;
|
||||
this._dirty = true;
|
||||
}
|
||||
|
||||
private _sequenceChanged(ev: CustomEvent): void {
|
||||
this._config = { ...this._config!, sequence: ev.detail.value as Action[] };
|
||||
this._errors = undefined;
|
||||
@@ -632,7 +607,7 @@ export class HaScriptEditor extends KeyboardShortcutMixin(LitElement) {
|
||||
) {
|
||||
return;
|
||||
}
|
||||
// Wait for dialog to complete closing
|
||||
// Wait for dialog to complate closing
|
||||
await new Promise((resolve) => setTimeout(resolve, 0));
|
||||
}
|
||||
showScriptEditor({
|
||||
@@ -774,9 +749,3 @@ export class HaScriptEditor extends KeyboardShortcutMixin(LitElement) {
|
||||
}
|
||||
|
||||
customElements.define("ha-script-editor", HaScriptEditor);
|
||||
|
||||
declare global {
|
||||
interface HTMLElementTagNameMap {
|
||||
"ha-script-editor": HaScriptEditor;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -50,21 +50,21 @@ class HaPanelDevStatistics extends LitElement {
|
||||
private _columns = memoizeOne(
|
||||
(localize): DataTableColumnContainer => ({
|
||||
state: {
|
||||
title: "Name",
|
||||
title: "Entity",
|
||||
sortable: true,
|
||||
filterable: true,
|
||||
grows: true,
|
||||
template: (entityState, data: any) =>
|
||||
html`${entityState
|
||||
? computeStateName(entityState)
|
||||
: data.name || data.statistic_id}`,
|
||||
: data.statistic_id}`,
|
||||
},
|
||||
statistic_id: {
|
||||
title: "Statistic id",
|
||||
sortable: true,
|
||||
filterable: true,
|
||||
hidden: this.narrow,
|
||||
width: "20%",
|
||||
width: "30%",
|
||||
},
|
||||
unit_of_measurement: {
|
||||
title: "Unit",
|
||||
@@ -72,12 +72,6 @@ class HaPanelDevStatistics extends LitElement {
|
||||
filterable: true,
|
||||
width: "10%",
|
||||
},
|
||||
source: {
|
||||
title: "Source",
|
||||
sortable: true,
|
||||
filterable: true,
|
||||
width: "10%",
|
||||
},
|
||||
issues: {
|
||||
title: "Issue",
|
||||
sortable: true,
|
||||
@@ -152,7 +146,6 @@ class HaPanelDevStatistics extends LitElement {
|
||||
this._data.push({
|
||||
statistic_id: statisticId,
|
||||
unit_of_measurement: "",
|
||||
source: "",
|
||||
state: this.hass.states[statisticId],
|
||||
issues: issues[statisticId],
|
||||
});
|
||||
|
||||
@@ -12,7 +12,6 @@ import {
|
||||
} from "date-fns";
|
||||
import { css, html, LitElement, PropertyValues } from "lit";
|
||||
import { property, state } from "lit/decorators";
|
||||
import { extractSearchParam } from "../../common/url/search-params";
|
||||
import { computeRTL } from "../../common/util/compute_rtl";
|
||||
import "../../components/chart/state-history-charts";
|
||||
import "../../components/entity/ha-entity-picker";
|
||||
@@ -137,8 +136,6 @@ class HaPanelHistory extends LitElement {
|
||||
[this.hass.localize("ui.components.date-range-picker.ranges.last_week")]:
|
||||
[addDays(weekStart, -7), addDays(weekEnd, -7)],
|
||||
};
|
||||
|
||||
this._entityId = extractSearchParam("entity_id") ?? "";
|
||||
}
|
||||
|
||||
protected updated(changedProps: PropertyValues) {
|
||||
|
||||
@@ -222,7 +222,6 @@ class HaLogbook extends LitElement {
|
||||
}?run_id=${
|
||||
this.traceContexts[item.context_id!].run_id
|
||||
}`}
|
||||
@click=${this._close}
|
||||
>${this.hass.localize(
|
||||
"ui.components.logbook.show_trace"
|
||||
)}</a
|
||||
@@ -255,10 +254,6 @@ class HaLogbook extends LitElement {
|
||||
});
|
||||
}
|
||||
|
||||
private _close(): void {
|
||||
setTimeout(() => fireEvent(this, "closed"), 500);
|
||||
}
|
||||
|
||||
static get styles(): CSSResultGroup {
|
||||
return [
|
||||
haStyle,
|
||||
|
||||
@@ -33,7 +33,6 @@ import "../../layouts/ha-app-layout";
|
||||
import { haStyle } from "../../resources/styles";
|
||||
import { HomeAssistant } from "../../types";
|
||||
import "./ha-logbook";
|
||||
import { extractSearchParam } from "../../common/url/search-params";
|
||||
|
||||
@customElement("ha-panel-logbook")
|
||||
export class HaPanelLogbook extends LitElement {
|
||||
@@ -159,8 +158,6 @@ export class HaPanelLogbook extends LitElement {
|
||||
[this.hass.localize("ui.components.date-range-picker.ranges.last_week")]:
|
||||
[addDays(weekStart, -7), addDays(weekEnd, -7)],
|
||||
};
|
||||
|
||||
this._entityId = extractSearchParam("entity_id") ?? "";
|
||||
}
|
||||
|
||||
protected updated(changedProps: PropertyValues<this>) {
|
||||
|
||||
@@ -154,13 +154,11 @@ class HuiAlarmPanelCard extends LitElement implements LovelaceCard {
|
||||
stateObj.attributes.friendly_name ||
|
||||
stateLabel}
|
||||
<ha-chip
|
||||
hasIcon
|
||||
.leadingIcon=${alarmPanelIcon(stateObj.state)}
|
||||
.label=${stateLabel}
|
||||
class=${classMap({ [stateObj.state]: true })}
|
||||
@click=${this._handleMoreInfo}
|
||||
>
|
||||
<ha-svg-icon slot="icon" .path=${alarmPanelIcon(stateObj.state)}>
|
||||
</ha-svg-icon>
|
||||
${stateLabel}
|
||||
</ha-chip>
|
||||
</h1>
|
||||
<div id="armActions" class="actions">
|
||||
|
||||
@@ -78,7 +78,7 @@ export class HuiStatisticsGraphCard extends LitElement implements LovelaceCard {
|
||||
}
|
||||
|
||||
const configEntities = config.entities
|
||||
? processConfigEntities(config.entities, false)
|
||||
? processConfigEntities(config.entities)
|
||||
: [];
|
||||
|
||||
this._entities = [];
|
||||
|
||||
@@ -87,14 +87,7 @@ class HuiWeatherForecastCard extends LitElement implements LovelaceCard {
|
||||
}
|
||||
|
||||
public getCardSize(): number {
|
||||
let cardSize = 0;
|
||||
if (this._config?.show_current !== false) {
|
||||
cardSize += 2;
|
||||
}
|
||||
if (this._config?.show_forecast !== false) {
|
||||
cardSize += 3;
|
||||
}
|
||||
return cardSize;
|
||||
return this._config?.show_forecast !== false ? 5 : 2;
|
||||
}
|
||||
|
||||
public setConfig(config: WeatherForecastCardConfig): void {
|
||||
@@ -175,7 +168,6 @@ class HuiWeatherForecastCard extends LitElement implements LovelaceCard {
|
||||
stateObj.attributes.forecast?.length
|
||||
? stateObj.attributes.forecast.slice(0, this._veryVeryNarrow ? 3 : 5)
|
||||
: undefined;
|
||||
const weather = !forecast || this._config?.show_current !== false;
|
||||
|
||||
let hourly: boolean | undefined;
|
||||
let dayNight: boolean | undefined;
|
||||
@@ -210,81 +202,74 @@ class HuiWeatherForecastCard extends LitElement implements LovelaceCard {
|
||||
hasAction(this._config.tap_action) ? "0" : undefined
|
||||
)}
|
||||
>
|
||||
${weather
|
||||
? html`
|
||||
<div class="content">
|
||||
<div class="icon-image">
|
||||
${weatherStateIcon ||
|
||||
html`
|
||||
<ha-state-icon
|
||||
class="weather-icon"
|
||||
.state=${stateObj}
|
||||
></ha-state-icon>
|
||||
`}
|
||||
</div>
|
||||
<div class="info">
|
||||
<div class="name-state">
|
||||
<div class="state">
|
||||
${computeStateDisplay(
|
||||
this.hass.localize,
|
||||
stateObj,
|
||||
this.hass.locale
|
||||
)}
|
||||
</div>
|
||||
<div class="name" .title=${name}>${name}</div>
|
||||
</div>
|
||||
<div class="temp-attribute">
|
||||
<div class="temp">
|
||||
${formatNumber(
|
||||
stateObj.attributes.temperature,
|
||||
this.hass.locale
|
||||
)} <span
|
||||
>${getWeatherUnit(this.hass, "temperature")}</span
|
||||
>
|
||||
</div>
|
||||
<div class="attribute">
|
||||
${this._config.secondary_info_attribute !== undefined
|
||||
? html`
|
||||
${this._config.secondary_info_attribute in
|
||||
weatherAttrIcons
|
||||
? html`
|
||||
<ha-svg-icon
|
||||
class="attr-icon"
|
||||
.path=${weatherAttrIcons[
|
||||
this._config.secondary_info_attribute
|
||||
]}
|
||||
></ha-svg-icon>
|
||||
`
|
||||
: this.hass!.localize(
|
||||
`ui.card.weather.attributes.${this._config.secondary_info_attribute}`
|
||||
)}
|
||||
${this._config.secondary_info_attribute ===
|
||||
"wind_speed"
|
||||
? getWind(
|
||||
this.hass,
|
||||
stateObj.attributes.wind_speed,
|
||||
stateObj.attributes.wind_bearing
|
||||
)
|
||||
: html`
|
||||
${formatNumber(
|
||||
stateObj.attributes[
|
||||
this._config.secondary_info_attribute
|
||||
],
|
||||
this.hass.locale
|
||||
)}
|
||||
${getWeatherUnit(
|
||||
this.hass,
|
||||
this._config.secondary_info_attribute
|
||||
)}
|
||||
`}
|
||||
`
|
||||
: getSecondaryWeatherAttribute(this.hass, stateObj)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="content">
|
||||
<div class="icon-image">
|
||||
${weatherStateIcon ||
|
||||
html`
|
||||
<ha-state-icon
|
||||
class="weather-icon"
|
||||
.state=${stateObj}
|
||||
></ha-state-icon>
|
||||
`}
|
||||
</div>
|
||||
<div class="info">
|
||||
<div class="name-state">
|
||||
<div class="state">
|
||||
${computeStateDisplay(
|
||||
this.hass.localize,
|
||||
stateObj,
|
||||
this.hass.locale
|
||||
)}
|
||||
</div>
|
||||
`
|
||||
: ""}
|
||||
<div class="name" .title=${name}>${name}</div>
|
||||
</div>
|
||||
<div class="temp-attribute">
|
||||
<div class="temp">
|
||||
${formatNumber(
|
||||
stateObj.attributes.temperature,
|
||||
this.hass.locale
|
||||
)} <span>${getWeatherUnit(this.hass, "temperature")}</span>
|
||||
</div>
|
||||
<div class="attribute">
|
||||
${this._config.secondary_info_attribute !== undefined
|
||||
? html`
|
||||
${this._config.secondary_info_attribute in
|
||||
weatherAttrIcons
|
||||
? html`
|
||||
<ha-svg-icon
|
||||
class="attr-icon"
|
||||
.path=${weatherAttrIcons[
|
||||
this._config.secondary_info_attribute
|
||||
]}
|
||||
></ha-svg-icon>
|
||||
`
|
||||
: this.hass!.localize(
|
||||
`ui.card.weather.attributes.${this._config.secondary_info_attribute}`
|
||||
)}
|
||||
${this._config.secondary_info_attribute === "wind_speed"
|
||||
? getWind(
|
||||
this.hass,
|
||||
stateObj.attributes.wind_speed,
|
||||
stateObj.attributes.wind_bearing
|
||||
)
|
||||
: html`
|
||||
${formatNumber(
|
||||
stateObj.attributes[
|
||||
this._config.secondary_info_attribute
|
||||
],
|
||||
this.hass.locale
|
||||
)}
|
||||
${getWeatherUnit(
|
||||
this.hass,
|
||||
this._config.secondary_info_attribute
|
||||
)}
|
||||
`}
|
||||
`
|
||||
: getSecondaryWeatherAttribute(this.hass, stateObj)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
${forecast
|
||||
? html`
|
||||
<div class="forecast">
|
||||
|
||||
@@ -387,7 +387,6 @@ export interface ThermostatCardConfig extends LovelaceCardConfig {
|
||||
export interface WeatherForecastCardConfig extends LovelaceCardConfig {
|
||||
entity: string;
|
||||
name?: string;
|
||||
show_current?: boolean;
|
||||
show_forecast?: boolean;
|
||||
secondary_info_attribute?: string;
|
||||
theme?: string;
|
||||
|
||||
@@ -20,6 +20,7 @@ import {
|
||||
AlarmPanelCardConfig,
|
||||
EntitiesCardConfig,
|
||||
HumidifierCardConfig,
|
||||
LightCardConfig,
|
||||
PictureEntityCardConfig,
|
||||
ThermostatCardConfig,
|
||||
} from "../cards/types";
|
||||
@@ -31,8 +32,6 @@ const HIDE_DOMAIN = new Set([
|
||||
"device_tracker",
|
||||
"geo_location",
|
||||
"persistent_notification",
|
||||
"script",
|
||||
"sun",
|
||||
"zone",
|
||||
]);
|
||||
|
||||
@@ -85,7 +84,8 @@ const splitByAreas = (
|
||||
|
||||
export const computeCards = (
|
||||
states: Array<[string, HassEntity?]>,
|
||||
entityCardOptions: Partial<EntitiesCardConfig>
|
||||
entityCardOptions: Partial<EntitiesCardConfig>,
|
||||
single = false
|
||||
): LovelaceCardConfig[] => {
|
||||
const cards: LovelaceCardConfig[] = [];
|
||||
|
||||
@@ -123,6 +123,12 @@ export const computeCards = (
|
||||
entity: entityId,
|
||||
};
|
||||
cards.push(cardConfig);
|
||||
} else if (domain === "light" && single) {
|
||||
const cardConfig: LightCardConfig = {
|
||||
type: "light",
|
||||
entity: entityId,
|
||||
};
|
||||
cards.push(cardConfig);
|
||||
} else if (domain === "media_player") {
|
||||
const cardConfig = {
|
||||
type: "media-control",
|
||||
|
||||
@@ -52,7 +52,7 @@ export function hasConfigOrEntitiesChanged(
|
||||
|
||||
const oldHass = changedProps.get("hass") as HomeAssistant;
|
||||
|
||||
const entities = processConfigEntities(element._config!.entities, false);
|
||||
const entities = processConfigEntities(element._config!.entities);
|
||||
|
||||
return entities.some(
|
||||
(entity) =>
|
||||
|
||||
@@ -5,8 +5,7 @@ import { EntityConfig, LovelaceRowConfig } from "../entity-rows/types";
|
||||
export const processConfigEntities = <
|
||||
T extends EntityConfig | LovelaceRowConfig
|
||||
>(
|
||||
entities: Array<T | string>,
|
||||
checkEntityId = true
|
||||
entities: Array<T | string>
|
||||
): T[] => {
|
||||
if (!entities || !Array.isArray(entities)) {
|
||||
throw new Error("Entities need to be an array");
|
||||
@@ -36,7 +35,7 @@ export const processConfigEntities = <
|
||||
throw new Error(`Invalid entity specified at position ${index}.`);
|
||||
}
|
||||
|
||||
if (checkEntityId && !isValidEntityId((config as EntityConfig).entity!)) {
|
||||
if (!isValidEntityId((config as EntityConfig).entity!)) {
|
||||
throw new Error(
|
||||
`Invalid entity ID at position ${index}: ${
|
||||
(config as EntityConfig).entity
|
||||
|
||||
@@ -13,10 +13,8 @@ import { showSelectViewDialog } from "./select-view/show-select-view-dialog";
|
||||
export const addEntitiesToLovelaceView = async (
|
||||
element: HTMLElement,
|
||||
hass: HomeAssistant,
|
||||
entities: string[],
|
||||
cardTitle?: string
|
||||
entities: string[]
|
||||
) => {
|
||||
hass.loadFragmentTranslation("lovelace");
|
||||
const dashboards = await fetchDashboards(hass);
|
||||
|
||||
const storageDashs = dashboards.filter(
|
||||
@@ -32,7 +30,6 @@ export const addEntitiesToLovelaceView = async (
|
||||
showSuggestCardDialog(element, {
|
||||
entities,
|
||||
yaml: true,
|
||||
cardTitle,
|
||||
});
|
||||
return;
|
||||
}
|
||||
@@ -71,7 +68,6 @@ export const addEntitiesToLovelaceView = async (
|
||||
showSuggestCardDialog(element, {
|
||||
entities,
|
||||
yaml: true,
|
||||
cardTitle,
|
||||
});
|
||||
} else {
|
||||
// all storage dashboards are generated
|
||||
@@ -91,7 +87,6 @@ export const addEntitiesToLovelaceView = async (
|
||||
|
||||
if (!storageDashs.length && lovelaceConfig.views.length === 1) {
|
||||
showSuggestCardDialog(element, {
|
||||
cardTitle,
|
||||
lovelaceConfig: lovelaceConfig!,
|
||||
saveConfig: async (newConfig: LovelaceConfig): Promise<void> => {
|
||||
try {
|
||||
@@ -112,11 +107,9 @@ export const addEntitiesToLovelaceView = async (
|
||||
lovelaceConfig,
|
||||
urlPath,
|
||||
allowDashboardChange: true,
|
||||
actionLabel: hass.localize("ui.common.next"),
|
||||
dashboards,
|
||||
viewSelectedCallback: (newUrlPath, selectedDashConfig, viewIndex) => {
|
||||
showSuggestCardDialog(element, {
|
||||
cardTitle,
|
||||
lovelaceConfig: selectedDashConfig,
|
||||
saveConfig: async (newConfig: LovelaceConfig): Promise<void> => {
|
||||
try {
|
||||
|
||||
@@ -35,9 +35,8 @@ export class HuiDialogSuggestCard extends LitElement {
|
||||
entityId,
|
||||
this.hass.states[entityId],
|
||||
]),
|
||||
{
|
||||
title: params.cardTitle,
|
||||
}
|
||||
{},
|
||||
true
|
||||
);
|
||||
if (!Object.isFrozen(this._cardConfig)) {
|
||||
this._cardConfig = deepFreeze(this._cardConfig);
|
||||
|
||||
@@ -2,7 +2,6 @@ import { fireEvent } from "../../../../common/dom/fire_event";
|
||||
import { LovelaceCardConfig, LovelaceConfig } from "../../../../data/lovelace";
|
||||
|
||||
export interface SuggestCardDialogParams {
|
||||
cardTitle?: string;
|
||||
lovelaceConfig?: LovelaceConfig;
|
||||
yaml?: boolean;
|
||||
saveConfig?: (config: LovelaceConfig) => void;
|
||||
|
||||
@@ -61,7 +61,7 @@ export class HuiStatisticsGraphCardEditor
|
||||
assert(config, cardConfigStruct);
|
||||
this._config = config;
|
||||
this._configEntities = config.entities
|
||||
? processConfigEntities(config.entities, false).map((cfg) => cfg.entity)
|
||||
? processConfigEntities(config.entities).map((cfg) => cfg.entity)
|
||||
: [];
|
||||
}
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@ import { computeRTLDirection } from "../../../../common/util/compute_rtl";
|
||||
import "../../../../components/entity/ha-entity-attribute-picker";
|
||||
import "../../../../components/entity/ha-entity-picker";
|
||||
import "../../../../components/ha-formfield";
|
||||
import "../../../../components/ha-radio";
|
||||
import "../../../../components/ha-switch";
|
||||
import { HomeAssistant } from "../../../../types";
|
||||
import { WeatherForecastCardConfig } from "../../cards/types";
|
||||
import "../../components/hui-theme-select-editor";
|
||||
@@ -15,8 +15,6 @@ import { actionConfigStruct } from "../structs/action-struct";
|
||||
import { EditorTarget, EntitiesEditorEvent } from "../types";
|
||||
import { configElementStyle } from "./config-elements-style";
|
||||
import { baseLovelaceCardConfig } from "../structs/base-card-struct";
|
||||
import { UNAVAILABLE } from "../../../../data/entity";
|
||||
import { WeatherEntity } from "../../../../data/weather";
|
||||
|
||||
const cardConfigStruct = assign(
|
||||
baseLovelaceCardConfig,
|
||||
@@ -24,7 +22,6 @@ const cardConfigStruct = assign(
|
||||
entity: optional(string()),
|
||||
name: optional(string()),
|
||||
theme: optional(string()),
|
||||
show_current: optional(boolean()),
|
||||
show_forecast: optional(boolean()),
|
||||
secondary_info_attribute: optional(string()),
|
||||
tap_action: optional(actionConfigStruct),
|
||||
@@ -47,18 +44,6 @@ export class HuiWeatherForecastCardEditor
|
||||
public setConfig(config: WeatherForecastCardConfig): void {
|
||||
assert(config, cardConfigStruct);
|
||||
this._config = config;
|
||||
|
||||
if (
|
||||
/* cannot show forecast in case it is unavailable on the entity */
|
||||
(config.show_forecast === true && this._has_forecast === false) ||
|
||||
/* cannot hide both weather and forecast, need one of them */
|
||||
(config.show_current === false && config.show_forecast === false)
|
||||
) {
|
||||
/* reset to sane default, show weather, but hide forecast */
|
||||
fireEvent(this, "config-changed", {
|
||||
config: { ...config, show_current: true, show_forecast: false },
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
get _entity(): string {
|
||||
@@ -73,28 +58,14 @@ export class HuiWeatherForecastCardEditor
|
||||
return this._config!.theme || "";
|
||||
}
|
||||
|
||||
get _show_current(): boolean {
|
||||
return this._config!.show_current ?? true;
|
||||
}
|
||||
|
||||
get _show_forecast(): boolean {
|
||||
return this._config!.show_forecast ?? this._has_forecast === true;
|
||||
return this._config!.show_forecast || true;
|
||||
}
|
||||
|
||||
get _secondary_info_attribute(): string {
|
||||
return this._config!.secondary_info_attribute || "";
|
||||
}
|
||||
|
||||
get _has_forecast(): boolean | undefined {
|
||||
if (this.hass && this._config) {
|
||||
const stateObj = this.hass.states[this._config.entity] as WeatherEntity;
|
||||
if (stateObj && stateObj.state !== UNAVAILABLE) {
|
||||
return !!stateObj.attributes.forecast?.length;
|
||||
}
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
protected render(): TemplateResult {
|
||||
if (!this.hass || !this._config) {
|
||||
return html``;
|
||||
@@ -132,6 +103,8 @@ export class HuiWeatherForecastCardEditor
|
||||
.configValue=${"theme"}
|
||||
@value-changed=${this._valueChanged}
|
||||
></hui-theme-select-editor>
|
||||
</div>
|
||||
<div class="side-by-side">
|
||||
<ha-entity-attribute-picker
|
||||
.hass=${this.hass}
|
||||
.entityId=${this._entity}
|
||||
@@ -144,51 +117,17 @@ export class HuiWeatherForecastCardEditor
|
||||
.configValue=${"secondary_info_attribute"}
|
||||
@value-changed=${this._valueChanged}
|
||||
></ha-entity-attribute-picker>
|
||||
</div>
|
||||
<div class="side-by-side">
|
||||
<ha-formfield
|
||||
.label=${this.hass.localize(
|
||||
"ui.panel.lovelace.editor.card.weather-forecast.show_both"
|
||||
"ui.panel.lovelace.editor.card.weather-forecast.show_forecast"
|
||||
)}
|
||||
.dir=${computeRTLDirection(this.hass)}
|
||||
>
|
||||
<ha-radio
|
||||
.disabled=${this._has_forecast === false}
|
||||
.checked=${this._has_forecast === true &&
|
||||
this._show_current &&
|
||||
this._show_forecast}
|
||||
.configValue=${"show_both"}
|
||||
@change=${this._valueChanged}
|
||||
></ha-radio
|
||||
></ha-formfield>
|
||||
<ha-formfield
|
||||
.label=${this.hass.localize(
|
||||
"ui.panel.lovelace.editor.card.weather-forecast.show_only_current"
|
||||
)}
|
||||
.dir=${computeRTLDirection(this.hass)}
|
||||
>
|
||||
<ha-radio
|
||||
.disabled=${this._has_forecast === false}
|
||||
.checked=${this._has_forecast === false ||
|
||||
(this._show_current && !this._show_forecast)}
|
||||
.configValue=${"show_current"}
|
||||
@change=${this._valueChanged}
|
||||
></ha-radio
|
||||
></ha-formfield>
|
||||
<ha-formfield
|
||||
.label=${this.hass.localize(
|
||||
"ui.panel.lovelace.editor.card.weather-forecast.show_only_forecast"
|
||||
)}
|
||||
.dir=${computeRTLDirection(this.hass)}
|
||||
>
|
||||
<ha-radio
|
||||
.disabled=${this._has_forecast === false}
|
||||
.checked=${this._has_forecast === true &&
|
||||
!this._show_current &&
|
||||
this._show_forecast}
|
||||
<ha-switch
|
||||
.checked=${this._config!.show_forecast !== false}
|
||||
.configValue=${"show_forecast"}
|
||||
@change=${this._valueChanged}
|
||||
></ha-radio
|
||||
></ha-switch
|
||||
></ha-formfield>
|
||||
</div>
|
||||
</div>
|
||||
@@ -204,20 +143,7 @@ export class HuiWeatherForecastCardEditor
|
||||
return;
|
||||
}
|
||||
if (target.configValue) {
|
||||
if (target.configValue.startsWith("show_")) {
|
||||
this._config = { ...this._config };
|
||||
if (target.configValue === "show_both") {
|
||||
/* delete since true is default */
|
||||
delete this._config.show_current;
|
||||
delete this._config.show_forecast;
|
||||
} else if (target.configValue === "show_current") {
|
||||
delete this._config.show_current;
|
||||
this._config.show_forecast = false;
|
||||
} else if (target.configValue === "show_forecast") {
|
||||
delete this._config.show_forecast;
|
||||
this._config.show_current = false;
|
||||
}
|
||||
} else if (target.value === "") {
|
||||
if (target.value === "") {
|
||||
this._config = { ...this._config };
|
||||
delete this._config[target.configValue!];
|
||||
} else {
|
||||
|
||||
@@ -131,7 +131,7 @@ export class HuiDialogSelectView extends LitElement {
|
||||
${this.hass!.localize("ui.common.cancel")}
|
||||
</mwc-button>
|
||||
<mwc-button slot="primaryAction" @click=${this._selectView}>
|
||||
${this._params.actionLabel || this.hass!.localize("ui.common.move")}
|
||||
${this.hass!.localize("ui.common.move")}
|
||||
</mwc-button>
|
||||
</ha-dialog>
|
||||
`;
|
||||
|
||||
@@ -7,7 +7,6 @@ export interface SelectViewDialogParams {
|
||||
dashboards?: LovelaceDashboard[];
|
||||
urlPath?: string | null;
|
||||
header?: string;
|
||||
actionLabel?: string;
|
||||
viewSelectedCallback: (
|
||||
urlPath: string | null,
|
||||
config: LovelaceConfig,
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { askWrite } from "../common/auth/token_storage";
|
||||
import { subscribeUser, userCollection } from "../data/ws-user";
|
||||
import { Constructor } from "../types";
|
||||
import { clearState } from "../util/ha-pref-storage";
|
||||
@@ -25,6 +26,16 @@ export default <T extends Constructor<HassBaseEl>>(superClass: T) =>
|
||||
subscribeUser(this.hass!.connection, (user) =>
|
||||
this._updateHass({ user })
|
||||
);
|
||||
|
||||
if (askWrite()) {
|
||||
this.updateComplete
|
||||
.then(() => import("../dialogs/ha-store-auth-card"))
|
||||
.then(() => {
|
||||
const el = document.createElement("ha-store-auth-card");
|
||||
this.provideHass(el);
|
||||
document.body.appendChild(el);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private async _handleLogout() {
|
||||
|
||||
+14
-20
@@ -105,6 +105,11 @@
|
||||
}
|
||||
},
|
||||
"ui": {
|
||||
"auth_store": {
|
||||
"ask": "Do you want to stay logged in?",
|
||||
"decline": "No",
|
||||
"confirm": "Yes"
|
||||
},
|
||||
"card": {
|
||||
"alarm_control_panel": {
|
||||
"code": "Code",
|
||||
@@ -628,10 +633,8 @@
|
||||
"edit": "Edit entity",
|
||||
"details": "Details",
|
||||
"history": "History",
|
||||
"logbook": "Logbook",
|
||||
"last_changed": "Last changed",
|
||||
"last_updated": "Last updated",
|
||||
"show_more": "Show more",
|
||||
"script": {
|
||||
"last_action": "Last action",
|
||||
"last_triggered": "Last triggered"
|
||||
@@ -1693,17 +1696,17 @@
|
||||
"label": "Call service"
|
||||
},
|
||||
"delay": {
|
||||
"label": "Wait for time to pass (delay)",
|
||||
"delay": "Duration"
|
||||
"label": "Delay",
|
||||
"delay": "[%key:ui::panel::config::automation::editor::actions::type::delay::label%]"
|
||||
},
|
||||
"wait_template": {
|
||||
"label": "Wait for a template",
|
||||
"label": "Wait",
|
||||
"wait_template": "Wait Template",
|
||||
"timeout": "Timeout (optional)",
|
||||
"continue_timeout": "Continue on timeout"
|
||||
},
|
||||
"wait_for_trigger": {
|
||||
"label": "Wait for a trigger",
|
||||
"label": "Wait for trigger",
|
||||
"timeout": "[%key:ui::panel::config::automation::editor::actions::type::wait_template::timeout%]",
|
||||
"continue_timeout": "[%key:ui::panel::config::automation::editor::actions::type::wait_template::continue_timeout%]"
|
||||
},
|
||||
@@ -1796,18 +1799,13 @@
|
||||
"learn_more": "Learn more about using blueprints",
|
||||
"headers": {
|
||||
"name": "Name",
|
||||
"type": "Type",
|
||||
"domain": "Domain",
|
||||
"file_name": "File name"
|
||||
},
|
||||
"types": {
|
||||
"automation": "Automation",
|
||||
"script": "Script"
|
||||
},
|
||||
"confirm_delete_header": "Delete this blueprint?",
|
||||
"confirm_delete_text": "Are you sure you want to delete this blueprint?",
|
||||
"add_blueprint": "Import blueprint",
|
||||
"create_automation": "Create automation",
|
||||
"create_script": "Create script",
|
||||
"use_blueprint": "Create automation",
|
||||
"delete_blueprint": "Delete blueprint",
|
||||
"share_blueprint": "Share blueprint",
|
||||
"share_blueprint_no_url": "Unable to share blueprint: no source url",
|
||||
@@ -2175,10 +2173,9 @@
|
||||
"device_not_found": "Device not found.",
|
||||
"entities": {
|
||||
"entities": "Entities",
|
||||
"control": "Controls",
|
||||
"sensor": "Sensors",
|
||||
"state": "State",
|
||||
"diagnostic": "Diagnostic",
|
||||
"config": "Configuration",
|
||||
"config": "Config",
|
||||
"add_entities_lovelace": "Add to Lovelace",
|
||||
"none": "This device has no entities",
|
||||
"hide_disabled": "Hide disabled",
|
||||
@@ -3441,9 +3438,7 @@
|
||||
"weather-forecast": {
|
||||
"name": "Weather Forecast",
|
||||
"description": "The Weather Forecast card displays the weather. Very useful to include on interfaces that people display on the wall.",
|
||||
"show_both": "Show current Weather and Forecast",
|
||||
"show_only_current": "Show only current Weather",
|
||||
"show_only_forecast": "Show only Forecast"
|
||||
"show_forecast": "Show Forecast"
|
||||
}
|
||||
},
|
||||
"view": {
|
||||
@@ -3671,7 +3666,6 @@
|
||||
"logging_in_with": "Logging in with **{authProviderName}**.",
|
||||
"pick_auth_provider": "Or log in with",
|
||||
"abort_intro": "Login aborted",
|
||||
"store_token": "Keep me logged in",
|
||||
"form": {
|
||||
"working": "Please wait",
|
||||
"unknown_error": "Something went wrong",
|
||||
|
||||
Reference in New Issue
Block a user