mirror of
https://github.com/home-assistant/frontend.git
synced 2025-07-25 18:26:35 +00:00
20231205.0 (#18916)
This commit is contained in:
commit
eb5e7ba3f3
@ -39,7 +39,9 @@ export class HADemoCard extends LitElement implements LovelaceCard {
|
|||||||
<div class="picker">
|
<div class="picker">
|
||||||
<div class="label">
|
<div class="label">
|
||||||
${this._switching
|
${this._switching
|
||||||
? html`<ha-circular-progress active></ha-circular-progress>`
|
? html`<ha-circular-progress
|
||||||
|
indeterminate
|
||||||
|
></ha-circular-progress>`
|
||||||
: until(
|
: until(
|
||||||
selectedDemoConfig.then(
|
selectedDemoConfig.then(
|
||||||
(conf) => html`
|
(conf) => html`
|
||||||
|
@ -0,0 +1,4 @@
|
|||||||
|
---
|
||||||
|
title: Circular Progress
|
||||||
|
subtitle: Can be used to indicate an ongoing task.
|
||||||
|
---
|
64
gallery/src/pages/components/ha-circular-progress.ts
Normal file
64
gallery/src/pages/components/ha-circular-progress.ts
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
import { html, css, LitElement, TemplateResult } from "lit";
|
||||||
|
import { customElement, property } from "lit/decorators";
|
||||||
|
import "../../../../src/components/ha-bar";
|
||||||
|
import "../../../../src/components/ha-card";
|
||||||
|
import "../../../../src/components/ha-circular-progress";
|
||||||
|
import "@material/web/progress/circular-progress";
|
||||||
|
import { HomeAssistant } from "../../../../src/types";
|
||||||
|
|
||||||
|
@customElement("demo-components-ha-circular-progress")
|
||||||
|
export class DemoHaCircularProgress extends LitElement {
|
||||||
|
@property({ attribute: false }) hass!: HomeAssistant;
|
||||||
|
|
||||||
|
protected render(): TemplateResult {
|
||||||
|
return html`<ha-card header="Basic circular progress">
|
||||||
|
<div class="card-content">
|
||||||
|
<ha-circular-progress indeterminate></ha-circular-progress></div
|
||||||
|
></ha-card>
|
||||||
|
<ha-card header="Different circular progress sizes">
|
||||||
|
<div class="card-content">
|
||||||
|
<ha-circular-progress
|
||||||
|
indeterminate
|
||||||
|
size="tiny"
|
||||||
|
></ha-circular-progress>
|
||||||
|
<ha-circular-progress
|
||||||
|
indeterminate
|
||||||
|
size="small"
|
||||||
|
></ha-circular-progress>
|
||||||
|
<ha-circular-progress
|
||||||
|
indeterminate
|
||||||
|
size="medium"
|
||||||
|
></ha-circular-progress>
|
||||||
|
<ha-circular-progress
|
||||||
|
indeterminate
|
||||||
|
size="large"
|
||||||
|
></ha-circular-progress></div
|
||||||
|
></ha-card>
|
||||||
|
<ha-card header="Circular progress with an aria-label">
|
||||||
|
<div class="card-content">
|
||||||
|
<ha-circular-progress
|
||||||
|
indeterminate
|
||||||
|
aria-label="Doing something..."
|
||||||
|
></ha-circular-progress>
|
||||||
|
<ha-circular-progress
|
||||||
|
indeterminate
|
||||||
|
.ariaLabel=${"Doing something..."}
|
||||||
|
></ha-circular-progress></div
|
||||||
|
></ha-card>`;
|
||||||
|
}
|
||||||
|
|
||||||
|
static get styles() {
|
||||||
|
return css`
|
||||||
|
ha-card {
|
||||||
|
max-width: 600px;
|
||||||
|
margin: 24px auto;
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
declare global {
|
||||||
|
interface HTMLElementTagNameMap {
|
||||||
|
"demo-components-ha-circular-progress": DemoHaCircularProgress;
|
||||||
|
}
|
||||||
|
}
|
@ -20,7 +20,7 @@ class HassioAddonConfigDashboard extends LitElement {
|
|||||||
|
|
||||||
protected render(): TemplateResult {
|
protected render(): TemplateResult {
|
||||||
if (!this.addon) {
|
if (!this.addon) {
|
||||||
return html`<ha-circular-progress active></ha-circular-progress>`;
|
return html`<ha-circular-progress indeterminate></ha-circular-progress>`;
|
||||||
}
|
}
|
||||||
const hasConfiguration =
|
const hasConfiguration =
|
||||||
(this.addon.options && Object.keys(this.addon.options).length) ||
|
(this.addon.options && Object.keys(this.addon.options).length) ||
|
||||||
|
@ -34,7 +34,7 @@ class HassioAddonDocumentationDashboard extends LitElement {
|
|||||||
|
|
||||||
protected render(): TemplateResult {
|
protected render(): TemplateResult {
|
||||||
if (!this.addon) {
|
if (!this.addon) {
|
||||||
return html`<ha-circular-progress active></ha-circular-progress>`;
|
return html`<ha-circular-progress indeterminate></ha-circular-progress>`;
|
||||||
}
|
}
|
||||||
return html`
|
return html`
|
||||||
<div class="content">
|
<div class="content">
|
||||||
|
@ -22,7 +22,7 @@ class HassioAddonInfoDashboard extends LitElement {
|
|||||||
|
|
||||||
protected render(): TemplateResult {
|
protected render(): TemplateResult {
|
||||||
if (!this.addon) {
|
if (!this.addon) {
|
||||||
return html`<ha-circular-progress active></ha-circular-progress>`;
|
return html`<ha-circular-progress indeterminate></ha-circular-progress>`;
|
||||||
}
|
}
|
||||||
|
|
||||||
return html`
|
return html`
|
||||||
|
@ -18,7 +18,9 @@ class HassioAddonLogDashboard extends LitElement {
|
|||||||
|
|
||||||
protected render(): TemplateResult {
|
protected render(): TemplateResult {
|
||||||
if (!this.addon) {
|
if (!this.addon) {
|
||||||
return html` <ha-circular-progress active></ha-circular-progress> `;
|
return html`
|
||||||
|
<ha-circular-progress indeterminate></ha-circular-progress>
|
||||||
|
`;
|
||||||
}
|
}
|
||||||
return html`
|
return html`
|
||||||
<div class="content">
|
<div class="content">
|
||||||
|
@ -95,7 +95,7 @@ class HassioBackupDialog
|
|||||||
</ha-header-bar>
|
</ha-header-bar>
|
||||||
</div>
|
</div>
|
||||||
${this._restoringBackup
|
${this._restoringBackup
|
||||||
? html`<ha-circular-progress active></ha-circular-progress>`
|
? html`<ha-circular-progress indeterminate></ha-circular-progress>`
|
||||||
: html`
|
: html`
|
||||||
<supervisor-backup-content
|
<supervisor-backup-content
|
||||||
.hass=${this.hass}
|
.hass=${this.hass}
|
||||||
|
@ -57,7 +57,7 @@ class HassioCreateBackupDialog extends LitElement {
|
|||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
${this._creatingBackup
|
${this._creatingBackup
|
||||||
? html`<ha-circular-progress active></ha-circular-progress>`
|
? html`<ha-circular-progress indeterminate></ha-circular-progress>`
|
||||||
: html`<supervisor-backup-content
|
: html`<supervisor-backup-content
|
||||||
.hass=${this.hass}
|
.hass=${this.hass}
|
||||||
.supervisor=${this._dialogParams.supervisor}
|
.supervisor=${this._dialogParams.supervisor}
|
||||||
|
@ -71,7 +71,11 @@ class HassioDatadiskDialog extends LitElement {
|
|||||||
?hideActions=${this.moving}
|
?hideActions=${this.moving}
|
||||||
>
|
>
|
||||||
${this.moving
|
${this.moving
|
||||||
? html` <ha-circular-progress alt="Moving" size="large" active>
|
? html` <ha-circular-progress
|
||||||
|
aria-label="Moving"
|
||||||
|
size="large"
|
||||||
|
indeterminate
|
||||||
|
>
|
||||||
</ha-circular-progress>
|
</ha-circular-progress>
|
||||||
<p class="progress-text">
|
<p class="progress-text">
|
||||||
${this.dialogParams.supervisor.localize(
|
${this.dialogParams.supervisor.localize(
|
||||||
|
@ -155,7 +155,11 @@ export class DialogHassioNetwork
|
|||||||
.disabled=${this._scanning}
|
.disabled=${this._scanning}
|
||||||
>
|
>
|
||||||
${this._scanning
|
${this._scanning
|
||||||
? html`<ha-circular-progress active size="small">
|
? html`<ha-circular-progress
|
||||||
|
aria-label="Scanning"
|
||||||
|
indeterminate
|
||||||
|
size="small"
|
||||||
|
>
|
||||||
</ha-circular-progress>`
|
</ha-circular-progress>`
|
||||||
: this.supervisor.localize("dialog.network.scan_ap")}
|
: this.supervisor.localize("dialog.network.scan_ap")}
|
||||||
</mwc-button>
|
</mwc-button>
|
||||||
@ -274,7 +278,7 @@ export class DialogHassioNetwork
|
|||||||
</mwc-button>
|
</mwc-button>
|
||||||
<mwc-button @click=${this._updateNetwork} .disabled=${!this._dirty}>
|
<mwc-button @click=${this._updateNetwork} .disabled=${!this._dirty}>
|
||||||
${this._processing
|
${this._processing
|
||||||
? html`<ha-circular-progress active size="small">
|
? html`<ha-circular-progress indeterminate size="small">
|
||||||
</ha-circular-progress>`
|
</ha-circular-progress>`
|
||||||
: this.supervisor.localize("common.save")}
|
: this.supervisor.localize("common.save")}
|
||||||
</mwc-button>
|
</mwc-button>
|
||||||
|
@ -158,7 +158,7 @@ class HassioRepositoriesDialog extends LitElement {
|
|||||||
<mwc-button @click=${this._addRepository}>
|
<mwc-button @click=${this._addRepository}>
|
||||||
${this._processing
|
${this._processing
|
||||||
? html`<ha-circular-progress
|
? html`<ha-circular-progress
|
||||||
active
|
indeterminate
|
||||||
size="small"
|
size="small"
|
||||||
></ha-circular-progress>`
|
></ha-circular-progress>`
|
||||||
: this._dialogParams!.supervisor.localize(
|
: this._dialogParams!.supervisor.localize(
|
||||||
|
@ -174,7 +174,11 @@ class UpdateAvailableCard extends LitElement {
|
|||||||
`
|
`
|
||||||
: ""}
|
: ""}
|
||||||
`
|
`
|
||||||
: html`<ha-circular-progress alt="Updating" size="large" active>
|
: html`<ha-circular-progress
|
||||||
|
aria-label="Updating"
|
||||||
|
size="large"
|
||||||
|
indeterminate
|
||||||
|
>
|
||||||
</ha-circular-progress>
|
</ha-circular-progress>
|
||||||
<p class="progress-text">
|
<p class="progress-text">
|
||||||
${this.supervisor.localize("update_available.updating", {
|
${this.supervisor.localize("update_available.updating", {
|
||||||
|
12
package.json
12
package.json
@ -60,7 +60,6 @@
|
|||||||
"@material/mwc-base": "0.27.0",
|
"@material/mwc-base": "0.27.0",
|
||||||
"@material/mwc-button": "0.27.0",
|
"@material/mwc-button": "0.27.0",
|
||||||
"@material/mwc-checkbox": "0.27.0",
|
"@material/mwc-checkbox": "0.27.0",
|
||||||
"@material/mwc-circular-progress": "0.27.0",
|
|
||||||
"@material/mwc-dialog": "0.27.0",
|
"@material/mwc-dialog": "0.27.0",
|
||||||
"@material/mwc-drawer": "0.27.0",
|
"@material/mwc-drawer": "0.27.0",
|
||||||
"@material/mwc-fab": "0.27.0",
|
"@material/mwc-fab": "0.27.0",
|
||||||
@ -91,8 +90,8 @@
|
|||||||
"@polymer/paper-toast": "3.0.1",
|
"@polymer/paper-toast": "3.0.1",
|
||||||
"@polymer/polymer": "3.5.1",
|
"@polymer/polymer": "3.5.1",
|
||||||
"@thomasloven/round-slider": "0.6.0",
|
"@thomasloven/round-slider": "0.6.0",
|
||||||
"@vaadin/combo-box": "24.2.4",
|
"@vaadin/combo-box": "24.2.5",
|
||||||
"@vaadin/vaadin-themable-mixin": "24.2.4",
|
"@vaadin/vaadin-themable-mixin": "24.2.5",
|
||||||
"@vibrant/color": "3.2.1-alpha.1",
|
"@vibrant/color": "3.2.1-alpha.1",
|
||||||
"@vibrant/core": "3.2.1-alpha.1",
|
"@vibrant/core": "3.2.1-alpha.1",
|
||||||
"@vibrant/quantizer-mmcq": "3.2.1-alpha.1",
|
"@vibrant/quantizer-mmcq": "3.2.1-alpha.1",
|
||||||
@ -120,14 +119,13 @@
|
|||||||
"leaflet-draw": "1.0.4",
|
"leaflet-draw": "1.0.4",
|
||||||
"lit": "2.8.0",
|
"lit": "2.8.0",
|
||||||
"luxon": "3.4.4",
|
"luxon": "3.4.4",
|
||||||
"marked": "10.0.0",
|
"marked": "11.0.0",
|
||||||
"memoize-one": "6.0.0",
|
"memoize-one": "6.0.0",
|
||||||
"node-vibrant": "3.2.1-alpha.1",
|
"node-vibrant": "3.2.1-alpha.1",
|
||||||
"proxy-polyfill": "0.3.2",
|
"proxy-polyfill": "0.3.2",
|
||||||
"punycode": "2.3.1",
|
"punycode": "2.3.1",
|
||||||
"qr-scanner": "1.4.2",
|
"qr-scanner": "1.4.2",
|
||||||
"qrcode": "1.5.3",
|
"qrcode": "1.5.3",
|
||||||
"resize-observer-polyfill": "1.5.1",
|
|
||||||
"roboto-fontface": "0.10.0",
|
"roboto-fontface": "0.10.0",
|
||||||
"rrule": "2.8.1",
|
"rrule": "2.8.1",
|
||||||
"sortablejs": "1.15.1",
|
"sortablejs": "1.15.1",
|
||||||
@ -194,7 +192,7 @@
|
|||||||
"babel-plugin-template-html-minifier": "4.1.0",
|
"babel-plugin-template-html-minifier": "4.1.0",
|
||||||
"chai": "4.3.10",
|
"chai": "4.3.10",
|
||||||
"del": "7.1.0",
|
"del": "7.1.0",
|
||||||
"eslint": "8.54.0",
|
"eslint": "8.55.0",
|
||||||
"eslint-config-airbnb-base": "15.0.0",
|
"eslint-config-airbnb-base": "15.0.0",
|
||||||
"eslint-config-airbnb-typescript": "17.1.0",
|
"eslint-config-airbnb-typescript": "17.1.0",
|
||||||
"eslint-config-prettier": "9.0.0",
|
"eslint-config-prettier": "9.0.0",
|
||||||
@ -206,7 +204,7 @@
|
|||||||
"eslint-plugin-unused-imports": "3.0.0",
|
"eslint-plugin-unused-imports": "3.0.0",
|
||||||
"eslint-plugin-wc": "2.0.4",
|
"eslint-plugin-wc": "2.0.4",
|
||||||
"fancy-log": "2.0.0",
|
"fancy-log": "2.0.0",
|
||||||
"fs-extra": "11.1.1",
|
"fs-extra": "11.2.0",
|
||||||
"glob": "10.3.10",
|
"glob": "10.3.10",
|
||||||
"gulp": "4.0.2",
|
"gulp": "4.0.2",
|
||||||
"gulp-flatmap": "1.0.2",
|
"gulp-flatmap": "1.0.2",
|
||||||
|
@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|||||||
|
|
||||||
[project]
|
[project]
|
||||||
name = "home-assistant-frontend"
|
name = "home-assistant-frontend"
|
||||||
version = "20231204.0"
|
version = "20231205.0"
|
||||||
license = {text = "Apache-2.0"}
|
license = {text = "Apache-2.0"}
|
||||||
description = "The Home Assistant frontend"
|
description = "The Home Assistant frontend"
|
||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
|
@ -45,7 +45,7 @@ export class HaProgressButton extends LitElement {
|
|||||||
? html`
|
? html`
|
||||||
<ha-circular-progress
|
<ha-circular-progress
|
||||||
size="small"
|
size="small"
|
||||||
active
|
indeterminate
|
||||||
></ha-circular-progress>
|
></ha-circular-progress>
|
||||||
`
|
`
|
||||||
: ""}
|
: ""}
|
||||||
|
@ -469,6 +469,7 @@ export class HaChartBase extends LitElement {
|
|||||||
.chartTooltip li {
|
.chartTooltip li {
|
||||||
display: flex;
|
display: flex;
|
||||||
white-space: pre-line;
|
white-space: pre-line;
|
||||||
|
word-break: break-word;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
line-height: 16px;
|
line-height: 16px;
|
||||||
padding: 4px 0;
|
padding: 4px 0;
|
||||||
@ -476,6 +477,7 @@ export class HaChartBase extends LitElement {
|
|||||||
.chartTooltip .title {
|
.chartTooltip .title {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
|
word-break: break-word;
|
||||||
direction: ltr;
|
direction: ltr;
|
||||||
}
|
}
|
||||||
.chartTooltip .footer {
|
.chartTooltip .footer {
|
||||||
|
@ -1,54 +1,44 @@
|
|||||||
import { CircularProgress } from "@material/mwc-circular-progress";
|
import "element-internals-polyfill";
|
||||||
import { CSSResultGroup, css } from "lit";
|
import { MdCircularProgress } from "@material/web/progress/circular-progress";
|
||||||
|
import { CSSResult, PropertyValues, css } from "lit";
|
||||||
import { customElement, property } from "lit/decorators";
|
import { customElement, property } from "lit/decorators";
|
||||||
|
|
||||||
@customElement("ha-circular-progress")
|
@customElement("ha-circular-progress")
|
||||||
// @ts-ignore
|
export class HaCircularProgress extends MdCircularProgress {
|
||||||
export class HaCircularProgress extends CircularProgress {
|
@property({ attribute: "aria-label", type: String }) public ariaLabel =
|
||||||
@property({ type: Boolean })
|
"Loading";
|
||||||
public active = false;
|
|
||||||
|
|
||||||
@property()
|
@property() public size: "tiny" | "small" | "medium" | "large" = "medium";
|
||||||
public alt = "Loading";
|
|
||||||
|
|
||||||
@property()
|
protected updated(changedProps: PropertyValues) {
|
||||||
public size: "tiny" | "small" | "medium" | "large" = "medium";
|
super.updated(changedProps);
|
||||||
|
|
||||||
// @ts-ignore
|
if (changedProps.has("size")) {
|
||||||
public set density(_) {
|
switch (this.size) {
|
||||||
// just a dummy
|
case "tiny":
|
||||||
}
|
this.style.setProperty("--md-circular-progress-size", "16px");
|
||||||
|
break;
|
||||||
public get density() {
|
case "small":
|
||||||
switch (this.size) {
|
this.style.setProperty("--md-circular-progress-size", "28px");
|
||||||
case "tiny":
|
break;
|
||||||
return -8;
|
// medium is default size
|
||||||
case "small":
|
case "medium":
|
||||||
return -5;
|
this.style.setProperty("--md-circular-progress-size", "48px");
|
||||||
case "medium":
|
break;
|
||||||
return 0;
|
case "large":
|
||||||
case "large":
|
this.style.setProperty("--md-circular-progress-size", "68px");
|
||||||
return 5;
|
break;
|
||||||
default:
|
}
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// @ts-ignore
|
static get styles(): CSSResult[] {
|
||||||
public set indeterminate(_) {
|
|
||||||
// just a dummy
|
|
||||||
}
|
|
||||||
|
|
||||||
public get indeterminate() {
|
|
||||||
return this.active;
|
|
||||||
}
|
|
||||||
|
|
||||||
static get styles(): CSSResultGroup {
|
|
||||||
return [
|
return [
|
||||||
super.styles,
|
...super.styles,
|
||||||
css`
|
css`
|
||||||
:host {
|
:host {
|
||||||
overflow: hidden;
|
--md-sys-color-primary: var(--primary-color);
|
||||||
|
--md-circular-progress-size: 48px;
|
||||||
}
|
}
|
||||||
`,
|
`,
|
||||||
];
|
];
|
||||||
|
@ -618,6 +618,7 @@ export class HaControlCircularSlider extends LitElement {
|
|||||||
--control-circular-slider-high-color: var(
|
--control-circular-slider-high-color: var(
|
||||||
--control-circular-slider-color
|
--control-circular-slider-color
|
||||||
);
|
);
|
||||||
|
--control-circular-slider-interaction-margin: 12px;
|
||||||
width: 320px;
|
width: 320px;
|
||||||
display: block;
|
display: block;
|
||||||
}
|
}
|
||||||
@ -633,7 +634,9 @@ export class HaControlCircularSlider extends LitElement {
|
|||||||
fill: none;
|
fill: none;
|
||||||
stroke: transparent;
|
stroke: transparent;
|
||||||
stroke-linecap: round;
|
stroke-linecap: round;
|
||||||
stroke-width: 48px;
|
stroke-width: calc(
|
||||||
|
24px + 2 * var(--control-circular-slider-interaction-margin)
|
||||||
|
);
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
#display {
|
#display {
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
import { ResizeController } from "@lit-labs/observers/resize-controller";
|
||||||
import { mdiMinus, mdiPlus } from "@mdi/js";
|
import { mdiMinus, mdiPlus } from "@mdi/js";
|
||||||
import {
|
import {
|
||||||
CSSResultGroup,
|
CSSResultGroup,
|
||||||
@ -49,6 +50,13 @@ export class HaControlNumberButton extends LitElement {
|
|||||||
|
|
||||||
@query("#input") _input!: HTMLDivElement;
|
@query("#input") _input!: HTMLDivElement;
|
||||||
|
|
||||||
|
private _hideUnit = new ResizeController(this, {
|
||||||
|
callback: (entries) => {
|
||||||
|
const width = entries[0]?.contentRect.width;
|
||||||
|
return width < 100;
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
private boundedValue(value: number) {
|
private boundedValue(value: number) {
|
||||||
const clamped = conditionalClamp(value, this.min, this.max);
|
const clamped = conditionalClamp(value, this.min, this.max);
|
||||||
return Math.round(clamped / this._step) * this._step;
|
return Math.round(clamped / this._step) * this._step;
|
||||||
@ -145,7 +153,10 @@ export class HaControlNumberButton extends LitElement {
|
|||||||
?disabled=${this.disabled}
|
?disabled=${this.disabled}
|
||||||
@keydown=${this._handleKeyDown}
|
@keydown=${this._handleKeyDown}
|
||||||
>
|
>
|
||||||
${value} ${unit ? html`<span class="unit">${unit}</span>` : nothing}
|
${value}
|
||||||
|
${unit && !this._hideUnit.value
|
||||||
|
? html`<span class="unit">${unit}</span>`
|
||||||
|
: nothing}
|
||||||
</div>
|
</div>
|
||||||
<button
|
<button
|
||||||
class="button minus"
|
class="button minus"
|
||||||
|
@ -6,6 +6,11 @@ import { MdOutlinedIconButton } from "@material/web/iconbutton/outlined-icon-but
|
|||||||
@customElement("ha-outlined-icon-button")
|
@customElement("ha-outlined-icon-button")
|
||||||
export class HaOutlinedIconButton extends MdOutlinedIconButton {
|
export class HaOutlinedIconButton extends MdOutlinedIconButton {
|
||||||
static override styles = [
|
static override styles = [
|
||||||
|
css`
|
||||||
|
.icon-button {
|
||||||
|
border-radius: var(--_container-shape);
|
||||||
|
}
|
||||||
|
`,
|
||||||
...super.styles,
|
...super.styles,
|
||||||
css`
|
css`
|
||||||
:host {
|
:host {
|
||||||
|
@ -1,9 +1,19 @@
|
|||||||
import { DEFAULT_SCHEMA, dump, load, Schema } from "js-yaml";
|
import { DEFAULT_SCHEMA, dump, load, Schema } from "js-yaml";
|
||||||
import { html, LitElement, nothing, PropertyValues } from "lit";
|
import {
|
||||||
|
CSSResultGroup,
|
||||||
|
css,
|
||||||
|
html,
|
||||||
|
LitElement,
|
||||||
|
nothing,
|
||||||
|
PropertyValues,
|
||||||
|
} from "lit";
|
||||||
import { customElement, property, state } from "lit/decorators";
|
import { customElement, property, state } from "lit/decorators";
|
||||||
import { fireEvent } from "../common/dom/fire_event";
|
import { fireEvent } from "../common/dom/fire_event";
|
||||||
import type { HomeAssistant } from "../types";
|
import type { HomeAssistant } from "../types";
|
||||||
|
import { haStyle } from "../resources/styles";
|
||||||
import "./ha-code-editor";
|
import "./ha-code-editor";
|
||||||
|
import { showToast } from "../util/toast";
|
||||||
|
import { copyToClipboard } from "../common/util/copy-clipboard";
|
||||||
|
|
||||||
const isEmpty = (obj: Record<string, unknown>): boolean => {
|
const isEmpty = (obj: Record<string, unknown>): boolean => {
|
||||||
if (typeof obj !== "object") {
|
if (typeof obj !== "object") {
|
||||||
@ -37,6 +47,8 @@ export class HaYamlEditor extends LitElement {
|
|||||||
|
|
||||||
@property({ type: Boolean }) public required = false;
|
@property({ type: Boolean }) public required = false;
|
||||||
|
|
||||||
|
@property({ type: Boolean }) public copyClipboard = false;
|
||||||
|
|
||||||
@state() private _yaml = "";
|
@state() private _yaml = "";
|
||||||
|
|
||||||
public setValue(value): void {
|
public setValue(value): void {
|
||||||
@ -88,6 +100,15 @@ export class HaYamlEditor extends LitElement {
|
|||||||
@value-changed=${this._onChange}
|
@value-changed=${this._onChange}
|
||||||
dir="ltr"
|
dir="ltr"
|
||||||
></ha-code-editor>
|
></ha-code-editor>
|
||||||
|
${this.copyClipboard
|
||||||
|
? html`<div class="card-actions">
|
||||||
|
<mwc-button @click=${this._copyYaml}>
|
||||||
|
${this.hass.localize(
|
||||||
|
"ui.components.yaml-editor.copy_to_clipboard"
|
||||||
|
)}
|
||||||
|
</mwc-button>
|
||||||
|
</div>`
|
||||||
|
: nothing}
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -117,6 +138,35 @@ export class HaYamlEditor extends LitElement {
|
|||||||
get yaml() {
|
get yaml() {
|
||||||
return this._yaml;
|
return this._yaml;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async _copyYaml(): Promise<void> {
|
||||||
|
if (this.yaml) {
|
||||||
|
await copyToClipboard(this.yaml);
|
||||||
|
showToast(this, {
|
||||||
|
message: this.hass.localize("ui.common.copied_clipboard"),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static get styles(): CSSResultGroup {
|
||||||
|
return [
|
||||||
|
haStyle,
|
||||||
|
css`
|
||||||
|
.card-actions {
|
||||||
|
border-radius: var(
|
||||||
|
--actions-border-radius,
|
||||||
|
0px 0px var(--ha-card-border-radius, 12px)
|
||||||
|
var(--ha-card-border-radius, 12px)
|
||||||
|
);
|
||||||
|
border: 1px solid var(--divider-color);
|
||||||
|
padding: 5px 16px;
|
||||||
|
}
|
||||||
|
ha-code-editor {
|
||||||
|
flex-grow: 1;
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
declare global {
|
declare global {
|
||||||
|
@ -147,7 +147,7 @@ class DialogMediaManage extends LitElement {
|
|||||||
${!this._currentItem
|
${!this._currentItem
|
||||||
? html`
|
? html`
|
||||||
<div class="refresh">
|
<div class="refresh">
|
||||||
<ha-circular-progress active></ha-circular-progress>
|
<ha-circular-progress indeterminate></ha-circular-progress>
|
||||||
</div>
|
</div>
|
||||||
`
|
`
|
||||||
: !children.length
|
: !children.length
|
||||||
|
@ -332,7 +332,7 @@ export class HaMediaPlayerBrowse extends LitElement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!this._currentItem) {
|
if (!this._currentItem) {
|
||||||
return html`<ha-circular-progress active></ha-circular-progress>`;
|
return html`<ha-circular-progress indeterminate></ha-circular-progress>`;
|
||||||
}
|
}
|
||||||
|
|
||||||
const currentItem = this._currentItem;
|
const currentItem = this._currentItem;
|
||||||
|
@ -54,8 +54,8 @@ class MediaUploadButton extends LitElement {
|
|||||||
? html`
|
? html`
|
||||||
<ha-circular-progress
|
<ha-circular-progress
|
||||||
size="tiny"
|
size="tiny"
|
||||||
active
|
indeterminate
|
||||||
alt=""
|
area-label="Uploading"
|
||||||
slot="icon"
|
slot="icon"
|
||||||
></ha-circular-progress>
|
></ha-circular-progress>
|
||||||
`
|
`
|
||||||
|
@ -2,6 +2,7 @@ import {
|
|||||||
HassEntityAttributeBase,
|
HassEntityAttributeBase,
|
||||||
HassEntityBase,
|
HassEntityBase,
|
||||||
} from "home-assistant-js-websocket";
|
} from "home-assistant-js-websocket";
|
||||||
|
import { getExtendedEntityRegistryEntry } from "./entity_registry";
|
||||||
import { showEnterCodeDialogDialog } from "../dialogs/enter-code/show-enter-code-dialog";
|
import { showEnterCodeDialogDialog } from "../dialogs/enter-code/show-enter-code-dialog";
|
||||||
import { HomeAssistant } from "../types";
|
import { HomeAssistant } from "../types";
|
||||||
|
|
||||||
@ -30,15 +31,20 @@ export const callProtectedLockService = async (
|
|||||||
service: ProtectedLockService
|
service: ProtectedLockService
|
||||||
) => {
|
) => {
|
||||||
let code: string | undefined;
|
let code: string | undefined;
|
||||||
|
const lockRegistryEntry = await getExtendedEntityRegistryEntry(
|
||||||
|
hass,
|
||||||
|
stateObj.entity_id
|
||||||
|
).catch(() => undefined);
|
||||||
|
const defaultCode = lockRegistryEntry?.options?.lock?.default_code;
|
||||||
|
|
||||||
if (stateObj!.attributes.code_format) {
|
if (stateObj!.attributes.code_format && !defaultCode) {
|
||||||
const response = await showEnterCodeDialogDialog(element, {
|
const response = await showEnterCodeDialogDialog(element, {
|
||||||
codeFormat: "text",
|
codeFormat: "text",
|
||||||
codePattern: stateObj!.attributes.code_format,
|
codePattern: stateObj!.attributes.code_format,
|
||||||
title: hass.localize(`ui.card.lock.${service}`),
|
title: hass.localize(`ui.card.lock.${service}`),
|
||||||
submitText: hass.localize(`ui.card.lock.${service}`),
|
submitText: hass.localize(`ui.card.lock.${service}`),
|
||||||
});
|
});
|
||||||
if (!response) {
|
if (response == null) {
|
||||||
throw new Error("Code dialog closed");
|
throw new Error("Code dialog closed");
|
||||||
}
|
}
|
||||||
code = response;
|
code = response;
|
||||||
|
@ -207,7 +207,7 @@ export class DialogAreaFilter
|
|||||||
color: var(--disabled-text-color);
|
color: var(--disabled-text-color);
|
||||||
}
|
}
|
||||||
.handle {
|
.handle {
|
||||||
cursor: grab;
|
cursor: move;
|
||||||
}
|
}
|
||||||
.actions {
|
.actions {
|
||||||
display: flex;
|
display: flex;
|
||||||
|
@ -90,7 +90,7 @@ class StepFlowForm extends LitElement {
|
|||||||
${this._loading
|
${this._loading
|
||||||
? html`
|
? html`
|
||||||
<div class="submit-spinner">
|
<div class="submit-spinner">
|
||||||
<ha-circular-progress active></ha-circular-progress>
|
<ha-circular-progress indeterminate></ha-circular-progress>
|
||||||
</div>
|
</div>
|
||||||
`
|
`
|
||||||
: html`
|
: html`
|
||||||
|
@ -27,7 +27,7 @@ class StepFlowLoading extends LitElement {
|
|||||||
return html`
|
return html`
|
||||||
<div class="init-spinner">
|
<div class="init-spinner">
|
||||||
${description ? html`<div>${description}</div>` : ""}
|
${description ? html`<div>${description}</div>` : ""}
|
||||||
<ha-circular-progress active></ha-circular-progress>
|
<ha-circular-progress indeterminate></ha-circular-progress>
|
||||||
</div>
|
</div>
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
@ -24,7 +24,7 @@ class StepFlowProgress extends LitElement {
|
|||||||
${this.flowConfig.renderShowFormProgressHeader(this.hass, this.step)}
|
${this.flowConfig.renderShowFormProgressHeader(this.hass, this.step)}
|
||||||
</h2>
|
</h2>
|
||||||
<div class="content">
|
<div class="content">
|
||||||
<ha-circular-progress active></ha-circular-progress>
|
<ha-circular-progress indeterminate></ha-circular-progress>
|
||||||
${this.flowConfig.renderShowFormProgressDescription(
|
${this.flowConfig.renderShowFormProgressDescription(
|
||||||
this.hass,
|
this.hass,
|
||||||
this.step
|
this.step
|
||||||
|
@ -99,6 +99,8 @@ export class DialogEnterCode
|
|||||||
id="code"
|
id="code"
|
||||||
.label=${this.hass.localize("ui.dialogs.enter_code.input_label")}
|
.label=${this.hass.localize("ui.dialogs.enter_code.input_label")}
|
||||||
type="password"
|
type="password"
|
||||||
|
autoValidate
|
||||||
|
validateOnInitialRender
|
||||||
pattern=${ifDefined(this._dialogParams.codePattern)}
|
pattern=${ifDefined(this._dialogParams.codePattern)}
|
||||||
inputmode="text"
|
inputmode="text"
|
||||||
></ha-textfield>
|
></ha-textfield>
|
||||||
|
@ -53,8 +53,8 @@ export class MoreInfoConfigurator extends LitElement {
|
|||||||
>
|
>
|
||||||
${this._isConfiguring
|
${this._isConfiguring
|
||||||
? html`<ha-circular-progress
|
? html`<ha-circular-progress
|
||||||
active
|
indeterminate
|
||||||
alt="Configuring"
|
aria-label="Configuring"
|
||||||
></ha-circular-progress>`
|
></ha-circular-progress>`
|
||||||
: ""}
|
: ""}
|
||||||
${this.stateObj.attributes.submit_caption}
|
${this.stateObj.attributes.submit_caption}
|
||||||
|
@ -104,7 +104,7 @@ class MoreInfoUpdate extends LitElement {
|
|||||||
${supportsFeature(this.stateObj!, UPDATE_SUPPORT_RELEASE_NOTES) &&
|
${supportsFeature(this.stateObj!, UPDATE_SUPPORT_RELEASE_NOTES) &&
|
||||||
!this._error
|
!this._error
|
||||||
? this._releaseNotes === undefined
|
? this._releaseNotes === undefined
|
||||||
? html`<ha-circular-progress active></ha-circular-progress>`
|
? html`<ha-circular-progress indeterminate></ha-circular-progress>`
|
||||||
: html`<hr />
|
: html`<hr />
|
||||||
<ha-faded>
|
<ha-faded>
|
||||||
<ha-markdown .content=${this._releaseNotes}></ha-markdown>
|
<ha-markdown .content=${this._releaseNotes}></ha-markdown>
|
||||||
|
@ -214,7 +214,7 @@ export class QuickBar extends LitElement {
|
|||||||
${!items
|
${!items
|
||||||
? html`<ha-circular-progress
|
? html`<ha-circular-progress
|
||||||
size="small"
|
size="small"
|
||||||
active
|
indeterminate
|
||||||
></ha-circular-progress>`
|
></ha-circular-progress>`
|
||||||
: items.length === 0
|
: items.length === 0
|
||||||
? html`
|
? html`
|
||||||
@ -375,7 +375,7 @@ export class QuickBar extends LitElement {
|
|||||||
const spinner = document.createElement("ha-circular-progress");
|
const spinner = document.createElement("ha-circular-progress");
|
||||||
spinner.size = "small";
|
spinner.size = "small";
|
||||||
spinner.slot = "meta";
|
spinner.slot = "meta";
|
||||||
spinner.active = true;
|
spinner.indeterminate = true;
|
||||||
this._getItemAtIndex(index)?.appendChild(spinner);
|
this._getItemAtIndex(index)?.appendChild(spinner);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -91,7 +91,7 @@ class DialogRestart extends LitElement {
|
|||||||
${this._loadingHostInfo
|
${this._loadingHostInfo
|
||||||
? html`
|
? html`
|
||||||
<div class="loader">
|
<div class="loader">
|
||||||
<ha-circular-progress active></ha-circular-progress>
|
<ha-circular-progress indeterminate></ha-circular-progress>
|
||||||
</div>
|
</div>
|
||||||
`
|
`
|
||||||
: html`
|
: html`
|
||||||
|
@ -85,8 +85,7 @@ export class TTSTryDialog extends LitElement {
|
|||||||
? html`
|
? html`
|
||||||
<ha-circular-progress
|
<ha-circular-progress
|
||||||
size="small"
|
size="small"
|
||||||
active
|
indeterminate
|
||||||
alt=""
|
|
||||||
slot="primaryAction"
|
slot="primaryAction"
|
||||||
class="loading"
|
class="loading"
|
||||||
></ha-circular-progress>
|
></ha-circular-progress>
|
||||||
|
@ -35,7 +35,7 @@ class HaInitPage extends LitElement {
|
|||||||
`
|
`
|
||||||
: html`
|
: html`
|
||||||
<div id="progress-indicator-wrapper">
|
<div id="progress-indicator-wrapper">
|
||||||
<ha-circular-progress active></ha-circular-progress>
|
<ha-circular-progress indeterminate></ha-circular-progress>
|
||||||
</div>
|
</div>
|
||||||
<div id="loading-text">
|
<div id="loading-text">
|
||||||
${this.migration
|
${this.migration
|
||||||
|
@ -46,7 +46,7 @@ class HassLoadingScreen extends LitElement {
|
|||||||
`}
|
`}
|
||||||
</div>`}
|
</div>`}
|
||||||
<div class="content">
|
<div class="content">
|
||||||
<ha-circular-progress active></ha-circular-progress>
|
<ha-circular-progress indeterminate></ha-circular-progress>
|
||||||
${this.message
|
${this.message
|
||||||
? html`<div id="loading-text">${this.message}</div>`
|
? html`<div id="loading-text">${this.message}</div>`
|
||||||
: nothing}
|
: nothing}
|
||||||
|
@ -57,7 +57,7 @@ class OnboardingCoreConfig extends LitElement {
|
|||||||
}
|
}
|
||||||
if (this._skipCore) {
|
if (this._skipCore) {
|
||||||
return html`<div class="row center">
|
return html`<div class="row center">
|
||||||
<ha-circular-progress active></ha-circular-progress>
|
<ha-circular-progress indeterminate></ha-circular-progress>
|
||||||
</div>`;
|
</div>`;
|
||||||
}
|
}
|
||||||
return html`
|
return html`
|
||||||
|
@ -123,7 +123,7 @@ class OnboardingLocation extends LitElement {
|
|||||||
? html`
|
? html`
|
||||||
<ha-circular-progress
|
<ha-circular-progress
|
||||||
slot="trailingIcon"
|
slot="trailingIcon"
|
||||||
active
|
indeterminate
|
||||||
size="small"
|
size="small"
|
||||||
></ha-circular-progress>
|
></ha-circular-progress>
|
||||||
`
|
`
|
||||||
|
@ -64,8 +64,7 @@ class PanelCalendar extends LitElement {
|
|||||||
private _end?: Date;
|
private _end?: Date;
|
||||||
|
|
||||||
private _showPaneController = new ResizeController(this, {
|
private _showPaneController = new ResizeController(this, {
|
||||||
callback: (entries: ResizeObserverEntry[]) =>
|
callback: (entries) => entries[0]?.contentRect.width > 750,
|
||||||
entries[0]?.contentRect.width > 750,
|
|
||||||
});
|
});
|
||||||
|
|
||||||
private _mql?: MediaQueryList;
|
private _mql?: MediaQueryList;
|
||||||
|
@ -227,7 +227,7 @@ export class DialogAddApplicationCredential extends LitElement {
|
|||||||
${this._loading
|
${this._loading
|
||||||
? html`
|
? html`
|
||||||
<div slot="primaryAction" class="submit-spinner">
|
<div slot="primaryAction" class="submit-spinner">
|
||||||
<ha-circular-progress active></ha-circular-progress>
|
<ha-circular-progress indeterminate></ha-circular-progress>
|
||||||
</div>
|
</div>
|
||||||
`
|
`
|
||||||
: html`
|
: html`
|
||||||
|
@ -101,7 +101,7 @@ export class HaBlueprintAutomationEditor extends LitElement {
|
|||||||
: this.hass.localize(
|
: this.hass.localize(
|
||||||
"ui.panel.config.automation.editor.blueprint.no_blueprints"
|
"ui.panel.config.automation.editor.blueprint.no_blueprints"
|
||||||
)
|
)
|
||||||
: html`<ha-circular-progress active></ha-circular-progress>`}
|
: html`<ha-circular-progress indeterminate></ha-circular-progress>`}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
${this.config.use_blueprint.path
|
${this.config.use_blueprint.path
|
||||||
|
@ -25,19 +25,16 @@ import {
|
|||||||
html,
|
html,
|
||||||
nothing,
|
nothing,
|
||||||
} from "lit";
|
} from "lit";
|
||||||
import { property, query, state } from "lit/decorators";
|
import { property, state } from "lit/decorators";
|
||||||
import { classMap } from "lit/directives/class-map";
|
import { classMap } from "lit/directives/class-map";
|
||||||
import { fireEvent } from "../../../common/dom/fire_event";
|
import { fireEvent } from "../../../common/dom/fire_event";
|
||||||
import { navigate } from "../../../common/navigate";
|
import { navigate } from "../../../common/navigate";
|
||||||
import { copyToClipboard } from "../../../common/util/copy-clipboard";
|
|
||||||
import { afterNextRender } from "../../../common/util/render-status";
|
import { afterNextRender } from "../../../common/util/render-status";
|
||||||
import "../../../components/ha-button-menu";
|
import "../../../components/ha-button-menu";
|
||||||
import "../../../components/ha-card";
|
|
||||||
import "../../../components/ha-fab";
|
import "../../../components/ha-fab";
|
||||||
import "../../../components/ha-icon-button";
|
import "../../../components/ha-icon-button";
|
||||||
import "../../../components/ha-svg-icon";
|
import "../../../components/ha-svg-icon";
|
||||||
import "../../../components/ha-yaml-editor";
|
import "../../../components/ha-yaml-editor";
|
||||||
import type { HaYamlEditor } from "../../../components/ha-yaml-editor";
|
|
||||||
import {
|
import {
|
||||||
AutomationConfig,
|
AutomationConfig,
|
||||||
AutomationEntity,
|
AutomationEntity,
|
||||||
@ -112,8 +109,6 @@ export class HaAutomationEditor extends KeyboardShortcutMixin(LitElement) {
|
|||||||
|
|
||||||
@state() private _validationErrors?: (string | TemplateResult)[];
|
@state() private _validationErrors?: (string | TemplateResult)[];
|
||||||
|
|
||||||
@query("ha-yaml-editor", true) private _yamlEditor?: HaYamlEditor;
|
|
||||||
|
|
||||||
private _configSubscriptions: Record<
|
private _configSubscriptions: Record<
|
||||||
string,
|
string,
|
||||||
(config?: AutomationConfig) => void
|
(config?: AutomationConfig) => void
|
||||||
@ -342,8 +337,7 @@ export class HaAutomationEditor extends KeyboardShortcutMixin(LitElement) {
|
|||||||
></manual-automation-editor>
|
></manual-automation-editor>
|
||||||
`
|
`
|
||||||
: this._mode === "yaml"
|
: this._mode === "yaml"
|
||||||
? html`
|
? html` ${this._readOnly
|
||||||
${this._readOnly
|
|
||||||
? html`<ha-alert alert-type="warning">
|
? html`<ha-alert alert-type="warning">
|
||||||
${this.hass.localize(
|
${this.hass.localize(
|
||||||
"ui.panel.config.automation.editor.read_only"
|
"ui.panel.config.automation.editor.read_only"
|
||||||
@ -376,22 +370,13 @@ export class HaAutomationEditor extends KeyboardShortcutMixin(LitElement) {
|
|||||||
`
|
`
|
||||||
: ""}
|
: ""}
|
||||||
<ha-yaml-editor
|
<ha-yaml-editor
|
||||||
|
copyClipboard
|
||||||
.hass=${this.hass}
|
.hass=${this.hass}
|
||||||
.defaultValue=${this._preprocessYaml()}
|
.defaultValue=${this._preprocessYaml()}
|
||||||
.readOnly=${this._readOnly}
|
.readOnly=${this._readOnly}
|
||||||
@value-changed=${this._yamlChanged}
|
@value-changed=${this._yamlChanged}
|
||||||
></ha-yaml-editor>
|
></ha-yaml-editor>`
|
||||||
<ha-card outlined>
|
: nothing}
|
||||||
<div class="card-actions">
|
|
||||||
<mwc-button @click=${this._copyYaml}>
|
|
||||||
${this.hass.localize(
|
|
||||||
"ui.panel.config.automation.editor.copy_to_clipboard"
|
|
||||||
)}
|
|
||||||
</mwc-button>
|
|
||||||
</div>
|
|
||||||
</ha-card>
|
|
||||||
`
|
|
||||||
: ``}
|
|
||||||
</div>
|
</div>
|
||||||
`
|
`
|
||||||
: ""}
|
: ""}
|
||||||
@ -612,15 +597,6 @@ export class HaAutomationEditor extends KeyboardShortcutMixin(LitElement) {
|
|||||||
return cleanConfig;
|
return cleanConfig;
|
||||||
}
|
}
|
||||||
|
|
||||||
private async _copyYaml(): Promise<void> {
|
|
||||||
if (this._yamlEditor?.yaml) {
|
|
||||||
await copyToClipboard(this._yamlEditor.yaml);
|
|
||||||
showToast(this, {
|
|
||||||
message: this.hass.localize("ui.common.copied_clipboard"),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private _yamlChanged(ev: CustomEvent) {
|
private _yamlChanged(ev: CustomEvent) {
|
||||||
ev.stopPropagation();
|
ev.stopPropagation();
|
||||||
if (!ev.detail.isValid) {
|
if (!ev.detail.isValid) {
|
||||||
@ -776,9 +752,6 @@ export class HaAutomationEditor extends KeyboardShortcutMixin(LitElement) {
|
|||||||
return [
|
return [
|
||||||
haStyle,
|
haStyle,
|
||||||
css`
|
css`
|
||||||
ha-card {
|
|
||||||
overflow: hidden;
|
|
||||||
}
|
|
||||||
.content {
|
.content {
|
||||||
padding-bottom: 20px;
|
padding-bottom: 20px;
|
||||||
}
|
}
|
||||||
@ -796,13 +769,11 @@ export class HaAutomationEditor extends KeyboardShortcutMixin(LitElement) {
|
|||||||
}
|
}
|
||||||
ha-yaml-editor {
|
ha-yaml-editor {
|
||||||
flex-grow: 1;
|
flex-grow: 1;
|
||||||
|
--actions-border-radius: 0;
|
||||||
--code-mirror-height: 100%;
|
--code-mirror-height: 100%;
|
||||||
min-height: 0;
|
min-height: 0;
|
||||||
}
|
display: flex;
|
||||||
.yaml-mode ha-card {
|
flex-direction: column;
|
||||||
overflow: initial;
|
|
||||||
--ha-card-border-radius: 0;
|
|
||||||
border-bottom: 1px solid var(--divider-color);
|
|
||||||
}
|
}
|
||||||
p {
|
p {
|
||||||
margin-bottom: 0;
|
margin-bottom: 0;
|
||||||
|
@ -158,7 +158,7 @@ class HaConfigBackup extends LitElement {
|
|||||||
${this._backupData.backing_up
|
${this._backupData.backing_up
|
||||||
? html`<ha-circular-progress
|
? html`<ha-circular-progress
|
||||||
slot="icon"
|
slot="icon"
|
||||||
active
|
indeterminate
|
||||||
></ha-circular-progress>`
|
></ha-circular-progress>`
|
||||||
: html`<ha-svg-icon slot="icon" .path=${mdiPlus}></ha-svg-icon>`}
|
: html`<ha-svg-icon slot="icon" .path=${mdiPlus}></ha-svg-icon>`}
|
||||||
</ha-fab>
|
</ha-fab>
|
||||||
|
@ -163,9 +163,9 @@ class DialogImportBlueprint extends LitElement {
|
|||||||
>
|
>
|
||||||
${this._importing
|
${this._importing
|
||||||
? html`<ha-circular-progress
|
? html`<ha-circular-progress
|
||||||
active
|
indeterminate
|
||||||
size="small"
|
size="small"
|
||||||
.title=${this.hass.localize(
|
.ariaLabel=${this.hass.localize(
|
||||||
"ui.panel.config.blueprint.add.importing"
|
"ui.panel.config.blueprint.add.importing"
|
||||||
)}
|
)}
|
||||||
></ha-circular-progress>`
|
></ha-circular-progress>`
|
||||||
@ -183,9 +183,9 @@ class DialogImportBlueprint extends LitElement {
|
|||||||
>
|
>
|
||||||
${this._saving
|
${this._saving
|
||||||
? html`<ha-circular-progress
|
? html`<ha-circular-progress
|
||||||
active
|
indeterminate
|
||||||
size="small"
|
size="small"
|
||||||
.title=${this.hass.localize(
|
.ariaLabel=${this.hass.localize(
|
||||||
"ui.panel.config.blueprint.add.saving"
|
"ui.panel.config.blueprint.add.saving"
|
||||||
)}
|
)}
|
||||||
></ha-circular-progress>`
|
></ha-circular-progress>`
|
||||||
|
@ -93,7 +93,7 @@ export class CloudWebhooks extends LitElement {
|
|||||||
? html`
|
? html`
|
||||||
<div class="progress">
|
<div class="progress">
|
||||||
<ha-circular-progress
|
<ha-circular-progress
|
||||||
active
|
indeterminate
|
||||||
></ha-circular-progress>
|
></ha-circular-progress>
|
||||||
</div>
|
</div>
|
||||||
`
|
`
|
||||||
|
@ -108,7 +108,7 @@ class HaConfigUpdates extends SubscribeMixin(LitElement) {
|
|||||||
></state-badge>
|
></state-badge>
|
||||||
${this.narrow && entity.attributes.in_progress
|
${this.narrow && entity.attributes.in_progress
|
||||||
? html`<ha-circular-progress
|
? html`<ha-circular-progress
|
||||||
active
|
indeterminate
|
||||||
size="small"
|
size="small"
|
||||||
slot="graphic"
|
slot="graphic"
|
||||||
class="absolute"
|
class="absolute"
|
||||||
@ -128,7 +128,7 @@ class HaConfigUpdates extends SubscribeMixin(LitElement) {
|
|||||||
${!this.narrow
|
${!this.narrow
|
||||||
? entity.attributes.in_progress
|
? entity.attributes.in_progress
|
||||||
? html`<ha-circular-progress
|
? html`<ha-circular-progress
|
||||||
active
|
indeterminate
|
||||||
size="small"
|
size="small"
|
||||||
slot="meta"
|
slot="meta"
|
||||||
></ha-circular-progress>`
|
></ha-circular-progress>`
|
||||||
|
@ -164,7 +164,9 @@ export class DialogHelperDetail extends LitElement {
|
|||||||
</mwc-button>
|
</mwc-button>
|
||||||
`;
|
`;
|
||||||
} else if (this._loading || this._helperFlows === undefined) {
|
} else if (this._loading || this._helperFlows === undefined) {
|
||||||
content = html`<ha-circular-progress active></ha-circular-progress>`;
|
content = html`<ha-circular-progress
|
||||||
|
indeterminate
|
||||||
|
></ha-circular-progress>`;
|
||||||
} else {
|
} else {
|
||||||
const items: [string, string][] = [];
|
const items: [string, string][] = [];
|
||||||
|
|
||||||
|
@ -449,7 +449,7 @@ class AddIntegrationDialog extends LitElement {
|
|||||||
>
|
>
|
||||||
</lit-virtualizer>
|
</lit-virtualizer>
|
||||||
</mwc-list>`
|
</mwc-list>`
|
||||||
: html`<ha-circular-progress active></ha-circular-progress>`} `;
|
: html`<ha-circular-progress indeterminate></ha-circular-progress>`} `;
|
||||||
}
|
}
|
||||||
|
|
||||||
private _keyFunction = (integration: IntegrationListItem) =>
|
private _keyFunction = (integration: IntegrationListItem) =>
|
||||||
|
@ -57,7 +57,7 @@ class DialogMatterAddDevice extends LitElement {
|
|||||||
)
|
)
|
||||||
: html`<ha-circular-progress
|
: html`<ha-circular-progress
|
||||||
size="large"
|
size="large"
|
||||||
active
|
indeterminate
|
||||||
></ha-circular-progress>`}
|
></ha-circular-progress>`}
|
||||||
</div>
|
</div>
|
||||||
<mwc-button slot="primaryAction" @click=${this.closeDialog}>
|
<mwc-button slot="primaryAction" @click=${this.closeDialog}>
|
||||||
|
@ -102,7 +102,7 @@ class DialogZHAReconfigureDevice extends LitElement {
|
|||||||
${this._status === "started"
|
${this._status === "started"
|
||||||
? html`
|
? html`
|
||||||
<div class="flex-container">
|
<div class="flex-container">
|
||||||
<ha-circular-progress active></ha-circular-progress>
|
<ha-circular-progress indeterminate></ha-circular-progress>
|
||||||
<div class="status">
|
<div class="status">
|
||||||
<p>
|
<p>
|
||||||
<b>
|
<b>
|
||||||
|
@ -98,8 +98,8 @@ class ZHAAddDevicesPage extends LitElement {
|
|||||||
)}
|
)}
|
||||||
</h1>
|
</h1>
|
||||||
<ha-circular-progress
|
<ha-circular-progress
|
||||||
active
|
indeterminate
|
||||||
alt="Searching"
|
aria-label="Searching"
|
||||||
></ha-circular-progress>
|
></ha-circular-progress>
|
||||||
`
|
`
|
||||||
: html`
|
: html`
|
||||||
|
@ -98,9 +98,9 @@ export class ZHAAddGroupPage extends LitElement {
|
|||||||
>
|
>
|
||||||
${this._processingAdd
|
${this._processingAdd
|
||||||
? html`<ha-circular-progress
|
? html`<ha-circular-progress
|
||||||
active
|
indeterminate
|
||||||
size="small"
|
size="small"
|
||||||
.title=${this.hass!.localize(
|
.ariaLabel=${this.hass!.localize(
|
||||||
"ui.panel.config.zha.groups.creating_group"
|
"ui.panel.config.zha.groups.creating_group"
|
||||||
)}
|
)}
|
||||||
></ha-circular-progress>`
|
></ha-circular-progress>`
|
||||||
|
@ -120,9 +120,8 @@ class ZHADeviceNeighbors extends LitElement {
|
|||||||
return html`
|
return html`
|
||||||
${!this._devices
|
${!this._devices
|
||||||
? html`<ha-circular-progress
|
? html`<ha-circular-progress
|
||||||
alt="Loading"
|
|
||||||
size="large"
|
size="large"
|
||||||
active
|
indeterminate
|
||||||
></ha-circular-progress>`
|
></ha-circular-progress>`
|
||||||
: html`<ha-data-table
|
: html`<ha-data-table
|
||||||
.hass=${this.hass}
|
.hass=${this.hass}
|
||||||
|
@ -169,12 +169,14 @@ export class ZHAGroupPage extends LitElement {
|
|||||||
@click=${this._removeMembersFromGroup}
|
@click=${this._removeMembersFromGroup}
|
||||||
class="button"
|
class="button"
|
||||||
>
|
>
|
||||||
<ha-circular-progress
|
${this._processingRemove
|
||||||
?active=${this._processingRemove}
|
? html`<ha-circular-progress
|
||||||
alt=${this.hass.localize(
|
indeterminate
|
||||||
"ui.panel.config.zha.groups.removing_members"
|
.ariaLabel=${this.hass.localize(
|
||||||
)}
|
"ui.panel.config.zha.groups.removing_members"
|
||||||
></ha-circular-progress>
|
)}
|
||||||
|
></ha-circular-progress>`
|
||||||
|
: nothing}
|
||||||
${this.hass!.localize(
|
${this.hass!.localize(
|
||||||
"ui.panel.config.zha.groups.remove_members"
|
"ui.panel.config.zha.groups.remove_members"
|
||||||
)}</mwc-button
|
)}</mwc-button
|
||||||
@ -208,7 +210,7 @@ export class ZHAGroupPage extends LitElement {
|
|||||||
? html`<ha-circular-progress
|
? html`<ha-circular-progress
|
||||||
active
|
active
|
||||||
size="small"
|
size="small"
|
||||||
title="Saving"
|
aria-label="Saving"
|
||||||
></ha-circular-progress>`
|
></ha-circular-progress>`
|
||||||
: ""}
|
: ""}
|
||||||
${this.hass!.localize(
|
${this.hass!.localize(
|
||||||
|
@ -116,7 +116,10 @@ class DialogZWaveJSAddNode extends LitElement {
|
|||||||
>
|
>
|
||||||
${this._status === "loading"
|
${this._status === "loading"
|
||||||
? html`<div style="display: flex; justify-content: center;">
|
? html`<div style="display: flex; justify-content: center;">
|
||||||
<ha-circular-progress size="large" active></ha-circular-progress>
|
<ha-circular-progress
|
||||||
|
size="large"
|
||||||
|
indeterminate
|
||||||
|
></ha-circular-progress>
|
||||||
</div>`
|
</div>`
|
||||||
: this._status === "choose_strategy"
|
: this._status === "choose_strategy"
|
||||||
? html`<h3>Choose strategy</h3>
|
? html`<h3>Choose strategy</h3>
|
||||||
@ -288,7 +291,9 @@ class DialogZWaveJSAddNode extends LitElement {
|
|||||||
"ui.panel.config.zwave_js.add_node.searching_device"
|
"ui.panel.config.zwave_js.add_node.searching_device"
|
||||||
)}
|
)}
|
||||||
</h3>
|
</h3>
|
||||||
<ha-circular-progress active></ha-circular-progress>
|
<ha-circular-progress
|
||||||
|
indeterminate
|
||||||
|
></ha-circular-progress>
|
||||||
<p>
|
<p>
|
||||||
${this.hass.localize(
|
${this.hass.localize(
|
||||||
"ui.panel.config.zwave_js.add_node.follow_device_instructions"
|
"ui.panel.config.zwave_js.add_node.follow_device_instructions"
|
||||||
@ -304,7 +309,7 @@ class DialogZWaveJSAddNode extends LitElement {
|
|||||||
)}
|
)}
|
||||||
</h2>
|
</h2>
|
||||||
<ha-circular-progress
|
<ha-circular-progress
|
||||||
active
|
indeterminate
|
||||||
></ha-circular-progress>
|
></ha-circular-progress>
|
||||||
<p>
|
<p>
|
||||||
${this.hass.localize(
|
${this.hass.localize(
|
||||||
@ -358,7 +363,7 @@ class DialogZWaveJSAddNode extends LitElement {
|
|||||||
? html`
|
? html`
|
||||||
<div class="flex-container">
|
<div class="flex-container">
|
||||||
<ha-circular-progress
|
<ha-circular-progress
|
||||||
active
|
indeterminate
|
||||||
></ha-circular-progress>
|
></ha-circular-progress>
|
||||||
<div class="status">
|
<div class="status">
|
||||||
<p>
|
<p>
|
||||||
|
@ -97,7 +97,7 @@ class DialogZWaveJSRebuildNodeRoutes extends LitElement {
|
|||||||
${this._status === "started"
|
${this._status === "started"
|
||||||
? html`
|
? html`
|
||||||
<div class="flex-container">
|
<div class="flex-container">
|
||||||
<ha-circular-progress active></ha-circular-progress>
|
<ha-circular-progress indeterminate></ha-circular-progress>
|
||||||
<div class="status">
|
<div class="status">
|
||||||
<p>
|
<p>
|
||||||
${this.hass.localize(
|
${this.hass.localize(
|
||||||
|
@ -68,7 +68,7 @@ class DialogZWaveJSReinterviewNode extends LitElement {
|
|||||||
${this._status === "started"
|
${this._status === "started"
|
||||||
? html`
|
? html`
|
||||||
<div class="flex-container">
|
<div class="flex-container">
|
||||||
<ha-circular-progress active></ha-circular-progress>
|
<ha-circular-progress indeterminate></ha-circular-progress>
|
||||||
<div class="status">
|
<div class="status">
|
||||||
<p>
|
<p>
|
||||||
<b>
|
<b>
|
||||||
|
@ -91,7 +91,7 @@ class DialogZWaveJSRemoveFailedNode extends LitElement {
|
|||||||
${this._status === "started"
|
${this._status === "started"
|
||||||
? html`
|
? html`
|
||||||
<div class="flex-container">
|
<div class="flex-container">
|
||||||
<ha-circular-progress active></ha-circular-progress>
|
<ha-circular-progress indeterminate></ha-circular-progress>
|
||||||
<div class="status">
|
<div class="status">
|
||||||
<p>
|
<p>
|
||||||
<b>
|
<b>
|
||||||
|
@ -71,7 +71,7 @@ class DialogZWaveJSRemoveNode extends LitElement {
|
|||||||
${this._status === "started"
|
${this._status === "started"
|
||||||
? html`
|
? html`
|
||||||
<div class="flex-container">
|
<div class="flex-container">
|
||||||
<ha-circular-progress active></ha-circular-progress>
|
<ha-circular-progress indeterminate></ha-circular-progress>
|
||||||
<div class="status">
|
<div class="status">
|
||||||
<p>
|
<p>
|
||||||
<b
|
<b
|
||||||
|
@ -171,7 +171,7 @@ class ZWaveJSConfigDashboard extends SubscribeMixin(LitElement) {
|
|||||||
<div class="icon">
|
<div class="icon">
|
||||||
${this._status === "disconnected"
|
${this._status === "disconnected"
|
||||||
? html`<ha-circular-progress
|
? html`<ha-circular-progress
|
||||||
active
|
indeterminate
|
||||||
></ha-circular-progress>`
|
></ha-circular-progress>`
|
||||||
: html`
|
: html`
|
||||||
<ha-svg-icon
|
<ha-svg-icon
|
||||||
@ -457,7 +457,7 @@ class ZWaveJSConfigDashboard extends SubscribeMixin(LitElement) {
|
|||||||
: html`
|
: html`
|
||||||
<ha-circular-progress
|
<ha-circular-progress
|
||||||
size="small"
|
size="small"
|
||||||
active
|
indeterminate
|
||||||
></ha-circular-progress>
|
></ha-circular-progress>
|
||||||
`}
|
`}
|
||||||
</div>
|
</div>
|
||||||
|
@ -97,7 +97,7 @@ export class SystemLogCard extends LitElement {
|
|||||||
${this._items === undefined
|
${this._items === undefined
|
||||||
? html`
|
? html`
|
||||||
<div class="loading-container">
|
<div class="loading-container">
|
||||||
<ha-circular-progress active></ha-circular-progress>
|
<ha-circular-progress indeterminate></ha-circular-progress>
|
||||||
</div>
|
</div>
|
||||||
`
|
`
|
||||||
: html`
|
: html`
|
||||||
|
@ -69,7 +69,7 @@ export class HassioHostname extends LitElement {
|
|||||||
<div class="card-actions">
|
<div class="card-actions">
|
||||||
<mwc-button @click=${this._save} .disabled=${this._processing}>
|
<mwc-button @click=${this._save} .disabled=${this._processing}>
|
||||||
${this._processing
|
${this._processing
|
||||||
? html`<ha-circular-progress active size="small">
|
? html`<ha-circular-progress indeterminate size="small">
|
||||||
</ha-circular-progress>`
|
</ha-circular-progress>`
|
||||||
: this.hass.localize("ui.common.save")}
|
: this.hass.localize("ui.common.save")}
|
||||||
</mwc-button>
|
</mwc-button>
|
||||||
|
@ -126,7 +126,7 @@ export class HassioNetwork extends LitElement {
|
|||||||
.disabled=${this._scanning}
|
.disabled=${this._scanning}
|
||||||
>
|
>
|
||||||
${this._scanning
|
${this._scanning
|
||||||
? html`<ha-circular-progress active size="small">
|
? html`<ha-circular-progress indeterminate size="small">
|
||||||
</ha-circular-progress>`
|
</ha-circular-progress>`
|
||||||
: this.hass.localize(
|
: this.hass.localize(
|
||||||
"ui.panel.config.network.supervisor.scan_ap"
|
"ui.panel.config.network.supervisor.scan_ap"
|
||||||
@ -242,7 +242,7 @@ export class HassioNetwork extends LitElement {
|
|||||||
<div class="card-actions">
|
<div class="card-actions">
|
||||||
<mwc-button @click=${this._updateNetwork} .disabled=${!this._dirty}>
|
<mwc-button @click=${this._updateNetwork} .disabled=${!this._dirty}>
|
||||||
${this._processing
|
${this._processing
|
||||||
? html`<ha-circular-progress active size="small">
|
? html`<ha-circular-progress indeterminate size="small">
|
||||||
</ha-circular-progress>`
|
</ha-circular-progress>`
|
||||||
: this.hass.localize("ui.common.save")}
|
: this.hass.localize("ui.common.save")}
|
||||||
</mwc-button>
|
</mwc-button>
|
||||||
|
@ -304,7 +304,7 @@ class DialogSystemInformation extends LitElement {
|
|||||||
if (!this._systemInfo) {
|
if (!this._systemInfo) {
|
||||||
sections.push(html`
|
sections.push(html`
|
||||||
<div class="loading-container">
|
<div class="loading-container">
|
||||||
<ha-circular-progress active></ha-circular-progress>
|
<ha-circular-progress indeterminate></ha-circular-progress>
|
||||||
</div>
|
</div>
|
||||||
`);
|
`);
|
||||||
} else {
|
} else {
|
||||||
@ -324,7 +324,10 @@ class DialogSystemInformation extends LitElement {
|
|||||||
|
|
||||||
if (info.type === "pending") {
|
if (info.type === "pending") {
|
||||||
value = html`
|
value = html`
|
||||||
<ha-circular-progress active size="tiny"></ha-circular-progress>
|
<ha-circular-progress
|
||||||
|
indeterminate
|
||||||
|
size="tiny"
|
||||||
|
></ha-circular-progress>
|
||||||
`;
|
`;
|
||||||
} else if (info.type === "failed") {
|
} else if (info.type === "failed") {
|
||||||
value = html`
|
value = html`
|
||||||
|
@ -80,7 +80,7 @@ export class HaBlueprintScriptEditor extends LitElement {
|
|||||||
: this.hass.localize(
|
: this.hass.localize(
|
||||||
"ui.panel.config.automation.editor.blueprint.no_blueprints"
|
"ui.panel.config.automation.editor.blueprint.no_blueprints"
|
||||||
)
|
)
|
||||||
: html`<ha-circular-progress active></ha-circular-progress>`}
|
: html`<ha-circular-progress indeterminate></ha-circular-progress>`}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
${this.config.use_blueprint.path
|
${this.config.use_blueprint.path
|
||||||
|
@ -26,7 +26,6 @@ import { fireEvent } from "../../../common/dom/fire_event";
|
|||||||
import { navigate } from "../../../common/navigate";
|
import { navigate } from "../../../common/navigate";
|
||||||
import { slugify } from "../../../common/string/slugify";
|
import { slugify } from "../../../common/string/slugify";
|
||||||
import { computeRTL } from "../../../common/util/compute_rtl";
|
import { computeRTL } from "../../../common/util/compute_rtl";
|
||||||
import { copyToClipboard } from "../../../common/util/copy-clipboard";
|
|
||||||
import { afterNextRender } from "../../../common/util/render-status";
|
import { afterNextRender } from "../../../common/util/render-status";
|
||||||
import "../../../components/ha-button-menu";
|
import "../../../components/ha-button-menu";
|
||||||
import "../../../components/ha-card";
|
import "../../../components/ha-card";
|
||||||
@ -38,7 +37,6 @@ import type {
|
|||||||
import "../../../components/ha-icon-button";
|
import "../../../components/ha-icon-button";
|
||||||
import "../../../components/ha-svg-icon";
|
import "../../../components/ha-svg-icon";
|
||||||
import "../../../components/ha-yaml-editor";
|
import "../../../components/ha-yaml-editor";
|
||||||
import type { HaYamlEditor } from "../../../components/ha-yaml-editor";
|
|
||||||
import { validateConfig } from "../../../data/config";
|
import { validateConfig } from "../../../data/config";
|
||||||
import { UNAVAILABLE } from "../../../data/entity";
|
import { UNAVAILABLE } from "../../../data/entity";
|
||||||
import { EntityRegistryEntry } from "../../../data/entity_registry";
|
import { EntityRegistryEntry } from "../../../data/entity_registry";
|
||||||
@ -94,8 +92,6 @@ export class HaScriptEditor extends KeyboardShortcutMixin(LitElement) {
|
|||||||
|
|
||||||
@state() private _readOnly = false;
|
@state() private _readOnly = false;
|
||||||
|
|
||||||
@query("ha-yaml-editor") private _yamlEditor?: HaYamlEditor;
|
|
||||||
|
|
||||||
@query("manual-script-editor")
|
@query("manual-script-editor")
|
||||||
private _manualEditor?: HaManualScriptEditor;
|
private _manualEditor?: HaManualScriptEditor;
|
||||||
|
|
||||||
@ -405,24 +401,14 @@ export class HaScriptEditor extends KeyboardShortcutMixin(LitElement) {
|
|||||||
</div>
|
</div>
|
||||||
`
|
`
|
||||||
: this._mode === "yaml"
|
: this._mode === "yaml"
|
||||||
? html`
|
? html` <ha-yaml-editor
|
||||||
<ha-yaml-editor
|
copyClipboard
|
||||||
.hass=${this.hass}
|
.hass=${this.hass}
|
||||||
.defaultValue=${this._preprocessYaml()}
|
.defaultValue=${this._preprocessYaml()}
|
||||||
.readOnly=${this._readOnly}
|
.readOnly=${this._readOnly}
|
||||||
@value-changed=${this._yamlChanged}
|
@value-changed=${this._yamlChanged}
|
||||||
></ha-yaml-editor>
|
></ha-yaml-editor>`
|
||||||
<ha-card outlined>
|
: nothing}
|
||||||
<div class="card-actions">
|
|
||||||
<mwc-button @click=${this._copyYaml}>
|
|
||||||
${this.hass.localize(
|
|
||||||
"ui.panel.config.automation.editor.copy_to_clipboard"
|
|
||||||
)}
|
|
||||||
</mwc-button>
|
|
||||||
</div>
|
|
||||||
</ha-card>
|
|
||||||
`
|
|
||||||
: ``}
|
|
||||||
</div>
|
</div>
|
||||||
<ha-fab
|
<ha-fab
|
||||||
slot="fab"
|
slot="fab"
|
||||||
@ -735,15 +721,6 @@ export class HaScriptEditor extends KeyboardShortcutMixin(LitElement) {
|
|||||||
return this._config;
|
return this._config;
|
||||||
}
|
}
|
||||||
|
|
||||||
private async _copyYaml(): Promise<void> {
|
|
||||||
if (this._yamlEditor?.yaml) {
|
|
||||||
await copyToClipboard(this._yamlEditor.yaml);
|
|
||||||
showToast(this, {
|
|
||||||
message: this.hass.localize("ui.common.copied_clipboard"),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private _yamlChanged(ev: CustomEvent) {
|
private _yamlChanged(ev: CustomEvent) {
|
||||||
ev.stopPropagation();
|
ev.stopPropagation();
|
||||||
if (!ev.detail.isValid) {
|
if (!ev.detail.isValid) {
|
||||||
@ -903,8 +880,11 @@ export class HaScriptEditor extends KeyboardShortcutMixin(LitElement) {
|
|||||||
}
|
}
|
||||||
ha-yaml-editor {
|
ha-yaml-editor {
|
||||||
flex-grow: 1;
|
flex-grow: 1;
|
||||||
|
--actions-border-radius: 0;
|
||||||
--code-mirror-height: 100%;
|
--code-mirror-height: 100%;
|
||||||
min-height: 0;
|
min-height: 0;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
}
|
}
|
||||||
.yaml-mode ha-card {
|
.yaml-mode ha-card {
|
||||||
overflow: initial;
|
overflow: initial;
|
||||||
|
@ -106,7 +106,11 @@ class MoveDatadiskDialog extends LitElement {
|
|||||||
>
|
>
|
||||||
${this._moving
|
${this._moving
|
||||||
? html`
|
? html`
|
||||||
<ha-circular-progress alt="Moving" size="large" active>
|
<ha-circular-progress
|
||||||
|
aria-label="Moving"
|
||||||
|
size="large"
|
||||||
|
indeterminate
|
||||||
|
>
|
||||||
</ha-circular-progress>
|
</ha-circular-progress>
|
||||||
<p class="progress-text">
|
<p class="progress-text">
|
||||||
${this.hass.localize(
|
${this.hass.localize(
|
||||||
|
@ -194,7 +194,7 @@ export class DialogAddUser extends LitElement {
|
|||||||
${this._loading
|
${this._loading
|
||||||
? html`
|
? html`
|
||||||
<div slot="primaryAction" class="submit-spinner">
|
<div slot="primaryAction" class="submit-spinner">
|
||||||
<ha-circular-progress active></ha-circular-progress>
|
<ha-circular-progress indeterminate></ha-circular-progress>
|
||||||
</div>
|
</div>
|
||||||
`
|
`
|
||||||
: html`
|
: html`
|
||||||
|
@ -90,7 +90,7 @@ const renderProgress = (
|
|||||||
return html`❌`;
|
return html`❌`;
|
||||||
}
|
}
|
||||||
return html`
|
return html`
|
||||||
<ha-circular-progress size="tiny" active></ha-circular-progress>
|
<ha-circular-progress size="tiny" indeterminate></ha-circular-progress>
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -184,6 +184,8 @@ class HaPanelDevService extends LitElement {
|
|||||||
>
|
>
|
||||||
<div class="card-content">
|
<div class="card-content">
|
||||||
<ha-yaml-editor
|
<ha-yaml-editor
|
||||||
|
.hass=${this.hass}
|
||||||
|
copyClipboard
|
||||||
readOnly
|
readOnly
|
||||||
autoUpdate
|
autoUpdate
|
||||||
.value=${this._response}
|
.value=${this._response}
|
||||||
|
@ -131,7 +131,7 @@ export class DialogStatisticsFixUnsupportedUnitMetadata extends LitElement {
|
|||||||
let stats: TemplateResult;
|
let stats: TemplateResult;
|
||||||
|
|
||||||
if (!this._stats5min || !this._statsHour) {
|
if (!this._stats5min || !this._statsHour) {
|
||||||
stats = html`<ha-circular-progress active></ha-circular-progress>`;
|
stats = html`<ha-circular-progress indeterminate></ha-circular-progress>`;
|
||||||
} else if (this._statsHour.length < 1 && this._stats5min.length < 1) {
|
} else if (this._statsHour.length < 1 && this._stats5min.length < 1) {
|
||||||
stats = html`<p>
|
stats = html`<p>
|
||||||
${this.hass.localize(
|
${this.hass.localize(
|
||||||
|
@ -156,7 +156,7 @@ class HaPanelDevTemplate extends LitElement {
|
|||||||
${this._rendering
|
${this._rendering
|
||||||
? html`<ha-circular-progress
|
? html`<ha-circular-progress
|
||||||
class="render-spinner"
|
class="render-spinner"
|
||||||
active
|
indeterminate
|
||||||
size="small"
|
size="small"
|
||||||
></ha-circular-progress>`
|
></ha-circular-progress>`
|
||||||
: ""}
|
: ""}
|
||||||
|
@ -77,7 +77,7 @@ export class DeveloperYamlConfig extends LitElement {
|
|||||||
? html`<div
|
? html`<div
|
||||||
class="validate-container layout vertical center-center"
|
class="validate-container layout vertical center-center"
|
||||||
>
|
>
|
||||||
<ha-circular-progress active></ha-circular-progress>
|
<ha-circular-progress indeterminate></ha-circular-progress>
|
||||||
</div> `
|
</div> `
|
||||||
: nothing
|
: nothing
|
||||||
: html`
|
: html`
|
||||||
@ -94,7 +94,7 @@ export class DeveloperYamlConfig extends LitElement {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
${
|
${
|
||||||
this._validateResult.errors
|
this._validateResult.errors
|
||||||
? html`<ha-alert
|
? html`<ha-alert
|
||||||
@ -233,7 +233,7 @@ export class DeveloperYamlConfig extends LitElement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.validate-log {
|
.validate-log {
|
||||||
white-space: pre;
|
white-space: pre-wrap;
|
||||||
direction: ltr;
|
direction: ltr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -193,10 +193,7 @@ class HaPanelHistory extends SubscribeMixin(LitElement) {
|
|||||||
</div>
|
</div>
|
||||||
${this._isLoading
|
${this._isLoading
|
||||||
? html`<div class="progress-wrapper">
|
? html`<div class="progress-wrapper">
|
||||||
<ha-circular-progress
|
<ha-circular-progress indeterminate></ha-circular-progress>
|
||||||
active
|
|
||||||
alt=${this.hass.localize("ui.common.loading")}
|
|
||||||
></ha-circular-progress>
|
|
||||||
</div>`
|
</div>`
|
||||||
: !this._targetPickerValue
|
: !this._targetPickerValue
|
||||||
? html`<div class="start-search">
|
? html`<div class="start-search">
|
||||||
|
@ -107,10 +107,7 @@ export class HaLogbook extends LitElement {
|
|||||||
if (this._logbookEntries === undefined) {
|
if (this._logbookEntries === undefined) {
|
||||||
return html`
|
return html`
|
||||||
<div class="progress-wrapper">
|
<div class="progress-wrapper">
|
||||||
<ha-circular-progress
|
<ha-circular-progress indeterminate></ha-circular-progress>
|
||||||
active
|
|
||||||
alt=${this.hass.localize("ui.common.loading")}
|
|
||||||
></ha-circular-progress>
|
|
||||||
</div>
|
</div>
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
@ -1,25 +1,34 @@
|
|||||||
import { mdiPower, mdiWaterPercent } from "@mdi/js";
|
import { mdiTuneVariant } from "@mdi/js";
|
||||||
import { HassEntity } from "home-assistant-js-websocket";
|
import { HassEntity } from "home-assistant-js-websocket";
|
||||||
import { LitElement, PropertyValues, TemplateResult, css, html } from "lit";
|
import { css, html, LitElement, PropertyValues, TemplateResult } from "lit";
|
||||||
import { customElement, property, state } from "lit/decorators";
|
import { customElement, property, query, state } from "lit/decorators";
|
||||||
import { styleMap } from "lit/directives/style-map";
|
import { stopPropagation } from "../../../common/dom/stop_propagation";
|
||||||
import { computeDomain } from "../../../common/entity/compute_domain";
|
import { computeDomain } from "../../../common/entity/compute_domain";
|
||||||
import { stateColorCss } from "../../../common/entity/state_color";
|
import { supportsFeature } from "../../../common/entity/supports-feature";
|
||||||
import "../../../components/ha-control-select";
|
import "../../../components/ha-control-select";
|
||||||
import type { ControlSelectOption } from "../../../components/ha-control-select";
|
import type { ControlSelectOption } from "../../../components/ha-control-select";
|
||||||
|
import "../../../components/ha-control-select-menu";
|
||||||
|
import type { HaControlSelectMenu } from "../../../components/ha-control-select-menu";
|
||||||
|
import {
|
||||||
|
HumidifierEntityFeature,
|
||||||
|
HumidifierEntity,
|
||||||
|
computeHumidiferModeIcon,
|
||||||
|
} from "../../../data/humidifier";
|
||||||
import { UNAVAILABLE } from "../../../data/entity";
|
import { UNAVAILABLE } from "../../../data/entity";
|
||||||
import { HumidifierEntity, HumidifierState } from "../../../data/humidifier";
|
|
||||||
import { HomeAssistant } from "../../../types";
|
import { HomeAssistant } from "../../../types";
|
||||||
import { LovelaceCardFeature } from "../types";
|
import { LovelaceCardFeature, LovelaceCardFeatureEditor } from "../types";
|
||||||
import { HumidifierModesCardFeatureConfig } from "./types";
|
import { HumidifierModesCardFeatureConfig } from "./types";
|
||||||
|
|
||||||
export const supportsHumidifierModesCardFeature = (stateObj: HassEntity) => {
|
export const supportsHumidifierModesCardFeature = (stateObj: HassEntity) => {
|
||||||
const domain = computeDomain(stateObj.entity_id);
|
const domain = computeDomain(stateObj.entity_id);
|
||||||
return domain === "humidifier";
|
return (
|
||||||
|
domain === "humidifier" &&
|
||||||
|
supportsFeature(stateObj, HumidifierEntityFeature.MODES)
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
@customElement("hui-humidifier-modes-card-feature")
|
@customElement("hui-humidifier-modes-card-feature")
|
||||||
class HuiHumidifierModeCardFeature
|
class HuiHumidifierModesCardFeature
|
||||||
extends LitElement
|
extends LitElement
|
||||||
implements LovelaceCardFeature
|
implements LovelaceCardFeature
|
||||||
{
|
{
|
||||||
@ -29,14 +38,29 @@ class HuiHumidifierModeCardFeature
|
|||||||
|
|
||||||
@state() private _config?: HumidifierModesCardFeatureConfig;
|
@state() private _config?: HumidifierModesCardFeatureConfig;
|
||||||
|
|
||||||
@state() _currentState?: HumidifierState;
|
@state() _currentMode?: string;
|
||||||
|
|
||||||
static getStubConfig(): HumidifierModesCardFeatureConfig {
|
@query("ha-control-select-menu", true)
|
||||||
|
private _haSelect?: HaControlSelectMenu;
|
||||||
|
|
||||||
|
static getStubConfig(
|
||||||
|
_,
|
||||||
|
stateObj?: HassEntity
|
||||||
|
): HumidifierModesCardFeatureConfig {
|
||||||
return {
|
return {
|
||||||
type: "humidifier-modes",
|
type: "humidifier-modes",
|
||||||
|
style: "dropdown",
|
||||||
|
modes: stateObj?.attributes.available_modes || [],
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static async getConfigElement(): Promise<LovelaceCardFeatureEditor> {
|
||||||
|
await import(
|
||||||
|
"../editor/config-elements/hui-humidifier-modes-card-feature-editor"
|
||||||
|
);
|
||||||
|
return document.createElement("hui-humidifier-modes-card-feature-editor");
|
||||||
|
}
|
||||||
|
|
||||||
public setConfig(config: HumidifierModesCardFeatureConfig): void {
|
public setConfig(config: HumidifierModesCardFeatureConfig): void {
|
||||||
if (!config) {
|
if (!config) {
|
||||||
throw new Error("Invalid configuration");
|
throw new Error("Invalid configuration");
|
||||||
@ -47,33 +71,46 @@ class HuiHumidifierModeCardFeature
|
|||||||
protected willUpdate(changedProp: PropertyValues): void {
|
protected willUpdate(changedProp: PropertyValues): void {
|
||||||
super.willUpdate(changedProp);
|
super.willUpdate(changedProp);
|
||||||
if (changedProp.has("stateObj") && this.stateObj) {
|
if (changedProp.has("stateObj") && this.stateObj) {
|
||||||
this._currentState = this.stateObj.state as HumidifierState;
|
this._currentMode = this.stateObj.attributes.mode;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected updated(changedProps: PropertyValues) {
|
||||||
|
super.updated(changedProps);
|
||||||
|
if (this._haSelect && changedProps.has("hass")) {
|
||||||
|
const oldHass = changedProps.get("hass") as HomeAssistant | undefined;
|
||||||
|
if (
|
||||||
|
this.hass &&
|
||||||
|
this.hass.formatEntityAttributeValue !==
|
||||||
|
oldHass?.formatEntityAttributeValue
|
||||||
|
) {
|
||||||
|
this._haSelect.layoutOptions();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async _valueChanged(ev: CustomEvent) {
|
private async _valueChanged(ev: CustomEvent) {
|
||||||
const newState = (ev.detail as any).value as HumidifierState;
|
const mode =
|
||||||
|
(ev.detail as any).value ?? ((ev.target as any).value as string);
|
||||||
|
|
||||||
if (newState === this.stateObj!.state) return;
|
const oldMode = this.stateObj!.attributes.mode;
|
||||||
|
|
||||||
const oldState = this.stateObj!.state as HumidifierState;
|
if (mode === oldMode) return;
|
||||||
this._currentState = newState;
|
|
||||||
|
this._currentMode = mode;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await this._setState(newState);
|
await this._setMode(mode);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
this._currentState = oldState;
|
this._currentMode = oldMode;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async _setState(newState: HumidifierState) {
|
private async _setMode(mode: string) {
|
||||||
await this.hass!.callService(
|
await this.hass!.callService("humidifier", "set_mode", {
|
||||||
"humidifier",
|
entity_id: this.stateObj!.entity_id,
|
||||||
newState === "on" ? "turn_on" : "turn_off",
|
mode: mode,
|
||||||
{
|
});
|
||||||
entity_id: this.stateObj!.entity_id,
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected render(): TemplateResult | null {
|
protected render(): TemplateResult | null {
|
||||||
@ -86,34 +123,75 @@ class HuiHumidifierModeCardFeature
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
const color = stateColorCss(this.stateObj);
|
const stateObj = this.stateObj;
|
||||||
|
|
||||||
const options = ["on", "off"].map<ControlSelectOption>((entityState) => ({
|
const modes = stateObj.attributes.available_modes || [];
|
||||||
value: entityState,
|
|
||||||
label: this.hass!.formatEntityState(this.stateObj!, entityState),
|
const options = modes
|
||||||
path: entityState === "on" ? mdiWaterPercent : mdiPower,
|
.filter((mode) => (this._config!.modes || []).includes(mode))
|
||||||
}));
|
.map<ControlSelectOption>((mode) => ({
|
||||||
|
value: mode,
|
||||||
|
label: this.hass!.formatEntityAttributeValue(
|
||||||
|
this.stateObj!,
|
||||||
|
"mode",
|
||||||
|
mode
|
||||||
|
),
|
||||||
|
path: computeHumidiferModeIcon(mode),
|
||||||
|
}));
|
||||||
|
|
||||||
|
if (this._config.style === "icons") {
|
||||||
|
return html`
|
||||||
|
<div class="container">
|
||||||
|
<ha-control-select
|
||||||
|
.options=${options}
|
||||||
|
.value=${this._currentMode}
|
||||||
|
@value-changed=${this._valueChanged}
|
||||||
|
hide-label
|
||||||
|
.ariaLabel=${this.hass!.formatEntityAttributeName(stateObj, "mode")}
|
||||||
|
.disabled=${this.stateObj!.state === UNAVAILABLE}
|
||||||
|
>
|
||||||
|
</ha-control-select>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
return html`
|
return html`
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<ha-control-select
|
<ha-control-select-menu
|
||||||
.options=${options}
|
show-arrow
|
||||||
.value=${this._currentState}
|
|
||||||
@value-changed=${this._valueChanged}
|
|
||||||
hide-label
|
hide-label
|
||||||
.ariaLabel=${this.hass.localize("ui.card.humidifier.state")}
|
.label=${this.hass!.formatEntityAttributeName(stateObj, "mode")}
|
||||||
style=${styleMap({
|
.value=${this._currentMode}
|
||||||
"--control-select-color": color,
|
.disabled=${this.stateObj.state === UNAVAILABLE}
|
||||||
})}
|
fixedMenuPosition
|
||||||
.disabled=${this.stateObj!.state === UNAVAILABLE}
|
naturalMenuWidth
|
||||||
|
@selected=${this._valueChanged}
|
||||||
|
@closed=${stopPropagation}
|
||||||
>
|
>
|
||||||
</ha-control-select>
|
<ha-svg-icon slot="icon" .path=${mdiTuneVariant}></ha-svg-icon>
|
||||||
|
${options.map(
|
||||||
|
(option) => html`
|
||||||
|
<ha-list-item .value=${option.value} graphic="icon">
|
||||||
|
<ha-svg-icon slot="graphic" .path=${option.path}></ha-svg-icon>
|
||||||
|
${option.label}
|
||||||
|
</ha-list-item>
|
||||||
|
`
|
||||||
|
)}
|
||||||
|
</ha-control-select-menu>
|
||||||
</div>
|
</div>
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
static get styles() {
|
static get styles() {
|
||||||
return css`
|
return css`
|
||||||
|
ha-control-select-menu {
|
||||||
|
box-sizing: border-box;
|
||||||
|
--control-select-menu-height: 40px;
|
||||||
|
--control-select-menu-border-radius: 10px;
|
||||||
|
line-height: 1.2;
|
||||||
|
display: block;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
ha-control-select {
|
ha-control-select {
|
||||||
--control-select-color: var(--feature-color);
|
--control-select-color: var(--feature-color);
|
||||||
--control-select-padding: 0;
|
--control-select-padding: 0;
|
||||||
@ -131,6 +209,6 @@ class HuiHumidifierModeCardFeature
|
|||||||
|
|
||||||
declare global {
|
declare global {
|
||||||
interface HTMLElementTagNameMap {
|
interface HTMLElementTagNameMap {
|
||||||
"hui-humidifier-modes-card-feature": HuiHumidifierModeCardFeature;
|
"hui-humidifier-modes-card-feature": HuiHumidifierModesCardFeature;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,136 @@
|
|||||||
|
import { mdiPower, mdiWaterPercent } from "@mdi/js";
|
||||||
|
import { HassEntity } from "home-assistant-js-websocket";
|
||||||
|
import { LitElement, PropertyValues, TemplateResult, css, html } from "lit";
|
||||||
|
import { customElement, property, state } from "lit/decorators";
|
||||||
|
import { styleMap } from "lit/directives/style-map";
|
||||||
|
import { computeDomain } from "../../../common/entity/compute_domain";
|
||||||
|
import { stateColorCss } from "../../../common/entity/state_color";
|
||||||
|
import "../../../components/ha-control-select";
|
||||||
|
import type { ControlSelectOption } from "../../../components/ha-control-select";
|
||||||
|
import { UNAVAILABLE } from "../../../data/entity";
|
||||||
|
import { HumidifierEntity, HumidifierState } from "../../../data/humidifier";
|
||||||
|
import { HomeAssistant } from "../../../types";
|
||||||
|
import { LovelaceCardFeature } from "../types";
|
||||||
|
import { HumidifierToggleCardFeatureConfig } from "./types";
|
||||||
|
|
||||||
|
export const supportsHumidifierToggleCardFeature = (stateObj: HassEntity) => {
|
||||||
|
const domain = computeDomain(stateObj.entity_id);
|
||||||
|
return domain === "humidifier";
|
||||||
|
};
|
||||||
|
|
||||||
|
@customElement("hui-humidifier-toggle-card-feature")
|
||||||
|
class HuiHumidifierToggleCardFeature
|
||||||
|
extends LitElement
|
||||||
|
implements LovelaceCardFeature
|
||||||
|
{
|
||||||
|
@property({ attribute: false }) public hass?: HomeAssistant;
|
||||||
|
|
||||||
|
@property({ attribute: false }) public stateObj?: HumidifierEntity;
|
||||||
|
|
||||||
|
@state() private _config?: HumidifierToggleCardFeatureConfig;
|
||||||
|
|
||||||
|
@state() _currentState?: HumidifierState;
|
||||||
|
|
||||||
|
static getStubConfig(): HumidifierToggleCardFeatureConfig {
|
||||||
|
return {
|
||||||
|
type: "humidifier-toggle",
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public setConfig(config: HumidifierToggleCardFeatureConfig): void {
|
||||||
|
if (!config) {
|
||||||
|
throw new Error("Invalid configuration");
|
||||||
|
}
|
||||||
|
this._config = config;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected willUpdate(changedProp: PropertyValues): void {
|
||||||
|
super.willUpdate(changedProp);
|
||||||
|
if (changedProp.has("stateObj") && this.stateObj) {
|
||||||
|
this._currentState = this.stateObj.state as HumidifierState;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async _valueChanged(ev: CustomEvent) {
|
||||||
|
const newState = (ev.detail as any).value as HumidifierState;
|
||||||
|
|
||||||
|
if (newState === this.stateObj!.state) return;
|
||||||
|
|
||||||
|
const oldState = this.stateObj!.state as HumidifierState;
|
||||||
|
this._currentState = newState;
|
||||||
|
|
||||||
|
try {
|
||||||
|
await this._setState(newState);
|
||||||
|
} catch (err) {
|
||||||
|
this._currentState = oldState;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async _setState(newState: HumidifierState) {
|
||||||
|
await this.hass!.callService(
|
||||||
|
"humidifier",
|
||||||
|
newState === "on" ? "turn_on" : "turn_off",
|
||||||
|
{
|
||||||
|
entity_id: this.stateObj!.entity_id,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected render(): TemplateResult | null {
|
||||||
|
if (
|
||||||
|
!this._config ||
|
||||||
|
!this.hass ||
|
||||||
|
!this.stateObj ||
|
||||||
|
!supportsHumidifierToggleCardFeature(this.stateObj)
|
||||||
|
) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const color = stateColorCss(this.stateObj);
|
||||||
|
|
||||||
|
const options = ["on", "off"].map<ControlSelectOption>((entityState) => ({
|
||||||
|
value: entityState,
|
||||||
|
label: this.hass!.formatEntityState(this.stateObj!, entityState),
|
||||||
|
path: entityState === "on" ? mdiWaterPercent : mdiPower,
|
||||||
|
}));
|
||||||
|
|
||||||
|
return html`
|
||||||
|
<div class="container">
|
||||||
|
<ha-control-select
|
||||||
|
.options=${options}
|
||||||
|
.value=${this._currentState}
|
||||||
|
@value-changed=${this._valueChanged}
|
||||||
|
hide-label
|
||||||
|
.ariaLabel=${this.hass.localize("ui.card.humidifier.state")}
|
||||||
|
style=${styleMap({
|
||||||
|
"--control-select-color": color,
|
||||||
|
})}
|
||||||
|
.disabled=${this.stateObj!.state === UNAVAILABLE}
|
||||||
|
>
|
||||||
|
</ha-control-select>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
static get styles() {
|
||||||
|
return css`
|
||||||
|
ha-control-select {
|
||||||
|
--control-select-color: var(--feature-color);
|
||||||
|
--control-select-padding: 0;
|
||||||
|
--control-select-thickness: 40px;
|
||||||
|
--control-select-border-radius: 10px;
|
||||||
|
--control-select-button-border-radius: 10px;
|
||||||
|
}
|
||||||
|
.container {
|
||||||
|
padding: 0 12px 12px 12px;
|
||||||
|
width: auto;
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
declare global {
|
||||||
|
interface HTMLElementTagNameMap {
|
||||||
|
"hui-humidifier-toggle-card-feature": HuiHumidifierToggleCardFeature;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,127 @@
|
|||||||
|
import { HassEntity } from "home-assistant-js-websocket";
|
||||||
|
import { css, html, LitElement, nothing, PropertyValues } from "lit";
|
||||||
|
import { customElement, property, state } from "lit/decorators";
|
||||||
|
import { computeDomain } from "../../../common/entity/compute_domain";
|
||||||
|
import "../../../components/ha-control-slider";
|
||||||
|
import { UNAVAILABLE } from "../../../data/entity";
|
||||||
|
import { HumidifierEntity } from "../../../data/humidifier";
|
||||||
|
import { HomeAssistant } from "../../../types";
|
||||||
|
import { LovelaceCardFeature } from "../types";
|
||||||
|
import { TargetHumidityCardFeatureConfig } from "./types";
|
||||||
|
|
||||||
|
export const supportsTargetHumidityCardFeature = (stateObj: HassEntity) => {
|
||||||
|
const domain = computeDomain(stateObj.entity_id);
|
||||||
|
return domain === "humidifier";
|
||||||
|
};
|
||||||
|
|
||||||
|
@customElement("hui-target-humidity-card-feature")
|
||||||
|
class HuiTargetHumidityCardFeature
|
||||||
|
extends LitElement
|
||||||
|
implements LovelaceCardFeature
|
||||||
|
{
|
||||||
|
@property({ attribute: false }) public hass?: HomeAssistant;
|
||||||
|
|
||||||
|
@property({ attribute: false }) public stateObj?: HumidifierEntity;
|
||||||
|
|
||||||
|
@state() private _config?: TargetHumidityCardFeatureConfig;
|
||||||
|
|
||||||
|
@state() private _targetHumidity?: number;
|
||||||
|
|
||||||
|
static getStubConfig(): TargetHumidityCardFeatureConfig {
|
||||||
|
return {
|
||||||
|
type: "target-humidity",
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public setConfig(config: TargetHumidityCardFeatureConfig): void {
|
||||||
|
if (!config) {
|
||||||
|
throw new Error("Invalid configuration");
|
||||||
|
}
|
||||||
|
this._config = config;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected willUpdate(changedProp: PropertyValues): void {
|
||||||
|
super.willUpdate(changedProp);
|
||||||
|
if (changedProp.has("stateObj")) {
|
||||||
|
this._targetHumidity = this.stateObj!.attributes.humidity;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private get _step() {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
private get _min() {
|
||||||
|
return this.stateObj!.attributes.min_humidity ?? 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
private get _max() {
|
||||||
|
return this.stateObj!.attributes.max_humidity ?? 100;
|
||||||
|
}
|
||||||
|
|
||||||
|
private _valueChanged(ev: CustomEvent) {
|
||||||
|
const value = (ev.detail as any).value;
|
||||||
|
if (isNaN(value)) return;
|
||||||
|
this._targetHumidity = value;
|
||||||
|
this._callService();
|
||||||
|
}
|
||||||
|
|
||||||
|
private _callService() {
|
||||||
|
this.hass!.callService("humidifier", "set_humidity", {
|
||||||
|
entity_id: this.stateObj!.entity_id,
|
||||||
|
humidity: this._targetHumidity,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
protected render() {
|
||||||
|
if (
|
||||||
|
!this._config ||
|
||||||
|
!this.hass ||
|
||||||
|
!this.stateObj ||
|
||||||
|
!supportsTargetHumidityCardFeature(this.stateObj)
|
||||||
|
) {
|
||||||
|
return nothing;
|
||||||
|
}
|
||||||
|
|
||||||
|
return html`
|
||||||
|
<div class="container">
|
||||||
|
<ha-control-slider
|
||||||
|
.value=${this.stateObj.attributes.humidity}
|
||||||
|
.min=${this._min}
|
||||||
|
.max=${this._max}
|
||||||
|
.step=${this._step}
|
||||||
|
.disabled=${this.stateObj!.state === UNAVAILABLE}
|
||||||
|
@value-changed=${this._valueChanged}
|
||||||
|
.label=${this.hass.formatEntityAttributeName(
|
||||||
|
this.stateObj,
|
||||||
|
"humidity"
|
||||||
|
)}
|
||||||
|
unit="%"
|
||||||
|
.locale=${this.hass.locale}
|
||||||
|
></ha-control-slider>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
static get styles() {
|
||||||
|
return css`
|
||||||
|
ha-control-slider {
|
||||||
|
--control-slider-color: var(--feature-color);
|
||||||
|
--control-slider-background: var(--feature-color);
|
||||||
|
--control-slider-background-opacity: 0.2;
|
||||||
|
--control-slider-thickness: 40px;
|
||||||
|
--control-slider-border-radius: 10px;
|
||||||
|
}
|
||||||
|
.container {
|
||||||
|
padding: 0 12px 12px 12px;
|
||||||
|
width: auto;
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
declare global {
|
||||||
|
interface HTMLElementTagNameMap {
|
||||||
|
"hui-target-humidity-card-feature": HuiTargetHumidityCardFeature;
|
||||||
|
}
|
||||||
|
}
|
@ -55,6 +55,10 @@ export interface NumericInputCardFeatureConfig {
|
|||||||
style?: "buttons" | "slider";
|
style?: "buttons" | "slider";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface TargetHumidityCardFeatureConfig {
|
||||||
|
type: "target-humidity";
|
||||||
|
}
|
||||||
|
|
||||||
export interface TargetTemperatureCardFeatureConfig {
|
export interface TargetTemperatureCardFeatureConfig {
|
||||||
type: "target-temperature";
|
type: "target-temperature";
|
||||||
}
|
}
|
||||||
@ -66,6 +70,12 @@ export interface WaterHeaterOperationModesCardFeatureConfig {
|
|||||||
|
|
||||||
export interface HumidifierModesCardFeatureConfig {
|
export interface HumidifierModesCardFeatureConfig {
|
||||||
type: "humidifier-modes";
|
type: "humidifier-modes";
|
||||||
|
style?: "dropdown" | "icons";
|
||||||
|
modes?: string[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface HumidifierToggleCardFeatureConfig {
|
||||||
|
type: "humidifier-toggle";
|
||||||
}
|
}
|
||||||
|
|
||||||
export const VACUUM_COMMANDS = [
|
export const VACUUM_COMMANDS = [
|
||||||
@ -101,11 +111,13 @@ export type LovelaceCardFeatureConfig =
|
|||||||
| CoverTiltPositionCardFeatureConfig
|
| CoverTiltPositionCardFeatureConfig
|
||||||
| CoverTiltCardFeatureConfig
|
| CoverTiltCardFeatureConfig
|
||||||
| FanSpeedCardFeatureConfig
|
| FanSpeedCardFeatureConfig
|
||||||
|
| HumidifierToggleCardFeatureConfig
|
||||||
| HumidifierModesCardFeatureConfig
|
| HumidifierModesCardFeatureConfig
|
||||||
| LawnMowerCommandsCardFeatureConfig
|
| LawnMowerCommandsCardFeatureConfig
|
||||||
| LightBrightnessCardFeatureConfig
|
| LightBrightnessCardFeatureConfig
|
||||||
| LightColorTempCardFeatureConfig
|
| LightColorTempCardFeatureConfig
|
||||||
| VacuumCommandsCardFeatureConfig
|
| VacuumCommandsCardFeatureConfig
|
||||||
|
| TargetHumidityCardFeatureConfig
|
||||||
| TargetTemperatureCardFeatureConfig
|
| TargetTemperatureCardFeatureConfig
|
||||||
| WaterHeaterOperationModesCardFeatureConfig
|
| WaterHeaterOperationModesCardFeatureConfig
|
||||||
| SelectOptionsCardFeatureConfig
|
| SelectOptionsCardFeatureConfig
|
||||||
|
@ -51,7 +51,7 @@ export class HuiHumidifierCard extends LitElement implements LovelaceCard {
|
|||||||
entity: foundEntities[0] || "",
|
entity: foundEntities[0] || "",
|
||||||
features: [
|
features: [
|
||||||
{
|
{
|
||||||
type: "humidifier-modes",
|
type: "humidifier-toggle",
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
};
|
};
|
||||||
@ -180,6 +180,7 @@ export class HuiHumidifierCard extends LitElement implements LovelaceCard {
|
|||||||
max-width: 344px; /* 12px + 12px + 320px */
|
max-width: 344px; /* 12px + 12px + 320px */
|
||||||
padding: 0 12px 12px 12px;
|
padding: 0 12px 12px 12px;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
|
--interaction-margin: 0px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.more-info {
|
.more-info {
|
||||||
|
@ -101,6 +101,8 @@ export class HuiMediaControlCard extends LitElement implements LovelaceCard {
|
|||||||
}
|
}
|
||||||
|
|
||||||
this._config = config;
|
this._config = config;
|
||||||
|
|
||||||
|
this.updateComplete.then(() => this._measureCard());
|
||||||
}
|
}
|
||||||
|
|
||||||
public connectedCallback(): void {
|
public connectedCallback(): void {
|
||||||
@ -339,15 +341,12 @@ export class HuiMediaControlCard extends LitElement implements LovelaceCard {
|
|||||||
|
|
||||||
protected firstUpdated(): void {
|
protected firstUpdated(): void {
|
||||||
this._attachObserver();
|
this._attachObserver();
|
||||||
|
this._measureCard();
|
||||||
}
|
}
|
||||||
|
|
||||||
public willUpdate(changedProps: PropertyValues): void {
|
public willUpdate(changedProps: PropertyValues): void {
|
||||||
super.willUpdate(changedProps);
|
super.willUpdate(changedProps);
|
||||||
|
|
||||||
if (!this.hasUpdated) {
|
|
||||||
this._measureCard();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (
|
if (
|
||||||
!this._config ||
|
!this._config ||
|
||||||
!this.hass ||
|
!this.hass ||
|
||||||
@ -468,6 +467,7 @@ export class HuiMediaControlCard extends LitElement implements LovelaceCard {
|
|||||||
|
|
||||||
private _measureCard() {
|
private _measureCard() {
|
||||||
const card = this.shadowRoot!.querySelector("ha-card");
|
const card = this.shadowRoot!.querySelector("ha-card");
|
||||||
|
|
||||||
if (!card) {
|
if (!card) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -46,7 +46,7 @@ export class HuiStartingCard extends LitElement implements LovelaceCard {
|
|||||||
|
|
||||||
return html`
|
return html`
|
||||||
<div class="content">
|
<div class="content">
|
||||||
<ha-circular-progress active></ha-circular-progress>
|
<ha-circular-progress indeterminate></ha-circular-progress>
|
||||||
${this.hass.localize("ui.panel.lovelace.cards.starting.description")}
|
${this.hass.localize("ui.panel.lovelace.cards.starting.description")}
|
||||||
</div>
|
</div>
|
||||||
`;
|
`;
|
||||||
|
@ -172,6 +172,7 @@ export class HuiThermostatCard extends LitElement implements LovelaceCard {
|
|||||||
max-width: 344px; /* 12px + 12px + 320px */
|
max-width: 344px; /* 12px + 12px + 320px */
|
||||||
padding: 0 12px 12px 12px;
|
padding: 0 12px 12px 12px;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
|
--interaction-margin: 0px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.more-info {
|
.more-info {
|
||||||
|
@ -22,6 +22,7 @@ import memoizeOne from "memoize-one";
|
|||||||
import type { SortableEvent } from "sortablejs";
|
import type { SortableEvent } from "sortablejs";
|
||||||
import { applyThemesOnElement } from "../../../common/dom/apply_themes_on_element";
|
import { applyThemesOnElement } from "../../../common/dom/apply_themes_on_element";
|
||||||
import { supportsFeature } from "../../../common/entity/supports-feature";
|
import { supportsFeature } from "../../../common/entity/supports-feature";
|
||||||
|
import { showConfirmationDialog } from "../../../dialogs/generic/show-dialog-box";
|
||||||
import "../../../components/ha-card";
|
import "../../../components/ha-card";
|
||||||
import "../../../components/ha-checkbox";
|
import "../../../components/ha-checkbox";
|
||||||
import "../../../components/ha-icon-button";
|
import "../../../components/ha-icon-button";
|
||||||
@ -347,7 +348,7 @@ export class HuiTodoListCard extends LitElement implements LovelaceCard {
|
|||||||
.title=${this.hass!.localize(
|
.title=${this.hass!.localize(
|
||||||
"ui.panel.lovelace.cards.todo-list.drag_and_drop"
|
"ui.panel.lovelace.cards.todo-list.drag_and_drop"
|
||||||
)}
|
)}
|
||||||
class="reorderButton"
|
class="reorderButton handle"
|
||||||
.path=${mdiDrag}
|
.path=${mdiDrag}
|
||||||
>
|
>
|
||||||
</ha-svg-icon>
|
</ha-svg-icon>
|
||||||
@ -439,7 +440,21 @@ export class HuiTodoListCard extends LitElement implements LovelaceCard {
|
|||||||
}
|
}
|
||||||
const checkedItems = this._getCheckedItems(this._items);
|
const checkedItems = this._getCheckedItems(this._items);
|
||||||
const uids = checkedItems.map((item: TodoItem) => item.uid);
|
const uids = checkedItems.map((item: TodoItem) => item.uid);
|
||||||
deleteItems(this.hass!, this._entityId!, uids);
|
showConfirmationDialog(this, {
|
||||||
|
title: this.hass.localize(
|
||||||
|
"ui.panel.lovelace.cards.todo-list.delete_confirm_title"
|
||||||
|
),
|
||||||
|
text: this.hass.localize(
|
||||||
|
"ui.panel.lovelace.cards.todo-list.delete_confirm_text",
|
||||||
|
{ number: uids.length }
|
||||||
|
),
|
||||||
|
dismissText: this.hass.localize("ui.common.cancel"),
|
||||||
|
confirmText: this.hass.localize("ui.common.delete"),
|
||||||
|
destructive: true,
|
||||||
|
confirm: () => {
|
||||||
|
deleteItems(this.hass!, this._entityId!, uids);
|
||||||
|
},
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private get _newItem(): HaTextField {
|
private get _newItem(): HaTextField {
|
||||||
@ -583,6 +598,10 @@ export class HuiTodoListCard extends LitElement implements LovelaceCard {
|
|||||||
direction: var(--direction);
|
direction: var(--direction);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.handle {
|
||||||
|
cursor: move;
|
||||||
|
}
|
||||||
|
|
||||||
ha-checkbox {
|
ha-checkbox {
|
||||||
margin-left: -12px;
|
margin-left: -12px;
|
||||||
margin-inline-start: -12px;
|
margin-inline-start: -12px;
|
||||||
|
@ -263,7 +263,7 @@ export class HuiImage extends LitElement {
|
|||||||
>
|
>
|
||||||
<ha-circular-progress
|
<ha-circular-progress
|
||||||
class="render-spinner"
|
class="render-spinner"
|
||||||
active
|
indeterminate
|
||||||
size="small"
|
size="small"
|
||||||
></ha-circular-progress>
|
></ha-circular-progress>
|
||||||
</div>`
|
</div>`
|
||||||
|
@ -7,12 +7,14 @@ import "../card-features/hui-cover-tilt-card-feature";
|
|||||||
import "../card-features/hui-cover-tilt-position-card-feature";
|
import "../card-features/hui-cover-tilt-position-card-feature";
|
||||||
import "../card-features/hui-fan-speed-card-feature";
|
import "../card-features/hui-fan-speed-card-feature";
|
||||||
import "../card-features/hui-humidifier-modes-card-feature";
|
import "../card-features/hui-humidifier-modes-card-feature";
|
||||||
|
import "../card-features/hui-humidifier-toggle-card-feature";
|
||||||
import "../card-features/hui-lawn-mower-commands-card-feature";
|
import "../card-features/hui-lawn-mower-commands-card-feature";
|
||||||
import "../card-features/hui-light-brightness-card-feature";
|
import "../card-features/hui-light-brightness-card-feature";
|
||||||
import "../card-features/hui-light-color-temp-card-feature";
|
import "../card-features/hui-light-color-temp-card-feature";
|
||||||
import "../card-features/hui-numeric-input-card-feature";
|
import "../card-features/hui-numeric-input-card-feature";
|
||||||
import "../card-features/hui-select-options-card-feature";
|
import "../card-features/hui-select-options-card-feature";
|
||||||
import "../card-features/hui-target-temperature-card-feature";
|
import "../card-features/hui-target-temperature-card-feature";
|
||||||
|
import "../card-features/hui-target-humidity-card-feature";
|
||||||
import "../card-features/hui-vacuum-commands-card-feature";
|
import "../card-features/hui-vacuum-commands-card-feature";
|
||||||
import "../card-features/hui-water-heater-operation-modes-card-feature";
|
import "../card-features/hui-water-heater-operation-modes-card-feature";
|
||||||
import { LovelaceCardFeatureConfig } from "../card-features/types";
|
import { LovelaceCardFeatureConfig } from "../card-features/types";
|
||||||
@ -31,11 +33,13 @@ const TYPES: Set<LovelaceCardFeatureConfig["type"]> = new Set([
|
|||||||
"cover-tilt",
|
"cover-tilt",
|
||||||
"fan-speed",
|
"fan-speed",
|
||||||
"humidifier-modes",
|
"humidifier-modes",
|
||||||
|
"humidifier-toggle",
|
||||||
"lawn-mower-commands",
|
"lawn-mower-commands",
|
||||||
"light-brightness",
|
"light-brightness",
|
||||||
"light-color-temp",
|
"light-color-temp",
|
||||||
"numeric-input",
|
"numeric-input",
|
||||||
"select-options",
|
"select-options",
|
||||||
|
"target-humidity",
|
||||||
"target-temperature",
|
"target-temperature",
|
||||||
"vacuum-commands",
|
"vacuum-commands",
|
||||||
"water-heater-operation-modes",
|
"water-heater-operation-modes",
|
||||||
|
@ -142,8 +142,7 @@ export class HuiCardPicker extends LitElement {
|
|||||||
html`
|
html`
|
||||||
<div class="card spinner">
|
<div class="card spinner">
|
||||||
<ha-circular-progress
|
<ha-circular-progress
|
||||||
active
|
indeterminate
|
||||||
alt="Loading"
|
|
||||||
></ha-circular-progress>
|
></ha-circular-progress>
|
||||||
</div>
|
</div>
|
||||||
`
|
`
|
||||||
@ -238,7 +237,7 @@ export class HuiCardPicker extends LitElement {
|
|||||||
this._renderCardElement(card),
|
this._renderCardElement(card),
|
||||||
html`
|
html`
|
||||||
<div class="card spinner">
|
<div class="card spinner">
|
||||||
<ha-circular-progress active alt="Loading"></ha-circular-progress>
|
<ha-circular-progress indeterminate></ha-circular-progress>
|
||||||
</div>
|
</div>
|
||||||
`
|
`
|
||||||
)}`,
|
)}`,
|
||||||
|
@ -235,8 +235,8 @@ export class HuiDialogEditCard
|
|||||||
${this._error
|
${this._error
|
||||||
? html`
|
? html`
|
||||||
<ha-circular-progress
|
<ha-circular-progress
|
||||||
active
|
indeterminate
|
||||||
alt="Can't update card"
|
aria-label="Can't update card"
|
||||||
></ha-circular-progress>
|
></ha-circular-progress>
|
||||||
`
|
`
|
||||||
: ``}
|
: ``}
|
||||||
@ -271,8 +271,8 @@ export class HuiDialogEditCard
|
|||||||
${this._saving
|
${this._saving
|
||||||
? html`
|
? html`
|
||||||
<ha-circular-progress
|
<ha-circular-progress
|
||||||
active
|
indeterminate
|
||||||
title="Saving"
|
aria-label="Saving"
|
||||||
size="small"
|
size="small"
|
||||||
></ha-circular-progress>
|
></ha-circular-progress>
|
||||||
`
|
`
|
||||||
|
@ -110,8 +110,8 @@ export class HuiDialogSuggestCard extends LitElement {
|
|||||||
${this._saving
|
${this._saving
|
||||||
? html`
|
? html`
|
||||||
<ha-circular-progress
|
<ha-circular-progress
|
||||||
active
|
indeterminate
|
||||||
title="Saving"
|
aria-label="Saving"
|
||||||
size="small"
|
size="small"
|
||||||
></ha-circular-progress>
|
></ha-circular-progress>
|
||||||
`
|
`
|
||||||
|
@ -29,12 +29,14 @@ import { supportsCoverPositionCardFeature } from "../../card-features/hui-cover-
|
|||||||
import { supportsCoverTiltCardFeature } from "../../card-features/hui-cover-tilt-card-feature";
|
import { supportsCoverTiltCardFeature } from "../../card-features/hui-cover-tilt-card-feature";
|
||||||
import { supportsCoverTiltPositionCardFeature } from "../../card-features/hui-cover-tilt-position-card-feature";
|
import { supportsCoverTiltPositionCardFeature } from "../../card-features/hui-cover-tilt-position-card-feature";
|
||||||
import { supportsFanSpeedCardFeature } from "../../card-features/hui-fan-speed-card-feature";
|
import { supportsFanSpeedCardFeature } from "../../card-features/hui-fan-speed-card-feature";
|
||||||
|
import { supportsHumidifierToggleCardFeature } from "../../card-features/hui-humidifier-toggle-card-feature";
|
||||||
import { supportsHumidifierModesCardFeature } from "../../card-features/hui-humidifier-modes-card-feature";
|
import { supportsHumidifierModesCardFeature } from "../../card-features/hui-humidifier-modes-card-feature";
|
||||||
import { supportsLawnMowerCommandCardFeature } from "../../card-features/hui-lawn-mower-commands-card-feature";
|
import { supportsLawnMowerCommandCardFeature } from "../../card-features/hui-lawn-mower-commands-card-feature";
|
||||||
import { supportsLightBrightnessCardFeature } from "../../card-features/hui-light-brightness-card-feature";
|
import { supportsLightBrightnessCardFeature } from "../../card-features/hui-light-brightness-card-feature";
|
||||||
import { supportsLightColorTempCardFeature } from "../../card-features/hui-light-color-temp-card-feature";
|
import { supportsLightColorTempCardFeature } from "../../card-features/hui-light-color-temp-card-feature";
|
||||||
import { supportsNumericInputCardFeature } from "../../card-features/hui-numeric-input-card-feature";
|
import { supportsNumericInputCardFeature } from "../../card-features/hui-numeric-input-card-feature";
|
||||||
import { supportsSelectOptionsCardFeature } from "../../card-features/hui-select-options-card-feature";
|
import { supportsSelectOptionsCardFeature } from "../../card-features/hui-select-options-card-feature";
|
||||||
|
import { supportsTargetHumidityCardFeature } from "../../card-features/hui-target-humidity-card-feature";
|
||||||
import { supportsTargetTemperatureCardFeature } from "../../card-features/hui-target-temperature-card-feature";
|
import { supportsTargetTemperatureCardFeature } from "../../card-features/hui-target-temperature-card-feature";
|
||||||
import { supportsVacuumCommandsCardFeature } from "../../card-features/hui-vacuum-commands-card-feature";
|
import { supportsVacuumCommandsCardFeature } from "../../card-features/hui-vacuum-commands-card-feature";
|
||||||
import { supportsWaterHeaterOperationModesCardFeature } from "../../card-features/hui-water-heater-operation-modes-card-feature";
|
import { supportsWaterHeaterOperationModesCardFeature } from "../../card-features/hui-water-heater-operation-modes-card-feature";
|
||||||
@ -54,10 +56,12 @@ const UI_FEATURE_TYPES = [
|
|||||||
"cover-tilt",
|
"cover-tilt",
|
||||||
"fan-speed",
|
"fan-speed",
|
||||||
"humidifier-modes",
|
"humidifier-modes",
|
||||||
|
"humidifier-toggle",
|
||||||
"lawn-mower-commands",
|
"lawn-mower-commands",
|
||||||
"light-brightness",
|
"light-brightness",
|
||||||
"light-color-temp",
|
"light-color-temp",
|
||||||
"select-options",
|
"select-options",
|
||||||
|
"target-humidity",
|
||||||
"target-temperature",
|
"target-temperature",
|
||||||
"vacuum-commands",
|
"vacuum-commands",
|
||||||
"water-heater-operation-modes",
|
"water-heater-operation-modes",
|
||||||
@ -70,6 +74,7 @@ const EDITABLES_FEATURE_TYPES = new Set<UiFeatureTypes>([
|
|||||||
"vacuum-commands",
|
"vacuum-commands",
|
||||||
"alarm-modes",
|
"alarm-modes",
|
||||||
"climate-hvac-modes",
|
"climate-hvac-modes",
|
||||||
|
"humidifier-modes",
|
||||||
"water-heater-operation-modes",
|
"water-heater-operation-modes",
|
||||||
"lawn-mower-commands",
|
"lawn-mower-commands",
|
||||||
"climate-preset-modes",
|
"climate-preset-modes",
|
||||||
@ -89,10 +94,12 @@ const SUPPORTS_FEATURE_TYPES: Record<
|
|||||||
"cover-tilt": supportsCoverTiltCardFeature,
|
"cover-tilt": supportsCoverTiltCardFeature,
|
||||||
"fan-speed": supportsFanSpeedCardFeature,
|
"fan-speed": supportsFanSpeedCardFeature,
|
||||||
"humidifier-modes": supportsHumidifierModesCardFeature,
|
"humidifier-modes": supportsHumidifierModesCardFeature,
|
||||||
|
"humidifier-toggle": supportsHumidifierToggleCardFeature,
|
||||||
"lawn-mower-commands": supportsLawnMowerCommandCardFeature,
|
"lawn-mower-commands": supportsLawnMowerCommandCardFeature,
|
||||||
"light-brightness": supportsLightBrightnessCardFeature,
|
"light-brightness": supportsLightBrightnessCardFeature,
|
||||||
"light-color-temp": supportsLightColorTempCardFeature,
|
"light-color-temp": supportsLightColorTempCardFeature,
|
||||||
"numeric-input": supportsNumericInputCardFeature,
|
"numeric-input": supportsNumericInputCardFeature,
|
||||||
|
"target-humidity": supportsTargetHumidityCardFeature,
|
||||||
"target-temperature": supportsTargetTemperatureCardFeature,
|
"target-temperature": supportsTargetTemperatureCardFeature,
|
||||||
"vacuum-commands": supportsVacuumCommandsCardFeature,
|
"vacuum-commands": supportsVacuumCommandsCardFeature,
|
||||||
"water-heater-operation-modes": supportsWaterHeaterOperationModesCardFeature,
|
"water-heater-operation-modes": supportsWaterHeaterOperationModesCardFeature,
|
||||||
|
@ -14,15 +14,22 @@ import { HASSDomEvent, fireEvent } from "../../../../common/dom/fire_event";
|
|||||||
import "../../../../components/ha-form/ha-form";
|
import "../../../../components/ha-form/ha-form";
|
||||||
import type { SchemaUnion } from "../../../../components/ha-form/types";
|
import type { SchemaUnion } from "../../../../components/ha-form/types";
|
||||||
import type { HomeAssistant } from "../../../../types";
|
import type { HomeAssistant } from "../../../../types";
|
||||||
import type { HumidifierCardConfig } from "../../cards/types";
|
|
||||||
import {
|
import {
|
||||||
LovelaceCardFeatureConfig,
|
LovelaceCardFeatureConfig,
|
||||||
LovelaceCardFeatureContext,
|
LovelaceCardFeatureContext,
|
||||||
} from "../../card-features/types";
|
} from "../../card-features/types";
|
||||||
|
import type { HumidifierCardConfig } from "../../cards/types";
|
||||||
import type { LovelaceCardEditor } from "../../types";
|
import type { LovelaceCardEditor } from "../../types";
|
||||||
|
import "../hui-sub-element-editor";
|
||||||
import { baseLovelaceCardConfig } from "../structs/base-card-struct";
|
import { baseLovelaceCardConfig } from "../structs/base-card-struct";
|
||||||
import { EditSubElementEvent, SubElementEditorConfig } from "../types";
|
import { EditSubElementEvent, SubElementEditorConfig } from "../types";
|
||||||
import "./hui-card-features-editor";
|
import "./hui-card-features-editor";
|
||||||
|
import type { FeatureType } from "./hui-card-features-editor";
|
||||||
|
|
||||||
|
const COMPATIBLE_FEATURES_TYPES: FeatureType[] = [
|
||||||
|
"humidifier-modes",
|
||||||
|
"humidifier-toggle",
|
||||||
|
];
|
||||||
|
|
||||||
const cardConfigStruct = assign(
|
const cardConfigStruct = assign(
|
||||||
baseLovelaceCardConfig,
|
baseLovelaceCardConfig,
|
||||||
@ -103,6 +110,7 @@ export class HuiHumidifierCardEditor
|
|||||||
<hui-card-features-editor
|
<hui-card-features-editor
|
||||||
.hass=${this.hass}
|
.hass=${this.hass}
|
||||||
.stateObj=${stateObj}
|
.stateObj=${stateObj}
|
||||||
|
.featuresTypes=${COMPATIBLE_FEATURES_TYPES}
|
||||||
.features=${this._config!.features ?? []}
|
.features=${this._config!.features ?? []}
|
||||||
@features-changed=${this._featuresChanged}
|
@features-changed=${this._featuresChanged}
|
||||||
@edit-detail-element=${this._editDetailElement}
|
@edit-detail-element=${this._editDetailElement}
|
||||||
|
@ -0,0 +1,129 @@
|
|||||||
|
import { HassEntity } from "home-assistant-js-websocket";
|
||||||
|
import { html, LitElement, nothing } from "lit";
|
||||||
|
import { customElement, property, state } from "lit/decorators";
|
||||||
|
import memoizeOne from "memoize-one";
|
||||||
|
import { fireEvent } from "../../../../common/dom/fire_event";
|
||||||
|
import { FormatEntityAttributeValueFunc } from "../../../../common/translations/entity-state";
|
||||||
|
import { LocalizeFunc } from "../../../../common/translations/localize";
|
||||||
|
import "../../../../components/ha-form/ha-form";
|
||||||
|
import type {
|
||||||
|
HaFormSchema,
|
||||||
|
SchemaUnion,
|
||||||
|
} from "../../../../components/ha-form/types";
|
||||||
|
import type { HomeAssistant } from "../../../../types";
|
||||||
|
import {
|
||||||
|
HumidifierModesCardFeatureConfig,
|
||||||
|
LovelaceCardFeatureContext,
|
||||||
|
} from "../../card-features/types";
|
||||||
|
import type { LovelaceCardFeatureEditor } from "../../types";
|
||||||
|
|
||||||
|
@customElement("hui-humidifier-modes-card-feature-editor")
|
||||||
|
export class HuiHumidifierModesCardFeatureEditor
|
||||||
|
extends LitElement
|
||||||
|
implements LovelaceCardFeatureEditor
|
||||||
|
{
|
||||||
|
@property({ attribute: false }) public hass?: HomeAssistant;
|
||||||
|
|
||||||
|
@property({ attribute: false }) public context?: LovelaceCardFeatureContext;
|
||||||
|
|
||||||
|
@state() private _config?: HumidifierModesCardFeatureConfig;
|
||||||
|
|
||||||
|
public setConfig(config: HumidifierModesCardFeatureConfig): void {
|
||||||
|
this._config = config;
|
||||||
|
}
|
||||||
|
|
||||||
|
private _schema = memoizeOne(
|
||||||
|
(
|
||||||
|
localize: LocalizeFunc,
|
||||||
|
formatEntityAttributeValue: FormatEntityAttributeValueFunc,
|
||||||
|
stateObj?: HassEntity
|
||||||
|
) =>
|
||||||
|
[
|
||||||
|
{
|
||||||
|
name: "style",
|
||||||
|
selector: {
|
||||||
|
select: {
|
||||||
|
multiple: false,
|
||||||
|
mode: "list",
|
||||||
|
options: ["dropdown", "icons"].map((mode) => ({
|
||||||
|
value: mode,
|
||||||
|
label: localize(
|
||||||
|
`ui.panel.lovelace.editor.features.types.humidifier-modes.style_list.${mode}`
|
||||||
|
),
|
||||||
|
})),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "modes",
|
||||||
|
selector: {
|
||||||
|
select: {
|
||||||
|
multiple: true,
|
||||||
|
mode: "list",
|
||||||
|
options:
|
||||||
|
stateObj?.attributes.available_modes?.map((mode) => ({
|
||||||
|
value: mode,
|
||||||
|
label: formatEntityAttributeValue(stateObj, "mode", mode),
|
||||||
|
})) || [],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
] as const satisfies readonly HaFormSchema[]
|
||||||
|
);
|
||||||
|
|
||||||
|
protected render() {
|
||||||
|
if (!this.hass || !this._config) {
|
||||||
|
return nothing;
|
||||||
|
}
|
||||||
|
|
||||||
|
const stateObj = this.context?.entity_id
|
||||||
|
? this.hass.states[this.context?.entity_id]
|
||||||
|
: undefined;
|
||||||
|
|
||||||
|
const data: HumidifierModesCardFeatureConfig = {
|
||||||
|
style: "dropdown",
|
||||||
|
modes: [],
|
||||||
|
...this._config,
|
||||||
|
};
|
||||||
|
|
||||||
|
const schema = this._schema(
|
||||||
|
this.hass.localize,
|
||||||
|
this.hass.formatEntityAttributeValue,
|
||||||
|
stateObj
|
||||||
|
);
|
||||||
|
|
||||||
|
return html`
|
||||||
|
<ha-form
|
||||||
|
.hass=${this.hass}
|
||||||
|
.data=${data}
|
||||||
|
.schema=${schema}
|
||||||
|
.computeLabel=${this._computeLabelCallback}
|
||||||
|
@value-changed=${this._valueChanged}
|
||||||
|
></ha-form>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
private _valueChanged(ev: CustomEvent): void {
|
||||||
|
fireEvent(this, "config-changed", { config: ev.detail.value });
|
||||||
|
}
|
||||||
|
|
||||||
|
private _computeLabelCallback = (
|
||||||
|
schema: SchemaUnion<ReturnType<typeof this._schema>>
|
||||||
|
) => {
|
||||||
|
switch (schema.name) {
|
||||||
|
case "style":
|
||||||
|
case "modes":
|
||||||
|
return this.hass!.localize(
|
||||||
|
`ui.panel.lovelace.editor.features.types.humidifier-modes.${schema.name}`
|
||||||
|
);
|
||||||
|
default:
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
declare global {
|
||||||
|
interface HTMLElementTagNameMap {
|
||||||
|
"hui-humidifier-modes-card-feature-editor": HuiHumidifierModesCardFeatureEditor;
|
||||||
|
}
|
||||||
|
}
|
@ -87,6 +87,8 @@ const HIDDEN_ATTRIBUTES = [
|
|||||||
"unit_of_measurement",
|
"unit_of_measurement",
|
||||||
"visibility_unit",
|
"visibility_unit",
|
||||||
"wind_speed_unit",
|
"wind_speed_unit",
|
||||||
|
"battery_icon",
|
||||||
|
"battery_level",
|
||||||
];
|
];
|
||||||
|
|
||||||
const cardConfigStruct = assign(
|
const cardConfigStruct = assign(
|
||||||
|
@ -132,9 +132,9 @@ export class HuiSaveConfig extends LitElement implements HassDialog {
|
|||||||
>
|
>
|
||||||
${this._saving
|
${this._saving
|
||||||
? html`<ha-circular-progress
|
? html`<ha-circular-progress
|
||||||
active
|
indeterminate
|
||||||
size="small"
|
size="small"
|
||||||
title="Saving"
|
aria-label="Saving"
|
||||||
></ha-circular-progress>`
|
></ha-circular-progress>`
|
||||||
: ""}
|
: ""}
|
||||||
${this.hass!.localize(
|
${this.hass!.localize(
|
||||||
|
@ -207,8 +207,7 @@ export abstract class HuiElementEditor<T, C = any> extends LitElement {
|
|||||||
${this._loading
|
${this._loading
|
||||||
? html`
|
? html`
|
||||||
<ha-circular-progress
|
<ha-circular-progress
|
||||||
active
|
indeterminate
|
||||||
alt="Loading"
|
|
||||||
class="center margin-bot"
|
class="center margin-bot"
|
||||||
></ha-circular-progress>
|
></ha-circular-progress>
|
||||||
`
|
`
|
||||||
|
@ -63,9 +63,9 @@ export class HuiDialogEditLovelace extends LitElement {
|
|||||||
>
|
>
|
||||||
${this._saving
|
${this._saving
|
||||||
? html`<ha-circular-progress
|
? html`<ha-circular-progress
|
||||||
active
|
indeterminate
|
||||||
size="small"
|
size="small"
|
||||||
title="Saving"
|
aria-label="Saving"
|
||||||
></ha-circular-progress>`
|
></ha-circular-progress>`
|
||||||
: ""}
|
: ""}
|
||||||
${this.hass!.localize("ui.common.save")}</mwc-button
|
${this.hass!.localize("ui.common.save")}</mwc-button
|
||||||
|
@ -323,9 +323,9 @@ export class HuiDialogEditView extends LitElement {
|
|||||||
>
|
>
|
||||||
${this._saving
|
${this._saving
|
||||||
? html`<ha-circular-progress
|
? html`<ha-circular-progress
|
||||||
active
|
indeterminate
|
||||||
size="small"
|
size="small"
|
||||||
title="Saving"
|
aria-label="Saving"
|
||||||
></ha-circular-progress>`
|
></ha-circular-progress>`
|
||||||
: ""}
|
: ""}
|
||||||
${this.hass!.localize("ui.common.save")}</mwc-button
|
${this.hass!.localize("ui.common.save")}</mwc-button
|
||||||
@ -528,7 +528,7 @@ export class HuiDialogEditView extends LitElement {
|
|||||||
ha-circular-progress {
|
ha-circular-progress {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
ha-circular-progress[active] {
|
ha-circular-progress[indeterminate] {
|
||||||
display: block;
|
display: block;
|
||||||
}
|
}
|
||||||
.selected_menu_item {
|
.selected_menu_item {
|
||||||
|
@ -111,7 +111,10 @@ export class HuiGraphHeaderFooter
|
|||||||
if (!this._coordinates) {
|
if (!this._coordinates) {
|
||||||
return html`
|
return html`
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<ha-circular-progress active size="small"></ha-circular-progress>
|
<ha-circular-progress
|
||||||
|
indeterminate
|
||||||
|
size="small"
|
||||||
|
></ha-circular-progress>
|
||||||
</div>
|
</div>
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user