mirror of
https://github.com/home-assistant/frontend.git
synced 2026-07-03 05:33:16 +00:00
Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 294967014d |
@@ -1,88 +0,0 @@
|
||||
import { css, html, LitElement, TemplateResult } from "lit";
|
||||
import { customElement } from "lit/decorators";
|
||||
import "../../../src/components/ha-card";
|
||||
import "../../../src/components/ha-faded";
|
||||
import "../../../src/components/ha-markdown";
|
||||
|
||||
const LONG_TEXT = `
|
||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nunc laoreet velit ut elit volutpat, eget ultrices odio lacinia. In imperdiet malesuada est, nec sagittis metus ultricies quis. Sed nisl ex, convallis porttitor ante quis, hendrerit tristique justo. Mauris pharetra venenatis augue, eu maximus sem cursus in. Quisque sed consequat risus. Suspendisse facilisis ligula a odio consectetur condimentum. Curabitur vehicula elit nec augue mollis, et volutpat massa dictum.
|
||||
|
||||
Nam pellentesque auctor rutrum. Suspendisse elit est, sodales vel diam nec, porttitor faucibus massa. Ut pretium ac orci eu pharetra. Praesent in nibh at magna viverra rutrum eu vitae tortor. Etiam eget sem ex. Fusce tristique odio nec lacus mattis, vitae tempor nunc malesuada. Maecenas faucibus magna vel libero maximus egestas. Vestibulum luctus semper velit, in lobortis risus tempus non. Curabitur bibendum ornare commodo. Quisque commodo neque sit amet tincidunt lacinia. Proin elementum ante velit, eu congue nulla semper quis. Pellentesque consequat vel nunc at scelerisque. Mauris sit amet venenatis diam, blandit viverra leo. Integer commodo laoreet orci.
|
||||
|
||||
Curabitur ipsum tortor, sodales ut augue sed, commodo porttitor libero. Pellentesque molestie vitae mi consectetur tempor. In sed lectus consequat, lobortis neque non, semper ipsum. Etiam eget ex et nibh sagittis pulvinar lacinia ac mauris. Aenean ligula eros, viverra ac nibh at, venenatis semper quam. Sed interdum ligula sit amet massa tincidunt tincidunt. Suspendisse potenti. Aliquam egestas facilisis est, sed faucibus erat scelerisque id. Duis dolor quam, viverra vitae orci euismod, laoreet pellentesque justo. Nunc malesuada non erat at ullamcorper. Mauris eget posuere odio. Vestibulum turpis nunc, pharetra eget ante in, feugiat mollis justo. Proin porttitor, diam nec vulputate pretium, tellus arcu rhoncus turpis, a blandit nisi nulla quis arcu. Nunc ac ullamcorper ligula, nec facilisis leo.
|
||||
|
||||
In vitae eros sollicitudin, iaculis ex eget, egestas orci. Etiam sed pretium lorem. Nam nisi enim, consectetur sit amet semper ac, semper pharetra diam. In pulvinar neque sapien, ac ullamcorper est lacinia a. Etiam tincidunt velit sed diam malesuada, eu ornare ex consectetur. Phasellus in imperdiet tellus. Sed bibendum, dui sit amet fringilla aliquet, enim odio sollicitudin lorem, vel semper turpis mauris vel mauris. Aenean congue magna ac massa cursus, in dictum orci commodo. Pellentesque mollis velit in sollicitudin tincidunt. Vestibulum et efficitur nulla.
|
||||
|
||||
Quisque posuere, velit sed porttitor dapibus, neque augue fringilla felis, eu luctus nisi nisl nec ipsum. Curabitur pellentesque ac lectus eget ultricies. Vestibulum est dolor, lacinia pharetra vulputate a, facilisis a magna. Nam vitae arcu nibh. Praesent finibus blandit ante, ac gravida ex mollis eget. Donec quam est, pulvinar vitae neque ut, bibendum aliquam erat. Nullam mollis arcu at sem tincidunt, in tristique lectus facilisis. Aenean ut lacus vel nisl finibus iaculis non a turpis. Integer eget ipsum ante. Donec nunc neque, vestibulum ac magna ac, posuere scelerisque dui. Pellentesque massa nibh, rhoncus id dolor quis, placerat posuere turpis. Donec aliquet augue nisi, eu finibus dui auctor et. Vestibulum eu varius lorem. Quisque lectus ante, malesuada pretium risus eget, interdum mattis enim.
|
||||
`;
|
||||
|
||||
const SMALL_TEXT = "Lorem ipsum dolor sit amet, consectetur adipiscing elit.";
|
||||
|
||||
@customElement("demo-ha-faded")
|
||||
export class DemoHaFaded extends LitElement {
|
||||
protected render(): TemplateResult {
|
||||
return html`
|
||||
<ha-card header="ha-faded demo">
|
||||
<div class="card-content">
|
||||
<h3>Long text directly as slotted content</h3>
|
||||
<ha-faded>${LONG_TEXT}</ha-faded>
|
||||
<h3>Long text with slotted element</h3>
|
||||
<ha-faded><span>${LONG_TEXT}</span></ha-faded>
|
||||
<h3>No text</h3>
|
||||
<ha-faded><span></span></ha-faded>
|
||||
<h3>Smal text</h3>
|
||||
<ha-faded><span>${SMALL_TEXT}</span></ha-faded>
|
||||
<h3>Long text in markdown</h3>
|
||||
<ha-faded>
|
||||
<ha-markdown .content=${LONG_TEXT}> </ha-markdown>
|
||||
</ha-faded>
|
||||
<h3>Missing 1px from hiding</h3>
|
||||
<ha-faded faded-height="87">
|
||||
<span>
|
||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nunc
|
||||
laoreet velit ut elit volutpat, eget ultrices odio lacinia. In
|
||||
imperdiet malesuada est, nec sagittis metus ultricies quis. Sed
|
||||
nisl ex, convallis porttitor ante quis, hendrerit tristique justo.
|
||||
Mauris pharetra venenatis augue, eu maximus sem cursus in. Quisque
|
||||
sed consequat risus. Suspendisse facilisis ligula a odio
|
||||
consectetur condimentum. Curabitur vehicula elit nec augue mollis,
|
||||
et volutpat massa dictum. Nam pellentesque auctor rutrum.
|
||||
Suspendisse elit est, sodales vel diam nec, porttitor faucibus
|
||||
massa. Ut pretium ac orci eu pharetra.
|
||||
</span>
|
||||
</ha-faded>
|
||||
<h3>1px over hiding point</h3>
|
||||
<ha-faded faded-height="85">
|
||||
<span>
|
||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nunc
|
||||
laoreet velit ut elit volutpat, eget ultrices odio lacinia. In
|
||||
imperdiet malesuada est, nec sagittis metus ultricies quis. Sed
|
||||
nisl ex, convallis porttitor ante quis, hendrerit tristique justo.
|
||||
Mauris pharetra venenatis augue, eu maximus sem cursus in. Quisque
|
||||
sed consequat risus. Suspendisse facilisis ligula a odio
|
||||
consectetur condimentum. Curabitur vehicula elit nec augue mollis,
|
||||
et volutpat massa dictum. Nam pellentesque auctor rutrum.
|
||||
Suspendisse elit est, sodales vel diam nec, porttitor faucibus
|
||||
massa. Ut pretium ac orci eu pharetra.
|
||||
</span>
|
||||
</ha-faded>
|
||||
</div>
|
||||
</ha-card>
|
||||
`;
|
||||
}
|
||||
|
||||
static get styles() {
|
||||
return css`
|
||||
ha-card {
|
||||
max-width: 600px;
|
||||
margin: 24px auto;
|
||||
}
|
||||
`;
|
||||
}
|
||||
}
|
||||
|
||||
declare global {
|
||||
interface HTMLElementTagNameMap {
|
||||
"demo-ha-faded": DemoHaFaded;
|
||||
}
|
||||
}
|
||||
@@ -1,164 +0,0 @@
|
||||
import { html, LitElement, PropertyValues, TemplateResult } from "lit";
|
||||
import { customElement, property, query } from "lit/decorators";
|
||||
import "../../../src/components/ha-card";
|
||||
import {
|
||||
SUPPORT_OPEN,
|
||||
SUPPORT_STOP,
|
||||
SUPPORT_CLOSE,
|
||||
SUPPORT_SET_POSITION,
|
||||
SUPPORT_OPEN_TILT,
|
||||
SUPPORT_STOP_TILT,
|
||||
SUPPORT_CLOSE_TILT,
|
||||
SUPPORT_SET_TILT_POSITION,
|
||||
} from "../../../src/data/cover";
|
||||
import "../../../src/dialogs/more-info/more-info-content";
|
||||
import { getEntity } from "../../../src/fake_data/entity";
|
||||
import {
|
||||
MockHomeAssistant,
|
||||
provideHass,
|
||||
} from "../../../src/fake_data/provide_hass";
|
||||
import "../components/demo-more-infos";
|
||||
|
||||
const ENTITIES = [
|
||||
getEntity("cover", "position_buttons", "on", {
|
||||
friendly_name: "Position Buttons",
|
||||
supported_features: SUPPORT_OPEN + SUPPORT_STOP + SUPPORT_CLOSE,
|
||||
}),
|
||||
getEntity("cover", "position_slider_half", "on", {
|
||||
friendly_name: "Position Half-Open",
|
||||
supported_features:
|
||||
SUPPORT_OPEN + SUPPORT_STOP + SUPPORT_CLOSE + SUPPORT_SET_POSITION,
|
||||
current_position: 50,
|
||||
}),
|
||||
getEntity("cover", "position_slider_open", "on", {
|
||||
friendly_name: "Position Open",
|
||||
supported_features:
|
||||
SUPPORT_OPEN + SUPPORT_STOP + SUPPORT_CLOSE + SUPPORT_SET_POSITION,
|
||||
current_position: 100,
|
||||
}),
|
||||
getEntity("cover", "position_slider_closed", "on", {
|
||||
friendly_name: "Position Closed",
|
||||
supported_features:
|
||||
SUPPORT_OPEN + SUPPORT_STOP + SUPPORT_CLOSE + SUPPORT_SET_POSITION,
|
||||
current_position: 0,
|
||||
}),
|
||||
getEntity("cover", "tilt_buttons", "on", {
|
||||
friendly_name: "Tilt Buttons",
|
||||
supported_features:
|
||||
SUPPORT_OPEN_TILT + SUPPORT_STOP_TILT + SUPPORT_CLOSE_TILT,
|
||||
}),
|
||||
getEntity("cover", "tilt_slider_half", "on", {
|
||||
friendly_name: "Tilt Half-Open",
|
||||
supported_features:
|
||||
SUPPORT_OPEN_TILT +
|
||||
SUPPORT_STOP_TILT +
|
||||
SUPPORT_CLOSE_TILT +
|
||||
SUPPORT_SET_TILT_POSITION,
|
||||
current_tilt_position: 50,
|
||||
}),
|
||||
getEntity("cover", "tilt_slider_open", "on", {
|
||||
friendly_name: "Tilt Open",
|
||||
supported_features:
|
||||
SUPPORT_OPEN_TILT +
|
||||
SUPPORT_STOP_TILT +
|
||||
SUPPORT_CLOSE_TILT +
|
||||
SUPPORT_SET_TILT_POSITION,
|
||||
current_tilt_position: 100,
|
||||
}),
|
||||
getEntity("cover", "tilt_slider_closed", "on", {
|
||||
friendly_name: "Tilt Closed",
|
||||
supported_features:
|
||||
SUPPORT_OPEN_TILT +
|
||||
SUPPORT_STOP_TILT +
|
||||
SUPPORT_CLOSE_TILT +
|
||||
SUPPORT_SET_TILT_POSITION,
|
||||
current_tilt_position: 0,
|
||||
}),
|
||||
getEntity("cover", "position_slider_tilt_slider", "on", {
|
||||
friendly_name: "Both Sliders",
|
||||
supported_features:
|
||||
SUPPORT_OPEN +
|
||||
SUPPORT_STOP +
|
||||
SUPPORT_CLOSE +
|
||||
SUPPORT_SET_POSITION +
|
||||
SUPPORT_OPEN_TILT +
|
||||
SUPPORT_STOP_TILT +
|
||||
SUPPORT_CLOSE_TILT +
|
||||
SUPPORT_SET_TILT_POSITION,
|
||||
current_position: 30,
|
||||
current_tilt_position: 70,
|
||||
}),
|
||||
getEntity("cover", "position_tilt_slider", "on", {
|
||||
friendly_name: "Position & Tilt Slider",
|
||||
supported_features:
|
||||
SUPPORT_OPEN +
|
||||
SUPPORT_STOP +
|
||||
SUPPORT_CLOSE +
|
||||
SUPPORT_OPEN_TILT +
|
||||
SUPPORT_STOP_TILT +
|
||||
SUPPORT_CLOSE_TILT +
|
||||
SUPPORT_SET_TILT_POSITION,
|
||||
current_tilt_position: 70,
|
||||
}),
|
||||
getEntity("cover", "position_slider_tilt", "on", {
|
||||
friendly_name: "Position Slider & Tilt",
|
||||
supported_features:
|
||||
SUPPORT_OPEN +
|
||||
SUPPORT_STOP +
|
||||
SUPPORT_CLOSE +
|
||||
SUPPORT_SET_POSITION +
|
||||
SUPPORT_OPEN_TILT +
|
||||
SUPPORT_STOP_TILT +
|
||||
SUPPORT_CLOSE_TILT,
|
||||
current_position: 30,
|
||||
}),
|
||||
getEntity("cover", "position_slider_only_tilt_slider", "on", {
|
||||
friendly_name: "Position Slider Only & Tilt Buttons",
|
||||
supported_features:
|
||||
SUPPORT_SET_POSITION +
|
||||
SUPPORT_OPEN_TILT +
|
||||
SUPPORT_STOP_TILT +
|
||||
SUPPORT_CLOSE_TILT,
|
||||
current_position: 30,
|
||||
}),
|
||||
getEntity("cover", "position_slider_only_tilt", "on", {
|
||||
friendly_name: "Position Slider Only & Tilt",
|
||||
supported_features:
|
||||
SUPPORT_SET_POSITION +
|
||||
SUPPORT_OPEN_TILT +
|
||||
SUPPORT_STOP_TILT +
|
||||
SUPPORT_CLOSE_TILT +
|
||||
SUPPORT_SET_TILT_POSITION,
|
||||
current_position: 30,
|
||||
current_tilt_position: 70,
|
||||
}),
|
||||
];
|
||||
|
||||
@customElement("demo-more-info-cover")
|
||||
class DemoMoreInfoCover extends LitElement {
|
||||
@property() public hass!: MockHomeAssistant;
|
||||
|
||||
@query("demo-more-infos") private _demoRoot!: HTMLElement;
|
||||
|
||||
protected render(): TemplateResult {
|
||||
return html`
|
||||
<demo-more-infos
|
||||
.hass=${this.hass}
|
||||
.entities=${ENTITIES.map((ent) => ent.entityId)}
|
||||
></demo-more-infos>
|
||||
`;
|
||||
}
|
||||
|
||||
protected firstUpdated(changedProperties: PropertyValues) {
|
||||
super.firstUpdated(changedProperties);
|
||||
const hass = provideHass(this._demoRoot);
|
||||
hass.updateTranslations(null, "en");
|
||||
hass.addEntities(ENTITIES);
|
||||
}
|
||||
}
|
||||
|
||||
declare global {
|
||||
interface HTMLElementTagNameMap {
|
||||
"demo-more-info-cover": DemoMoreInfoCover;
|
||||
}
|
||||
}
|
||||
@@ -16,7 +16,7 @@ import "../../../src/components/ha-alert";
|
||||
import "../../../src/components/ha-button-menu";
|
||||
import "../../../src/components/ha-card";
|
||||
import "../../../src/components/ha-checkbox";
|
||||
import "../../../src/components/ha-faded";
|
||||
import "../../../src/components/ha-expansion-panel";
|
||||
import "../../../src/components/ha-formfield";
|
||||
import "../../../src/components/ha-icon-button";
|
||||
import "../../../src/components/ha-markdown";
|
||||
@@ -136,10 +136,10 @@ class UpdateAvailableCard extends LitElement {
|
||||
? html`
|
||||
${this._changelogContent
|
||||
? html`
|
||||
<ha-faded>
|
||||
<ha-expansion-panel header="Changelog" outlined>
|
||||
<ha-markdown .content=${this._changelogContent}>
|
||||
</ha-markdown>
|
||||
</ha-faded>
|
||||
</ha-expansion-panel>
|
||||
`
|
||||
: ""}
|
||||
<div class="versions">
|
||||
@@ -387,6 +387,9 @@ class UpdateAvailableCard extends LitElement {
|
||||
ha-markdown {
|
||||
padding-bottom: 8px;
|
||||
}
|
||||
ha-formfield {
|
||||
cursor: pointer;
|
||||
}
|
||||
`;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@ from setuptools import setup, find_packages
|
||||
|
||||
setup(
|
||||
name="home-assistant-frontend",
|
||||
version="20211130.0",
|
||||
version="20211123.0",
|
||||
description="The Home Assistant frontend",
|
||||
url="https://github.com/home-assistant/frontend",
|
||||
author="The Home Assistant Authors",
|
||||
|
||||
@@ -95,7 +95,7 @@ export default class HaChartBase extends LitElement {
|
||||
borderColor: dataset.borderColor as string,
|
||||
})}
|
||||
></div>
|
||||
<div class="label">${dataset.label}</div>
|
||||
${dataset.label}
|
||||
</li>`
|
||||
)}
|
||||
</ul>
|
||||
@@ -278,9 +278,11 @@ export default class HaChartBase extends LitElement {
|
||||
}
|
||||
.chartLegend li {
|
||||
cursor: pointer;
|
||||
display: inline-grid;
|
||||
grid-auto-flow: column;
|
||||
display: inline-flex;
|
||||
padding: 0 8px;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
box-sizing: border-box;
|
||||
align-items: center;
|
||||
color: var(--secondary-text-color);
|
||||
@@ -288,11 +290,6 @@ export default class HaChartBase extends LitElement {
|
||||
.chartLegend .hidden {
|
||||
text-decoration: line-through;
|
||||
}
|
||||
.chartLegend .label {
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
}
|
||||
.chartLegend .bullet,
|
||||
.chartTooltip .bullet {
|
||||
border-width: 1px;
|
||||
|
||||
@@ -1,30 +1,39 @@
|
||||
import { mdiStop } from "@mdi/js";
|
||||
import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit";
|
||||
import { customElement, property } from "lit/decorators";
|
||||
import type { HassEntity } from "home-assistant-js-websocket";
|
||||
import {
|
||||
css,
|
||||
CSSResultGroup,
|
||||
html,
|
||||
LitElement,
|
||||
PropertyValues,
|
||||
TemplateResult,
|
||||
} from "lit";
|
||||
import { customElement, property, state } from "lit/decorators";
|
||||
import { classMap } from "lit/directives/class-map";
|
||||
import { computeCloseIcon, computeOpenIcon } from "../common/entity/cover_icon";
|
||||
import {
|
||||
CoverEntity,
|
||||
isClosing,
|
||||
isFullyClosed,
|
||||
isFullyOpen,
|
||||
isOpening,
|
||||
supportsClose,
|
||||
supportsOpen,
|
||||
supportsStop,
|
||||
} from "../data/cover";
|
||||
import { UNAVAILABLE } from "../data/entity";
|
||||
import type { HomeAssistant } from "../types";
|
||||
import CoverEntity from "../util/cover-model";
|
||||
import "./ha-icon-button";
|
||||
|
||||
@customElement("ha-cover-controls")
|
||||
class HaCoverControls extends LitElement {
|
||||
@property({ attribute: false }) public hass!: HomeAssistant;
|
||||
|
||||
@property({ attribute: false }) public stateObj!: CoverEntity;
|
||||
@property({ attribute: false }) public stateObj!: HassEntity;
|
||||
|
||||
@state() private _entityObj?: CoverEntity;
|
||||
|
||||
public willUpdate(changedProperties: PropertyValues): void {
|
||||
super.willUpdate(changedProperties);
|
||||
|
||||
if (changedProperties.has("stateObj")) {
|
||||
this._entityObj = new CoverEntity(this.hass, this.stateObj);
|
||||
}
|
||||
}
|
||||
|
||||
protected render(): TemplateResult {
|
||||
if (!this.stateObj) {
|
||||
if (!this._entityObj) {
|
||||
return html``;
|
||||
}
|
||||
|
||||
@@ -32,7 +41,7 @@ class HaCoverControls extends LitElement {
|
||||
<div class="state">
|
||||
<ha-icon-button
|
||||
class=${classMap({
|
||||
hidden: !supportsOpen(this.stateObj),
|
||||
hidden: !this._entityObj.supportsOpen,
|
||||
})}
|
||||
.label=${this.hass.localize(
|
||||
"ui.dialogs.more_info_control.open_cover"
|
||||
@@ -44,7 +53,7 @@ class HaCoverControls extends LitElement {
|
||||
</ha-icon-button>
|
||||
<ha-icon-button
|
||||
class=${classMap({
|
||||
hidden: !supportsStop(this.stateObj),
|
||||
hidden: !this._entityObj.supportsStop,
|
||||
})}
|
||||
.label=${this.hass.localize(
|
||||
"ui.dialogs.more_info_control.stop_cover"
|
||||
@@ -55,7 +64,7 @@ class HaCoverControls extends LitElement {
|
||||
></ha-icon-button>
|
||||
<ha-icon-button
|
||||
class=${classMap({
|
||||
hidden: !supportsClose(this.stateObj),
|
||||
hidden: !this._entityObj.supportsClose,
|
||||
})}
|
||||
.label=${this.hass.localize(
|
||||
"ui.dialogs.more_info_control.close_cover"
|
||||
@@ -75,7 +84,8 @@ class HaCoverControls extends LitElement {
|
||||
}
|
||||
const assumedState = this.stateObj.attributes.assumed_state === true;
|
||||
return (
|
||||
(isFullyOpen(this.stateObj) || isOpening(this.stateObj)) && !assumedState
|
||||
(this._entityObj.isFullyOpen || this._entityObj.isOpening) &&
|
||||
!assumedState
|
||||
);
|
||||
}
|
||||
|
||||
@@ -85,30 +95,24 @@ class HaCoverControls extends LitElement {
|
||||
}
|
||||
const assumedState = this.stateObj.attributes.assumed_state === true;
|
||||
return (
|
||||
(isFullyClosed(this.stateObj) || isClosing(this.stateObj)) &&
|
||||
(this._entityObj.isFullyClosed || this._entityObj.isClosing) &&
|
||||
!assumedState
|
||||
);
|
||||
}
|
||||
|
||||
private _onOpenTap(ev): void {
|
||||
ev.stopPropagation();
|
||||
this.hass.callService("cover", "open_cover", {
|
||||
entity_id: this.stateObj.entity_id,
|
||||
});
|
||||
this._entityObj.openCover();
|
||||
}
|
||||
|
||||
private _onCloseTap(ev): void {
|
||||
ev.stopPropagation();
|
||||
this.hass.callService("cover", "close_cover", {
|
||||
entity_id: this.stateObj.entity_id,
|
||||
});
|
||||
this._entityObj.closeCover();
|
||||
}
|
||||
|
||||
private _onStopTap(ev): void {
|
||||
ev.stopPropagation();
|
||||
this.hass.callService("cover", "stop_cover", {
|
||||
entity_id: this.stateObj.entity_id,
|
||||
});
|
||||
this._entityObj.stopCover();
|
||||
}
|
||||
|
||||
static get styles(): CSSResultGroup {
|
||||
|
||||
@@ -1,33 +1,44 @@
|
||||
import { mdiArrowBottomLeft, mdiArrowTopRight, mdiStop } from "@mdi/js";
|
||||
import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit";
|
||||
import { customElement, property } from "lit/decorators";
|
||||
import { classMap } from "lit/directives/class-map";
|
||||
import { HassEntity } from "home-assistant-js-websocket";
|
||||
import {
|
||||
CoverEntity,
|
||||
isFullyClosedTilt,
|
||||
isFullyOpenTilt,
|
||||
supportsCloseTilt,
|
||||
supportsOpenTilt,
|
||||
supportsStopTilt,
|
||||
} from "../data/cover";
|
||||
css,
|
||||
CSSResultGroup,
|
||||
html,
|
||||
LitElement,
|
||||
PropertyValues,
|
||||
TemplateResult,
|
||||
} from "lit";
|
||||
import { customElement, property, state } from "lit/decorators";
|
||||
import { classMap } from "lit/directives/class-map";
|
||||
import { UNAVAILABLE } from "../data/entity";
|
||||
import { HomeAssistant } from "../types";
|
||||
import CoverEntity from "../util/cover-model";
|
||||
import "./ha-icon-button";
|
||||
|
||||
@customElement("ha-cover-tilt-controls")
|
||||
class HaCoverTiltControls extends LitElement {
|
||||
@property({ attribute: false }) public hass!: HomeAssistant;
|
||||
|
||||
@property({ attribute: false }) stateObj!: CoverEntity;
|
||||
@property({ attribute: false }) stateObj!: HassEntity;
|
||||
|
||||
@state() private _entityObj?: CoverEntity;
|
||||
|
||||
public willUpdate(changedProperties: PropertyValues): void {
|
||||
super.willUpdate(changedProperties);
|
||||
|
||||
if (changedProperties.has("stateObj")) {
|
||||
this._entityObj = new CoverEntity(this.hass, this.stateObj);
|
||||
}
|
||||
}
|
||||
|
||||
protected render(): TemplateResult {
|
||||
if (!this.stateObj) {
|
||||
if (!this._entityObj) {
|
||||
return html``;
|
||||
}
|
||||
|
||||
return html` <ha-icon-button
|
||||
class=${classMap({
|
||||
invisible: !supportsOpenTilt(this.stateObj),
|
||||
invisible: !this._entityObj.supportsOpenTilt,
|
||||
})}
|
||||
.label=${this.hass.localize(
|
||||
"ui.dialogs.more_info_control.open_tilt_cover"
|
||||
@@ -38,7 +49,7 @@ class HaCoverTiltControls extends LitElement {
|
||||
></ha-icon-button>
|
||||
<ha-icon-button
|
||||
class=${classMap({
|
||||
invisible: !supportsStopTilt(this.stateObj),
|
||||
invisible: !this._entityObj.supportsStopTilt,
|
||||
})}
|
||||
.label=${this.hass.localize("ui.dialogs.more_info_control.stop_cover")}
|
||||
.path=${mdiStop}
|
||||
@@ -47,7 +58,7 @@ class HaCoverTiltControls extends LitElement {
|
||||
></ha-icon-button>
|
||||
<ha-icon-button
|
||||
class=${classMap({
|
||||
invisible: !supportsCloseTilt(this.stateObj),
|
||||
invisible: !this._entityObj.supportsCloseTilt,
|
||||
})}
|
||||
.label=${this.hass.localize(
|
||||
"ui.dialogs.more_info_control.close_tilt_cover"
|
||||
@@ -63,7 +74,7 @@ class HaCoverTiltControls extends LitElement {
|
||||
return true;
|
||||
}
|
||||
const assumedState = this.stateObj.attributes.assumed_state === true;
|
||||
return isFullyOpenTilt(this.stateObj) && !assumedState;
|
||||
return this._entityObj.isFullyOpenTilt && !assumedState;
|
||||
}
|
||||
|
||||
private _computeClosedDisabled(): boolean {
|
||||
@@ -71,28 +82,22 @@ class HaCoverTiltControls extends LitElement {
|
||||
return true;
|
||||
}
|
||||
const assumedState = this.stateObj.attributes.assumed_state === true;
|
||||
return isFullyClosedTilt(this.stateObj) && !assumedState;
|
||||
return this._entityObj.isFullyClosedTilt && !assumedState;
|
||||
}
|
||||
|
||||
private _onOpenTiltTap(ev): void {
|
||||
ev.stopPropagation();
|
||||
this.hass.callService("cover", "open_cover_tilt", {
|
||||
entity_id: this.stateObj.entity_id,
|
||||
});
|
||||
this._entityObj.openCoverTilt();
|
||||
}
|
||||
|
||||
private _onCloseTiltTap(ev): void {
|
||||
ev.stopPropagation();
|
||||
this.hass.callService("cover", "close_cover_tilt", {
|
||||
entity_id: this.stateObj.entity_id,
|
||||
});
|
||||
this._entityObj.closeCoverTilt();
|
||||
}
|
||||
|
||||
private _onStopTiltTap(ev): void {
|
||||
ev.stopPropagation();
|
||||
this.hass.callService("cover", "stop_cover_tilt", {
|
||||
entity_id: this.stateObj.entity_id,
|
||||
});
|
||||
this._entityObj.stopCoverTilt();
|
||||
}
|
||||
|
||||
static get styles(): CSSResultGroup {
|
||||
|
||||
@@ -1,84 +0,0 @@
|
||||
import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit";
|
||||
import { customElement, property, state } from "lit/decorators";
|
||||
import { classMap } from "lit/directives/class-map";
|
||||
|
||||
@customElement("ha-faded")
|
||||
class HaFaded extends LitElement {
|
||||
@property({ type: Number, attribute: "faded-height" })
|
||||
public fadedHeight = 102;
|
||||
|
||||
@state() _contentShown = false;
|
||||
|
||||
protected render(): TemplateResult {
|
||||
return html`
|
||||
<div
|
||||
class="container ${classMap({ faded: !this._contentShown })}"
|
||||
style=${!this._contentShown ? `max-height: ${this.fadedHeight}px` : ""}
|
||||
@click=${this._showContent}
|
||||
>
|
||||
<slot
|
||||
@iron-resize=${
|
||||
// ha-markdown-element fire this when render is complete
|
||||
this._setShowContent
|
||||
}
|
||||
></slot>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
get _slottedHeight(): number {
|
||||
return (
|
||||
(
|
||||
this.shadowRoot!.querySelector(".container")
|
||||
?.firstElementChild as HTMLSlotElement
|
||||
)
|
||||
.assignedElements()
|
||||
.reduce(
|
||||
(partial, element) => partial + (element as HTMLElement).offsetHeight,
|
||||
0
|
||||
) || 0
|
||||
);
|
||||
}
|
||||
|
||||
private _setShowContent() {
|
||||
const height = this._slottedHeight;
|
||||
if (height !== 0 && height <= this.fadedHeight + 50) {
|
||||
this._contentShown = true;
|
||||
}
|
||||
}
|
||||
|
||||
protected firstUpdated(changedProps) {
|
||||
super.firstUpdated(changedProps);
|
||||
this._setShowContent();
|
||||
}
|
||||
|
||||
private _showContent(): void {
|
||||
this._contentShown = true;
|
||||
}
|
||||
|
||||
static get styles(): CSSResultGroup {
|
||||
return css`
|
||||
.container {
|
||||
display: block;
|
||||
height: auto;
|
||||
cursor: default;
|
||||
}
|
||||
.faded {
|
||||
cursor: pointer;
|
||||
-webkit-mask-image: linear-gradient(
|
||||
to bottom,
|
||||
black 25%,
|
||||
transparent 100%
|
||||
);
|
||||
mask-image: linear-gradient(to bottom, black 25%, transparent 100%);
|
||||
overflow-y: hidden;
|
||||
}
|
||||
`;
|
||||
}
|
||||
}
|
||||
|
||||
declare global {
|
||||
interface HTMLElementTagNameMap {
|
||||
"ha-faded": HaFaded;
|
||||
}
|
||||
}
|
||||
@@ -1,12 +1,12 @@
|
||||
import "@material/mwc-list/mwc-list-item";
|
||||
import { mdiDotsVertical } from "@mdi/js";
|
||||
import "@polymer/paper-tooltip/paper-tooltip";
|
||||
import { css, html, LitElement, TemplateResult } from "lit";
|
||||
import { customElement, property } from "lit/decorators";
|
||||
import { HomeAssistant } from "../types";
|
||||
import "./ha-button-menu";
|
||||
import "./ha-icon-button";
|
||||
import "@material/mwc-list/mwc-list-item";
|
||||
import "@material/mwc-icon-button";
|
||||
import "./ha-svg-icon";
|
||||
import { mdiDotsVertical } from "@mdi/js";
|
||||
import { HomeAssistant } from "../types";
|
||||
import "@polymer/paper-tooltip/paper-tooltip";
|
||||
|
||||
export interface IconOverflowMenuItem {
|
||||
[key: string]: any;
|
||||
@@ -37,11 +37,13 @@ export class HaIconOverflowMenu extends LitElement {
|
||||
corner="BOTTOM_START"
|
||||
absolute
|
||||
>
|
||||
<ha-icon-button
|
||||
<mwc-icon-button
|
||||
.title=${this.hass.localize("ui.common.menu")}
|
||||
.label=${this.hass.localize("ui.common.overflow_menu")}
|
||||
.path=${mdiDotsVertical}
|
||||
slot="trigger"
|
||||
></ha-icon-button>
|
||||
>
|
||||
<ha-svg-icon .path=${mdiDotsVertical}></ha-svg-icon>
|
||||
</mwc-icon-button>
|
||||
|
||||
${this.items.map(
|
||||
(item) => html`
|
||||
|
||||
@@ -24,7 +24,7 @@ class HaMarkdownElement extends ReactiveElement {
|
||||
|
||||
private async _render() {
|
||||
this.innerHTML = await renderMarkdown(
|
||||
String(this.content),
|
||||
this.content,
|
||||
{
|
||||
breaks: this.breaks,
|
||||
gfm: true,
|
||||
|
||||
@@ -27,7 +27,7 @@ export class HaTimeInput extends LitElement {
|
||||
const parts = this.value?.split(":") || [];
|
||||
let hours = parts[0];
|
||||
const numberHours = Number(parts[0]);
|
||||
if (numberHours && useAMPM && numberHours > 12 && numberHours < 24) {
|
||||
if (numberHours && useAMPM && numberHours > 12) {
|
||||
hours = String(numberHours - 12).padStart(2, "0");
|
||||
}
|
||||
if (useAMPM && numberHours === 0) {
|
||||
|
||||
@@ -179,7 +179,7 @@ export interface StateCondition extends BaseCondition {
|
||||
condition: "state";
|
||||
entity_id: string;
|
||||
attribute?: string;
|
||||
state: string | number | string[];
|
||||
state: string | number;
|
||||
for?: string | number | ForDict;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,95 +0,0 @@
|
||||
import {
|
||||
HassEntityAttributeBase,
|
||||
HassEntityBase,
|
||||
} from "home-assistant-js-websocket";
|
||||
import { supportsFeature } from "../common/entity/supports-feature";
|
||||
|
||||
export const SUPPORT_OPEN = 1;
|
||||
export const SUPPORT_CLOSE = 2;
|
||||
export const SUPPORT_SET_POSITION = 4;
|
||||
export const SUPPORT_STOP = 8;
|
||||
export const SUPPORT_OPEN_TILT = 16;
|
||||
export const SUPPORT_CLOSE_TILT = 32;
|
||||
export const SUPPORT_STOP_TILT = 64;
|
||||
export const SUPPORT_SET_TILT_POSITION = 128;
|
||||
|
||||
export const FEATURE_CLASS_NAMES = {
|
||||
4: "has-set_position",
|
||||
16: "has-open_tilt",
|
||||
32: "has-close_tilt",
|
||||
64: "has-stop_tilt",
|
||||
128: "has-set_tilt_position",
|
||||
};
|
||||
|
||||
export const supportsOpen = (stateObj) =>
|
||||
supportsFeature(stateObj, SUPPORT_OPEN);
|
||||
|
||||
export const supportsClose = (stateObj) =>
|
||||
supportsFeature(stateObj, SUPPORT_CLOSE);
|
||||
|
||||
export const supportsSetPosition = (stateObj) =>
|
||||
supportsFeature(stateObj, SUPPORT_SET_POSITION);
|
||||
|
||||
export const supportsStop = (stateObj) =>
|
||||
supportsFeature(stateObj, SUPPORT_STOP);
|
||||
|
||||
export const supportsOpenTilt = (stateObj) =>
|
||||
supportsFeature(stateObj, SUPPORT_OPEN_TILT);
|
||||
|
||||
export const supportsCloseTilt = (stateObj) =>
|
||||
supportsFeature(stateObj, SUPPORT_CLOSE_TILT);
|
||||
|
||||
export const supportsStopTilt = (stateObj) =>
|
||||
supportsFeature(stateObj, SUPPORT_STOP_TILT);
|
||||
|
||||
export const supportsSetTiltPosition = (stateObj) =>
|
||||
supportsFeature(stateObj, SUPPORT_SET_TILT_POSITION);
|
||||
|
||||
export function isFullyOpen(stateObj: CoverEntity) {
|
||||
if (stateObj.attributes.current_position !== undefined) {
|
||||
return stateObj.attributes.current_position === 100;
|
||||
}
|
||||
return stateObj.state === "open";
|
||||
}
|
||||
|
||||
export function isFullyClosed(stateObj: CoverEntity) {
|
||||
if (stateObj.attributes.current_position !== undefined) {
|
||||
return stateObj.attributes.current_position === 0;
|
||||
}
|
||||
return stateObj.state === "closed";
|
||||
}
|
||||
|
||||
export function isFullyOpenTilt(stateObj: CoverEntity) {
|
||||
return stateObj.attributes.current_tilt_position === 100;
|
||||
}
|
||||
|
||||
export function isFullyClosedTilt(stateObj: CoverEntity) {
|
||||
return stateObj.attributes.current_tilt_position === 0;
|
||||
}
|
||||
|
||||
export function isOpening(stateObj: CoverEntity) {
|
||||
return stateObj.state === "opening";
|
||||
}
|
||||
|
||||
export function isClosing(stateObj: CoverEntity) {
|
||||
return stateObj.state === "closing";
|
||||
}
|
||||
|
||||
export function isTiltOnly(stateObj: CoverEntity) {
|
||||
const supportsCover =
|
||||
supportsOpen(stateObj) || supportsClose(stateObj) || supportsStop(stateObj);
|
||||
const supportsTilt =
|
||||
supportsOpenTilt(stateObj) ||
|
||||
supportsCloseTilt(stateObj) ||
|
||||
supportsStopTilt(stateObj);
|
||||
return supportsTilt && !supportsCover;
|
||||
}
|
||||
|
||||
interface CoverEntityAttributes extends HassEntityAttributeBase {
|
||||
current_position: number;
|
||||
current_tilt_position: number;
|
||||
}
|
||||
|
||||
export interface CoverEntity extends HassEntityBase {
|
||||
attributes: CoverEntityAttributes;
|
||||
}
|
||||
@@ -192,7 +192,7 @@ class MoreInfoClimate extends LitElement {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
${supportPresetMode && stateObj.attributes.preset_modes
|
||||
${supportPresetMode
|
||||
? html`
|
||||
<div class="container-preset_modes">
|
||||
<ha-paper-dropdown-menu
|
||||
@@ -220,7 +220,7 @@ class MoreInfoClimate extends LitElement {
|
||||
</div>
|
||||
`
|
||||
: ""}
|
||||
${supportFanMode && stateObj.attributes.fan_modes
|
||||
${supportFanMode
|
||||
? html`
|
||||
<div class="container-fan_list">
|
||||
<ha-paper-dropdown-menu
|
||||
@@ -248,7 +248,7 @@ class MoreInfoClimate extends LitElement {
|
||||
</div>
|
||||
`
|
||||
: ""}
|
||||
${supportSwingMode && stateObj.attributes.swing_modes
|
||||
${supportSwingMode
|
||||
? html`
|
||||
<div class="container-swing_list">
|
||||
<ha-paper-dropdown-menu
|
||||
|
||||
@@ -0,0 +1,124 @@
|
||||
import "@polymer/iron-flex-layout/iron-flex-layout-classes";
|
||||
import { html } from "@polymer/polymer/lib/utils/html-tag";
|
||||
/* eslint-plugin-disable lit */
|
||||
import { PolymerElement } from "@polymer/polymer/polymer-element";
|
||||
import { attributeClassNames } from "../../../common/entity/attribute_class_names";
|
||||
import { featureClassNames } from "../../../common/entity/feature_class_names";
|
||||
import "../../../components/ha-cover-tilt-controls";
|
||||
import "../../../components/ha-labeled-slider";
|
||||
import LocalizeMixin from "../../../mixins/localize-mixin";
|
||||
import CoverEntity from "../../../util/cover-model";
|
||||
|
||||
const FEATURE_CLASS_NAMES = {
|
||||
4: "has-set_position",
|
||||
128: "has-set_tilt_position",
|
||||
};
|
||||
class MoreInfoCover extends LocalizeMixin(PolymerElement) {
|
||||
static get template() {
|
||||
return html`
|
||||
<style include="iron-flex"></style>
|
||||
<style>
|
||||
.current_position,
|
||||
.tilt {
|
||||
max-height: 0px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.has-set_position .current_position,
|
||||
.has-current_position .current_position,
|
||||
.has-set_tilt_position .tilt,
|
||||
.has-current_tilt_position .tilt {
|
||||
max-height: 208px;
|
||||
}
|
||||
|
||||
[invisible] {
|
||||
visibility: hidden !important;
|
||||
}
|
||||
</style>
|
||||
<div class$="[[computeClassNames(stateObj)]]">
|
||||
<div class="current_position">
|
||||
<ha-labeled-slider
|
||||
caption="[[localize('ui.card.cover.position')]]"
|
||||
pin=""
|
||||
value="{{coverPositionSliderValue}}"
|
||||
disabled="[[!entityObj.supportsSetPosition]]"
|
||||
on-change="coverPositionSliderChanged"
|
||||
></ha-labeled-slider>
|
||||
</div>
|
||||
|
||||
<div class="tilt">
|
||||
<ha-labeled-slider
|
||||
caption="[[localize('ui.card.cover.tilt_position')]]"
|
||||
pin=""
|
||||
extra=""
|
||||
value="{{coverTiltPositionSliderValue}}"
|
||||
disabled="[[!entityObj.supportsSetTiltPosition]]"
|
||||
on-change="coverTiltPositionSliderChanged"
|
||||
>
|
||||
<ha-cover-tilt-controls
|
||||
slot="extra"
|
||||
hidden$="[[entityObj.isTiltOnly]]"
|
||||
hass="[[hass]]"
|
||||
state-obj="[[stateObj]]"
|
||||
></ha-cover-tilt-controls>
|
||||
</ha-labeled-slider>
|
||||
</div>
|
||||
</div>
|
||||
<ha-attributes
|
||||
hass="[[hass]]"
|
||||
state-obj="[[stateObj]]"
|
||||
extra-filters="current_position,current_tilt_position"
|
||||
></ha-attributes>
|
||||
`;
|
||||
}
|
||||
|
||||
static get properties() {
|
||||
return {
|
||||
hass: Object,
|
||||
stateObj: {
|
||||
type: Object,
|
||||
observer: "stateObjChanged",
|
||||
},
|
||||
entityObj: {
|
||||
type: Object,
|
||||
computed: "computeEntityObj(hass, stateObj)",
|
||||
},
|
||||
coverPositionSliderValue: Number,
|
||||
coverTiltPositionSliderValue: Number,
|
||||
};
|
||||
}
|
||||
|
||||
computeEntityObj(hass, stateObj) {
|
||||
return new CoverEntity(hass, stateObj);
|
||||
}
|
||||
|
||||
stateObjChanged(newVal) {
|
||||
if (newVal) {
|
||||
this.setProperties({
|
||||
coverPositionSliderValue: newVal.attributes.current_position,
|
||||
coverTiltPositionSliderValue: newVal.attributes.current_tilt_position,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
computeClassNames(stateObj) {
|
||||
const classes = [
|
||||
attributeClassNames(stateObj, [
|
||||
"current_position",
|
||||
"current_tilt_position",
|
||||
]),
|
||||
featureClassNames(stateObj, FEATURE_CLASS_NAMES),
|
||||
];
|
||||
return classes.join(" ");
|
||||
}
|
||||
|
||||
coverPositionSliderChanged(ev) {
|
||||
this.entityObj.setCoverPosition(ev.target.value);
|
||||
}
|
||||
|
||||
coverTiltPositionSliderChanged(ev) {
|
||||
this.entityObj.setCoverTiltPosition(ev.target.value);
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define("more-info-cover", MoreInfoCover);
|
||||
@@ -1,140 +0,0 @@
|
||||
import { css, CSSResult, html, LitElement, TemplateResult } from "lit";
|
||||
import { customElement, property } from "lit/decorators";
|
||||
import { attributeClassNames } from "../../../common/entity/attribute_class_names";
|
||||
import { featureClassNames } from "../../../common/entity/feature_class_names";
|
||||
import "../../../components/ha-attributes";
|
||||
import "../../../components/ha-cover-tilt-controls";
|
||||
import "../../../components/ha-labeled-slider";
|
||||
import {
|
||||
CoverEntity,
|
||||
FEATURE_CLASS_NAMES,
|
||||
isTiltOnly,
|
||||
supportsSetPosition,
|
||||
supportsSetTiltPosition,
|
||||
} from "../../../data/cover";
|
||||
import { HomeAssistant } from "../../../types";
|
||||
|
||||
@customElement("more-info-cover")
|
||||
class MoreInfoCover extends LitElement {
|
||||
@property({ attribute: false }) public hass!: HomeAssistant;
|
||||
|
||||
@property({ attribute: false }) public stateObj!: CoverEntity;
|
||||
|
||||
protected render(): TemplateResult {
|
||||
if (!this.stateObj) {
|
||||
return html``;
|
||||
}
|
||||
|
||||
const _isTiltOnly = isTiltOnly(this.stateObj);
|
||||
|
||||
return html`
|
||||
<div class=${this._computeClassNames(this.stateObj)}>
|
||||
<div class="current_position">
|
||||
<ha-labeled-slider
|
||||
.caption=${this.hass.localize("ui.card.cover.position")}
|
||||
pin=""
|
||||
.value=${this.stateObj.attributes.current_position}
|
||||
.disabled=${!supportsSetPosition(this.stateObj)}
|
||||
@change=${this._coverPositionSliderChanged}
|
||||
></ha-labeled-slider>
|
||||
</div>
|
||||
|
||||
<div class="tilt">
|
||||
${supportsSetTiltPosition(this.stateObj)
|
||||
? // Either render the labeled slider and put the tilt buttons into its slot
|
||||
// or (if tilt position is not supported and therefore no slider is shown)
|
||||
// render a title <div> (same style as for a labeled slider) and directly put
|
||||
// the tilt controls on the more-info.
|
||||
html` <ha-labeled-slider
|
||||
.caption=${this.hass.localize("ui.card.cover.tilt_position")}
|
||||
pin=""
|
||||
extra=""
|
||||
.value=${this.stateObj.attributes.current_tilt_position}
|
||||
@change=${this._coverTiltPositionSliderChanged}
|
||||
>
|
||||
${!_isTiltOnly
|
||||
? html`<ha-cover-tilt-controls
|
||||
.hass=${this.hass}
|
||||
slot="extra"
|
||||
.stateObj=${this.stateObj}
|
||||
></ha-cover-tilt-controls> `
|
||||
: html``}
|
||||
</ha-labeled-slider>`
|
||||
: !_isTiltOnly
|
||||
? html`
|
||||
<div class="title">
|
||||
${this.hass.localize("ui.card.cover.tilt_position")}
|
||||
</div>
|
||||
<ha-cover-tilt-controls
|
||||
.hass=${this.hass}
|
||||
.stateObj=${this.stateObj}
|
||||
></ha-cover-tilt-controls>
|
||||
`
|
||||
: html``}
|
||||
</div>
|
||||
</div>
|
||||
<ha-attributes
|
||||
.hass=${this.hass}
|
||||
.stateObj=${this.stateObj}
|
||||
extra-filters="current_position,current_tilt_position"
|
||||
></ha-attributes>
|
||||
`;
|
||||
}
|
||||
|
||||
private _computeClassNames(stateObj) {
|
||||
const classes = [
|
||||
attributeClassNames(stateObj, [
|
||||
"current_position",
|
||||
"current_tilt_position",
|
||||
]),
|
||||
featureClassNames(stateObj, FEATURE_CLASS_NAMES),
|
||||
];
|
||||
return classes.join(" ");
|
||||
}
|
||||
|
||||
private _coverPositionSliderChanged(ev) {
|
||||
this.hass.callService("cover", "set_cover_position", {
|
||||
entity_id: this.stateObj.entity_id,
|
||||
position: ev.target.value,
|
||||
});
|
||||
}
|
||||
|
||||
private _coverTiltPositionSliderChanged(ev) {
|
||||
this.hass.callService("cover", "set_cover_tilt_position", {
|
||||
entity_id: this.stateObj.entity_id,
|
||||
tilt_position: ev.target.value,
|
||||
});
|
||||
}
|
||||
|
||||
static get styles(): CSSResult {
|
||||
return css`
|
||||
.current_position,
|
||||
.tilt {
|
||||
max-height: 0px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.has-set_position .current_position,
|
||||
.has-current_position .current_position,
|
||||
.has-open_tilt .tilt,
|
||||
.has-close_tilt .tilt,
|
||||
.has-stop_tilt .tilt,
|
||||
.has-set_tilt_position .tilt,
|
||||
.has-current_tilt_position .tilt {
|
||||
max-height: 208px;
|
||||
}
|
||||
|
||||
/* from ha-labeled-slider for consistent look */
|
||||
.title {
|
||||
margin: 5px 0 8px;
|
||||
color: var(--primary-text-color);
|
||||
}
|
||||
`;
|
||||
}
|
||||
}
|
||||
|
||||
declare global {
|
||||
interface HTMLElementTagNameMap {
|
||||
"more-info-cover": MoreInfoCover;
|
||||
}
|
||||
}
|
||||
@@ -13,11 +13,12 @@ import { extractSearchParamsObject } from "../common/url/search-params";
|
||||
import { subscribeOne } from "../common/util/subscribe-one";
|
||||
import { AuthUrlSearchParams, hassUrl } from "../data/auth";
|
||||
import {
|
||||
fetchInstallationType,
|
||||
InstallationType,
|
||||
fetchOnboardingOverview,
|
||||
OnboardingResponses,
|
||||
OnboardingStep,
|
||||
onboardIntegrationStep,
|
||||
fetchInstallationType,
|
||||
} from "../data/onboarding";
|
||||
import { subscribeUser } from "../data/ws-user";
|
||||
import { litLocalizeLiteMixin } from "../mixins/lit-localize-lite-mixin";
|
||||
@@ -68,6 +69,8 @@ class HaOnboarding extends litLocalizeLiteMixin(HassElement) {
|
||||
|
||||
@state() private _steps?: OnboardingStep[];
|
||||
|
||||
@state() private _installation_type?: InstallationType;
|
||||
|
||||
protected render(): TemplateResult {
|
||||
const step = this._curStep()!;
|
||||
|
||||
@@ -87,6 +90,7 @@ class HaOnboarding extends litLocalizeLiteMixin(HassElement) {
|
||||
? html`<onboarding-restore-backup
|
||||
.localize=${this.localize}
|
||||
.restoring=${this._restoring}
|
||||
.installtionType=${this._installation_type}
|
||||
@restoring=${this._restoringBackup}
|
||||
>
|
||||
</onboarding-restore-backup>`
|
||||
|
||||
@@ -2,15 +2,15 @@ import "@material/mwc-button/mwc-button";
|
||||
import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit";
|
||||
import { customElement, property } from "lit/decorators";
|
||||
import "../../hassio/src/components/hassio-ansi-to-html";
|
||||
import { showBackupUploadDialog } from "../../hassio/src/dialogs/backup/show-dialog-backup-upload";
|
||||
import { showHassioBackupDialog } from "../../hassio/src/dialogs/backup/show-dialog-hassio-backup";
|
||||
import { showBackupUploadDialog } from "../../hassio/src/dialogs/backup/show-dialog-backup-upload";
|
||||
import type { LocalizeFunc } from "../common/translations/localize";
|
||||
import "../components/ha-card";
|
||||
import { fetchInstallationType } from "../data/onboarding";
|
||||
import { makeDialogManager } from "../dialogs/make-dialog-manager";
|
||||
import { ProvideHassLitMixin } from "../mixins/provide-hass-lit-mixin";
|
||||
import { haStyle } from "../resources/styles";
|
||||
import "./onboarding-loading";
|
||||
import { fetchInstallationType, InstallationType } from "../data/onboarding";
|
||||
|
||||
declare global {
|
||||
interface HASSDomEvents {
|
||||
@@ -26,6 +26,9 @@ class OnboardingRestoreBackup extends ProvideHassLitMixin(LitElement) {
|
||||
|
||||
@property({ type: Boolean }) public restoring = false;
|
||||
|
||||
@property({ attribute: false })
|
||||
public installationType?: InstallationType;
|
||||
|
||||
protected render(): TemplateResult {
|
||||
return this.restoring
|
||||
? html`<ha-card
|
||||
|
||||
@@ -5,7 +5,6 @@ import "@polymer/paper-item/paper-item";
|
||||
import { css, CSSResultGroup, html, LitElement } from "lit";
|
||||
import { customElement, property, state } from "lit/decorators";
|
||||
import { fireEvent } from "../../../../common/dom/fire_event";
|
||||
import { handleStructError } from "../../../../common/structs/handle-errors";
|
||||
import "../../../../components/ha-button-menu";
|
||||
import "../../../../components/ha-card";
|
||||
import "../../../../components/ha-icon-button";
|
||||
@@ -52,8 +51,6 @@ export default class HaAutomationConditionRow extends LitElement {
|
||||
|
||||
@state() private _yamlMode = false;
|
||||
|
||||
@state() private _warnings?: string[];
|
||||
|
||||
protected render() {
|
||||
if (!this.condition) {
|
||||
return html``;
|
||||
@@ -90,25 +87,7 @@ export default class HaAutomationConditionRow extends LitElement {
|
||||
</mwc-list-item>
|
||||
</ha-button-menu>
|
||||
</div>
|
||||
${this._warnings
|
||||
? html`<ha-alert
|
||||
alert-type="warning"
|
||||
.title=${this.hass.localize(
|
||||
"ui.errors.config.editor_not_supported"
|
||||
)}
|
||||
>
|
||||
${this._warnings!.length > 0 && this._warnings![0] !== undefined
|
||||
? html` <ul>
|
||||
${this._warnings!.map(
|
||||
(warning) => html`<li>${warning}</li>`
|
||||
)}
|
||||
</ul>`
|
||||
: ""}
|
||||
${this.hass.localize("ui.errors.config.edit_in_yaml_supported")}
|
||||
</ha-alert>`
|
||||
: ""}
|
||||
<ha-automation-condition-editor
|
||||
@ui-mode-not-available=${this._handleUiModeNotAvailable}
|
||||
.yamlMode=${this._yamlMode}
|
||||
.hass=${this.hass}
|
||||
.condition=${this.condition}
|
||||
@@ -118,15 +97,6 @@ export default class HaAutomationConditionRow extends LitElement {
|
||||
`;
|
||||
}
|
||||
|
||||
private _handleUiModeNotAvailable(ev: CustomEvent) {
|
||||
// Prevent possible parent action-row from switching to yamlMode
|
||||
ev.stopPropagation();
|
||||
this._warnings = handleStructError(this.hass, ev.detail).warnings;
|
||||
if (!this._yamlMode) {
|
||||
this._yamlMode = true;
|
||||
}
|
||||
}
|
||||
|
||||
private _handleAction(ev: CustomEvent<ActionDetail>) {
|
||||
switch (ev.detail.index) {
|
||||
case 0:
|
||||
@@ -155,7 +125,6 @@ export default class HaAutomationConditionRow extends LitElement {
|
||||
}
|
||||
|
||||
private _switchYamlMode() {
|
||||
this._warnings = undefined;
|
||||
this._yamlMode = !this._yamlMode;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import "@polymer/paper-input/paper-input";
|
||||
import { html, LitElement, PropertyValues } from "lit";
|
||||
import { html, LitElement } from "lit";
|
||||
import { customElement, property } from "lit/decorators";
|
||||
import { createDurationData } from "../../../../../common/datetime/create_duration_data";
|
||||
import "../../../../../components/entity/ha-entity-attribute-picker";
|
||||
@@ -11,7 +11,6 @@ import {
|
||||
handleChangeEvent,
|
||||
} from "../ha-automation-condition-row";
|
||||
import "../../../../../components/ha-duration-input";
|
||||
import { fireEvent } from "../../../../../common/dom/fire_event";
|
||||
|
||||
@customElement("ha-automation-condition-state")
|
||||
export class HaStateCondition extends LitElement implements ConditionElement {
|
||||
@@ -23,23 +22,6 @@ export class HaStateCondition extends LitElement implements ConditionElement {
|
||||
return { entity_id: "", state: "" };
|
||||
}
|
||||
|
||||
public willUpdate(changedProperties: PropertyValues): boolean {
|
||||
if (
|
||||
changedProperties.has("condition") &&
|
||||
Array.isArray(this.condition?.state)
|
||||
) {
|
||||
fireEvent(
|
||||
this,
|
||||
"ui-mode-not-available",
|
||||
Error(this.hass.localize("ui.errors.config.no_state_array_support"))
|
||||
);
|
||||
// We have to stop the update if state is an array.
|
||||
// Otherwise the state will be changed to a comma-separated string by the input element.
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
protected render() {
|
||||
const { entity_id, attribute, state } = this.condition;
|
||||
const forTime = createDurationData(this.condition.for);
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import "./ha-config-updates";
|
||||
import { mdiCloudLock } from "@mdi/js";
|
||||
import "@polymer/app-layout/app-header/app-header";
|
||||
import "@polymer/app-layout/app-toolbar/app-toolbar";
|
||||
@@ -8,14 +9,13 @@ import "../../../components/ha-card";
|
||||
import "../../../components/ha-icon-next";
|
||||
import "../../../components/ha-menu-button";
|
||||
import { CloudStatus } from "../../../data/cloud";
|
||||
import { SupervisorAvailableUpdates } from "../../../data/supervisor/supervisor";
|
||||
import "../../../layouts/ha-app-layout";
|
||||
import { haStyle } from "../../../resources/styles";
|
||||
import { HomeAssistant } from "../../../types";
|
||||
import "../ha-config-section";
|
||||
import { configSections } from "../ha-panel-config";
|
||||
import "./ha-config-navigation";
|
||||
import "./ha-config-updates";
|
||||
import { SupervisorAvailableUpdates } from "../../../data/supervisor/supervisor";
|
||||
|
||||
@customElement("ha-config-dashboard")
|
||||
class HaConfigDashboard extends LitElement {
|
||||
@@ -91,7 +91,21 @@ class HaConfigDashboard extends LitElement {
|
||||
.showAdvanced=${this.showAdvanced}
|
||||
.pages=${configSections.dashboard}
|
||||
></ha-config-navigation>
|
||||
</ha-card>`}
|
||||
</ha-card>
|
||||
${!this.showAdvanced
|
||||
? html`
|
||||
<div class="promo-advanced">
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.advanced_mode.hint_enable"
|
||||
)}
|
||||
<a href="/profile"
|
||||
>${this.hass.localize(
|
||||
"ui.panel.config.advanced_mode.link_profile_page"
|
||||
)}</a
|
||||
>.
|
||||
</div>
|
||||
`
|
||||
: ""}`}
|
||||
</ha-config-section>
|
||||
</ha-app-layout>
|
||||
`;
|
||||
@@ -125,6 +139,14 @@ class HaConfigDashboard extends LitElement {
|
||||
padding: 16px;
|
||||
padding-bottom: 0;
|
||||
}
|
||||
.promo-advanced {
|
||||
text-align: center;
|
||||
color: var(--secondary-text-color);
|
||||
margin-bottom: 24px;
|
||||
}
|
||||
.promo-advanced a {
|
||||
color: var(--secondary-text-color);
|
||||
}
|
||||
:host([narrow]) ha-card {
|
||||
background-color: var(--primary-background-color);
|
||||
box-shadow: unset;
|
||||
|
||||
@@ -76,12 +76,11 @@ class HaConfigUpdates extends LitElement {
|
||||
</paper-icon-item>
|
||||
`
|
||||
)}
|
||||
${!this._showAll && !this.narrow ? html`<div class="divider"></div>` : ""}
|
||||
${!this._showAll && this.supervisorUpdates.length >= 4
|
||||
? html`
|
||||
<button class="link show-all" @click=${this._showAllClicked}>
|
||||
${this.hass.localize("ui.panel.config.updates.more_updates", {
|
||||
count: this.supervisorUpdates!.length - updates.length,
|
||||
})}
|
||||
${this.hass.localize("ui.panel.config.updates.show_all_updates")}
|
||||
</button>
|
||||
`
|
||||
: ""}
|
||||
@@ -123,7 +122,13 @@ class HaConfigUpdates extends LitElement {
|
||||
button.show-all {
|
||||
color: var(--primary-color);
|
||||
text-decoration: none;
|
||||
margin: 16px;
|
||||
margin: 8px 16px;
|
||||
}
|
||||
.divider::before {
|
||||
content: " ";
|
||||
display: block;
|
||||
height: 1px;
|
||||
background-color: var(--divider-color);
|
||||
}
|
||||
`,
|
||||
];
|
||||
|
||||
@@ -320,6 +320,8 @@ export class HaConfigEntities extends SubscribeMixin(LitElement) {
|
||||
}
|
||||
}
|
||||
|
||||
entities.forEach((entity) => entity);
|
||||
|
||||
let filteredEntities = showReadOnly
|
||||
? entities.concat(stateEntities)
|
||||
: entities;
|
||||
|
||||
@@ -56,7 +56,7 @@ export const configSections: { [name: string]: PageNavigation[] } = {
|
||||
},
|
||||
{
|
||||
path: "/config/automation",
|
||||
name: "Automations & Scenes",
|
||||
name: "Automations",
|
||||
description: "Automations, blueprints, scenes and scripts",
|
||||
iconPath: mdiRobot,
|
||||
iconColor: "#518C43",
|
||||
|
||||
@@ -20,7 +20,7 @@ class ErrorLogCard extends LitElement {
|
||||
<ha-icon-button
|
||||
.path=${mdiRefresh}
|
||||
@click=${this._refreshErrorLog}
|
||||
.label=${this.hass.localize("ui.common.refresh")}
|
||||
.label=${this.hass!.localize("ui.common.refresh")}
|
||||
></ha-icon-button>
|
||||
<div class="card-content error-log">${this._errorHTML}</div>
|
||||
</ha-card>
|
||||
@@ -38,7 +38,6 @@ class ErrorLogCard extends LitElement {
|
||||
super.firstUpdated(changedProps);
|
||||
|
||||
if (this.hass?.config.safe_mode) {
|
||||
this.hass.loadFragmentTranslation("config");
|
||||
this._refreshErrorLog();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import "@material/mwc-button/mwc-button";
|
||||
import { HassEntity, UnsubscribeFunc } from "home-assistant-js-websocket";
|
||||
import { HassEntity } from "home-assistant-js-websocket";
|
||||
import { css, CSSResultGroup, html, LitElement } from "lit";
|
||||
import { customElement, property, state } from "lit/decorators";
|
||||
import memoizeOne from "memoize-one";
|
||||
@@ -7,7 +7,6 @@ import { fireEvent } from "../../../common/dom/fire_event";
|
||||
import { computeStateName } from "../../../common/entity/compute_state_name";
|
||||
import "../../../components/data-table/ha-data-table";
|
||||
import type { DataTableColumnContainer } from "../../../components/data-table/ha-data-table";
|
||||
import { subscribeEntityRegistry } from "../../../data/entity_registry";
|
||||
import {
|
||||
clearStatistics,
|
||||
getStatisticIds,
|
||||
@@ -19,7 +18,6 @@ import {
|
||||
showAlertDialog,
|
||||
showConfirmationDialog,
|
||||
} from "../../../dialogs/generic/show-dialog-box";
|
||||
import { SubscribeMixin } from "../../../mixins/subscribe-mixin";
|
||||
import { haStyle } from "../../../resources/styles";
|
||||
import { HomeAssistant } from "../../../types";
|
||||
import { showFixStatisticsUnitsChangedDialog } from "./show-dialog-statistics-fix-units-changed";
|
||||
@@ -35,7 +33,7 @@ const FIX_ISSUES_ORDER = {
|
||||
unsupported_unit_metadata: 5,
|
||||
};
|
||||
@customElement("developer-tools-statistics")
|
||||
class HaPanelDevStatistics extends SubscribeMixin(LitElement) {
|
||||
class HaPanelDevStatistics extends LitElement {
|
||||
@property({ attribute: false }) public hass!: HomeAssistant;
|
||||
|
||||
@property({ type: Boolean }) public narrow!: boolean;
|
||||
@@ -45,8 +43,6 @@ class HaPanelDevStatistics extends SubscribeMixin(LitElement) {
|
||||
state?: HassEntity;
|
||||
})[] = [] as StatisticsMetaData[];
|
||||
|
||||
private _disabledEntities = new Set<string>();
|
||||
|
||||
protected firstUpdated() {
|
||||
this._validateStatistics();
|
||||
}
|
||||
@@ -134,25 +130,6 @@ class HaPanelDevStatistics extends SubscribeMixin(LitElement) {
|
||||
}
|
||||
}
|
||||
|
||||
public hassSubscribe(): UnsubscribeFunc[] {
|
||||
return [
|
||||
subscribeEntityRegistry(this.hass.connection!, (entities) => {
|
||||
const disabledEntities = new Set<string>();
|
||||
for (const confEnt of entities) {
|
||||
if (!confEnt.disabled_by) {
|
||||
continue;
|
||||
}
|
||||
disabledEntities.add(confEnt.entity_id);
|
||||
}
|
||||
// If the disabled entities changed, re-validate the statistics
|
||||
if (disabledEntities !== this._disabledEntities) {
|
||||
this._disabledEntities = disabledEntities;
|
||||
this._validateStatistics();
|
||||
}
|
||||
}),
|
||||
];
|
||||
}
|
||||
|
||||
private async _validateStatistics() {
|
||||
const [statisticIds, issues] = await Promise.all([
|
||||
getStatisticIds(this.hass),
|
||||
@@ -161,24 +138,17 @@ class HaPanelDevStatistics extends SubscribeMixin(LitElement) {
|
||||
|
||||
const statsIds = new Set();
|
||||
|
||||
this._data = statisticIds
|
||||
.filter(
|
||||
(statistic) => !this._disabledEntities.has(statistic.statistic_id)
|
||||
)
|
||||
.map((statistic) => {
|
||||
statsIds.add(statistic.statistic_id);
|
||||
return {
|
||||
...statistic,
|
||||
state: this.hass.states[statistic.statistic_id],
|
||||
issues: issues[statistic.statistic_id],
|
||||
};
|
||||
});
|
||||
this._data = statisticIds.map((statistic) => {
|
||||
statsIds.add(statistic.statistic_id);
|
||||
return {
|
||||
...statistic,
|
||||
state: this.hass.states[statistic.statistic_id],
|
||||
issues: issues[statistic.statistic_id],
|
||||
};
|
||||
});
|
||||
|
||||
Object.keys(issues).forEach((statisticId) => {
|
||||
if (
|
||||
!statsIds.has(statisticId) &&
|
||||
!this._disabledEntities.has(statisticId)
|
||||
) {
|
||||
if (!statsIds.has(statisticId)) {
|
||||
this._data.push({
|
||||
statistic_id: statisticId,
|
||||
unit_of_measurement: "",
|
||||
|
||||
@@ -274,7 +274,7 @@ class HuiAlarmPanelCard extends LitElement implements LovelaceCard {
|
||||
|
||||
ha-chip {
|
||||
--ha-chip-background-color: var(--alarm-state-color);
|
||||
--primary-text-color: var(--text-primary-color);
|
||||
--ha-chip-text-color: var(--text-primary-color);
|
||||
line-height: initial;
|
||||
}
|
||||
|
||||
|
||||
@@ -289,8 +289,7 @@ class HuiEntitiesCard extends LitElement implements LovelaceCard {
|
||||
|
||||
private renderEntity(entityConf: LovelaceRowConfig): TemplateResult {
|
||||
const element = createRowElement(
|
||||
(!("type" in entityConf) || entityConf.type === "conditional") &&
|
||||
this._config!.state_color
|
||||
!("type" in entityConf) && this._config!.state_color
|
||||
? ({
|
||||
state_color: true,
|
||||
...(entityConf as EntityConfig),
|
||||
|
||||
@@ -87,8 +87,7 @@ const splitByAreas = (
|
||||
|
||||
export const computeCards = (
|
||||
states: Array<[string, HassEntity?]>,
|
||||
entityCardOptions: Partial<EntitiesCardConfig>,
|
||||
renderFooterEntities = true
|
||||
entityCardOptions: Partial<EntitiesCardConfig>
|
||||
): LovelaceCardConfig[] => {
|
||||
const cards: LovelaceCardConfig[] = [];
|
||||
|
||||
@@ -147,28 +146,12 @@ export const computeCards = (
|
||||
show_forecast: false,
|
||||
};
|
||||
cards.push(cardConfig);
|
||||
} else if (
|
||||
renderFooterEntities &&
|
||||
(domain === "scene" || domain === "script")
|
||||
) {
|
||||
const conf: typeof footerEntities[0] = {
|
||||
} else if (domain === "scene" || domain === "script") {
|
||||
footerEntities.push({
|
||||
entity: entityId,
|
||||
show_icon: true,
|
||||
show_name: true,
|
||||
};
|
||||
let name: string | undefined;
|
||||
if (
|
||||
titlePrefix &&
|
||||
stateObj &&
|
||||
// eslint-disable-next-line no-cond-assign
|
||||
(name = stripPrefixFromEntityName(
|
||||
computeStateName(stateObj),
|
||||
titlePrefix
|
||||
))
|
||||
) {
|
||||
conf.name = name;
|
||||
}
|
||||
footerEntities.push(conf);
|
||||
});
|
||||
} else if (
|
||||
domain === "sensor" &&
|
||||
stateObj?.attributes.device_class === SENSOR_DEVICE_CLASS_BATTERY
|
||||
@@ -194,12 +177,6 @@ export const computeCards = (
|
||||
}
|
||||
}
|
||||
|
||||
// If we ended up with footer entities but no normal entities,
|
||||
// render the footer entities as normal entities.
|
||||
if (entities.length === 0 && footerEntities.length > 0) {
|
||||
return computeCards(states, entityCardOptions, false);
|
||||
}
|
||||
|
||||
if (entities.length > 0 || footerEntities.length > 0) {
|
||||
const card: EntitiesCardConfig = {
|
||||
type: "entities",
|
||||
@@ -448,9 +425,7 @@ export const generateDefaultViewConfig = (
|
||||
|
||||
if (grid && grid.flow_from.length > 0) {
|
||||
areaCards.push({
|
||||
title: localize(
|
||||
"ui.panel.lovelace.cards.energy.energy_distribution.title_today"
|
||||
),
|
||||
title: "Energy distribution today",
|
||||
type: "energy-distribution",
|
||||
link_dashboard: true,
|
||||
});
|
||||
|
||||
@@ -65,8 +65,6 @@ export class HuiButtonsBase extends LitElement {
|
||||
:host {
|
||||
display: flex;
|
||||
justify-content: space-evenly;
|
||||
flex-wrap: wrap;
|
||||
padding: 0 8px;
|
||||
}
|
||||
div {
|
||||
cursor: pointer;
|
||||
|
||||
@@ -9,8 +9,8 @@ import {
|
||||
import { customElement, property, state } from "lit/decorators";
|
||||
import "../../../components/ha-cover-controls";
|
||||
import "../../../components/ha-cover-tilt-controls";
|
||||
import { CoverEntity, isTiltOnly } from "../../../data/cover";
|
||||
import { HomeAssistant } from "../../../types";
|
||||
import { isTiltOnly } from "../../../util/cover-model";
|
||||
import { hasConfigOrEntityChanged } from "../common/has-changed";
|
||||
import "../components/hui-generic-entity-row";
|
||||
import { createEntityNotFoundWarning } from "../components/hui-warning";
|
||||
@@ -38,7 +38,7 @@ class HuiCoverEntityRow extends LitElement implements LovelaceRow {
|
||||
return html``;
|
||||
}
|
||||
|
||||
const stateObj = this.hass.states[this._config.entity] as CoverEntity;
|
||||
const stateObj = this.hass.states[this._config.entity];
|
||||
|
||||
if (!stateObj) {
|
||||
return html`
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import { html, LitElement, TemplateResult } from "lit";
|
||||
import { customElement, property, state } from "lit/decorators";
|
||||
import { computeDomain } from "../../../common/entity/compute_domain";
|
||||
import { HomeAssistant } from "../../../types";
|
||||
import { processConfigEntities } from "../common/process-config-entities";
|
||||
import "../components/hui-buttons-base";
|
||||
@@ -27,21 +26,11 @@ export class HuiButtonsHeaderFooter
|
||||
|
||||
public setConfig(config: ButtonsHeaderFooterConfig): void {
|
||||
this._configEntities = processConfigEntities(config.entities).map(
|
||||
(entityConfig) => {
|
||||
const conf = {
|
||||
tap_action: { action: "toggle" },
|
||||
hold_action: { action: "more-info" },
|
||||
...entityConfig,
|
||||
};
|
||||
if (computeDomain(entityConfig.entity) === "scene") {
|
||||
conf.tap_action = {
|
||||
action: "call-service",
|
||||
service: "scene.turn_on",
|
||||
target: { entity_id: conf.entity },
|
||||
};
|
||||
}
|
||||
return conf;
|
||||
}
|
||||
(entityConfig) => ({
|
||||
tap_action: { action: "toggle" },
|
||||
hold_action: { action: "more-info" },
|
||||
...entityConfig,
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,12 +1,7 @@
|
||||
import { customElement } from "lit/decorators";
|
||||
import { EntityCardConfig } from "../cards/types";
|
||||
import { HuiConditionalBase } from "../components/hui-conditional-base";
|
||||
import { createRowElement } from "../create-element/create-row-element";
|
||||
import {
|
||||
ConditionalRowConfig,
|
||||
EntityConfig,
|
||||
LovelaceRow,
|
||||
} from "../entity-rows/types";
|
||||
import { ConditionalRowConfig, LovelaceRow } from "../entity-rows/types";
|
||||
|
||||
@customElement("hui-conditional-row")
|
||||
class HuiConditionalRow extends HuiConditionalBase implements LovelaceRow {
|
||||
@@ -17,14 +12,7 @@ class HuiConditionalRow extends HuiConditionalBase implements LovelaceRow {
|
||||
throw new Error("No row configured");
|
||||
}
|
||||
|
||||
this._element = createRowElement(
|
||||
(config as EntityCardConfig).state_color
|
||||
? ({
|
||||
state_color: true,
|
||||
...(config.row as EntityConfig),
|
||||
} as EntityConfig)
|
||||
: config.row
|
||||
) as LovelaceRow;
|
||||
this._element = createRowElement(config.row) as LovelaceRow;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,68 @@
|
||||
import "@polymer/iron-flex-layout/iron-flex-layout-classes";
|
||||
import { html } from "@polymer/polymer/lib/utils/html-tag";
|
||||
/* eslint-plugin-disable lit */
|
||||
import { PolymerElement } from "@polymer/polymer/polymer-element";
|
||||
import "../components/entity/state-info";
|
||||
import "../components/ha-cover-controls";
|
||||
import "../components/ha-cover-tilt-controls";
|
||||
import CoverEntity from "../util/cover-model";
|
||||
|
||||
class StateCardCover extends PolymerElement {
|
||||
static get template() {
|
||||
return html`
|
||||
<style include="iron-flex iron-flex-alignment"></style>
|
||||
<style>
|
||||
:host {
|
||||
line-height: 1.5;
|
||||
}
|
||||
</style>
|
||||
|
||||
<div class="horizontal justified layout">
|
||||
${this.stateInfoTemplate}
|
||||
<div class="horizontal layout">
|
||||
<ha-cover-controls
|
||||
hidden$="[[entityObj.isTiltOnly]]"
|
||||
hass="[[hass]]"
|
||||
state-obj="[[stateObj]]"
|
||||
></ha-cover-controls>
|
||||
<ha-cover-tilt-controls
|
||||
hidden$="[[!entityObj.isTiltOnly]]"
|
||||
hass="[[hass]]"
|
||||
state-obj="[[stateObj]]"
|
||||
></ha-cover-tilt-controls>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
static get stateInfoTemplate() {
|
||||
return html`
|
||||
<state-info
|
||||
hass="[[hass]]"
|
||||
state-obj="[[stateObj]]"
|
||||
in-dialog="[[inDialog]]"
|
||||
></state-info>
|
||||
`;
|
||||
}
|
||||
|
||||
static get properties() {
|
||||
return {
|
||||
hass: Object,
|
||||
stateObj: Object,
|
||||
inDialog: {
|
||||
type: Boolean,
|
||||
value: false,
|
||||
},
|
||||
entityObj: {
|
||||
type: Object,
|
||||
computed: "computeEntityObj(hass, stateObj)",
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
computeEntityObj(hass, stateObj) {
|
||||
const entity = new CoverEntity(hass, stateObj);
|
||||
return entity;
|
||||
}
|
||||
}
|
||||
customElements.define("state-card-cover", StateCardCover);
|
||||
@@ -1,56 +0,0 @@
|
||||
import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit";
|
||||
import { customElement, property } from "lit/decorators";
|
||||
import "../components/entity/state-info";
|
||||
import "../components/ha-cover-controls";
|
||||
import "../components/ha-cover-tilt-controls";
|
||||
import { CoverEntity, isTiltOnly } from "../data/cover";
|
||||
import { haStyle } from "../resources/styles";
|
||||
import { HomeAssistant } from "../types";
|
||||
|
||||
@customElement("state-card-cover")
|
||||
class StateCardCover extends LitElement {
|
||||
@property({ attribute: false }) public hass!: HomeAssistant;
|
||||
|
||||
@property({ attribute: false }) public stateObj!: CoverEntity;
|
||||
|
||||
@property({ type: Boolean }) public inDialog = false;
|
||||
|
||||
protected render(): TemplateResult {
|
||||
return html`
|
||||
<div class="horizontal justified layout">
|
||||
<state-info
|
||||
.hass=${this.hass}
|
||||
.stateObj=${this.stateObj}
|
||||
.inDialog=${this.inDialog}
|
||||
></state-info>
|
||||
<ha-cover-controls
|
||||
.hass=${this.hass}
|
||||
.hidden=${isTiltOnly(this.stateObj)}
|
||||
.stateObj=${this.stateObj}
|
||||
></ha-cover-controls>
|
||||
<ha-cover-tilt-controls
|
||||
.hass=${this.hass}
|
||||
.hidden=${!isTiltOnly(this.stateObj)}
|
||||
.stateObj=${this.stateObj}
|
||||
></ha-cover-tilt-controls>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
static get styles(): CSSResultGroup {
|
||||
return [
|
||||
haStyle,
|
||||
css`
|
||||
:host {
|
||||
line-height: 1.5;
|
||||
}
|
||||
`,
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
declare global {
|
||||
interface HTMLElementTagNameMap {
|
||||
"state-card-cover": StateCardCover;
|
||||
}
|
||||
}
|
||||
@@ -864,8 +864,7 @@
|
||||
"key_missing": "Required key ''{key}'' is missing.",
|
||||
"key_not_expected": "Key ''{key}'' is not expected or not supported by the visual editor.",
|
||||
"key_wrong_type": "The provided value for ''{key}'' is not supported by the visual editor. We support ({type_correct}) but received ({type_wrong}).",
|
||||
"no_template_editor_support": "Templates not supported in visual editor",
|
||||
"no_state_array_support": "Multiple state values not supported in visual editor"
|
||||
"no_template_editor_support": "Templates not supported in visual editor"
|
||||
},
|
||||
"supervisor": {
|
||||
"title": "Could not load the Supervisor panel!",
|
||||
@@ -930,7 +929,7 @@
|
||||
"title": "{count} {count, plural,\n one {update}\n other {updates}\n}",
|
||||
"unable_to_fetch": "Unable to fetch available updates",
|
||||
"version_available": "Version {version_available} is available",
|
||||
"more_updates": "+ {count} Updates",
|
||||
"show_all_updates": "Show all updates",
|
||||
"show": "show"
|
||||
},
|
||||
"areas": {
|
||||
@@ -3031,7 +3030,6 @@
|
||||
"grid_neutrality_not_calculated": "Grid neutrality could not be calculated"
|
||||
},
|
||||
"energy_distribution": {
|
||||
"title_today": "Energy distribution today",
|
||||
"grid": "Grid",
|
||||
"gas": "Gas",
|
||||
"solar": "Solar",
|
||||
|
||||
@@ -0,0 +1,149 @@
|
||||
import { supportsFeature } from "../common/entity/supports-feature";
|
||||
|
||||
/* eslint-enable no-bitwise */
|
||||
export default class CoverEntity {
|
||||
constructor(hass, stateObj) {
|
||||
this.hass = hass;
|
||||
this.stateObj = stateObj;
|
||||
this._attr = stateObj.attributes;
|
||||
this._feat = this._attr.supported_features;
|
||||
}
|
||||
|
||||
get isFullyOpen() {
|
||||
if (this._attr.current_position !== undefined) {
|
||||
return this._attr.current_position === 100;
|
||||
}
|
||||
return this.stateObj.state === "open";
|
||||
}
|
||||
|
||||
get isFullyClosed() {
|
||||
if (this._attr.current_position !== undefined) {
|
||||
return this._attr.current_position === 0;
|
||||
}
|
||||
return this.stateObj.state === "closed";
|
||||
}
|
||||
|
||||
get isFullyOpenTilt() {
|
||||
return this._attr.current_tilt_position === 100;
|
||||
}
|
||||
|
||||
get isFullyClosedTilt() {
|
||||
return this._attr.current_tilt_position === 0;
|
||||
}
|
||||
|
||||
get isOpening() {
|
||||
return this.stateObj.state === "opening";
|
||||
}
|
||||
|
||||
get isClosing() {
|
||||
return this.stateObj.state === "closing";
|
||||
}
|
||||
|
||||
get supportsOpen() {
|
||||
return supportsFeature(this.stateObj, 1);
|
||||
}
|
||||
|
||||
get supportsClose() {
|
||||
return supportsFeature(this.stateObj, 2);
|
||||
}
|
||||
|
||||
get supportsSetPosition() {
|
||||
return supportsFeature(this.stateObj, 4);
|
||||
}
|
||||
|
||||
get supportsStop() {
|
||||
return supportsFeature(this.stateObj, 8);
|
||||
}
|
||||
|
||||
get supportsOpenTilt() {
|
||||
return supportsFeature(this.stateObj, 16);
|
||||
}
|
||||
|
||||
get supportsCloseTilt() {
|
||||
return supportsFeature(this.stateObj, 32);
|
||||
}
|
||||
|
||||
get supportsStopTilt() {
|
||||
return supportsFeature(this.stateObj, 64);
|
||||
}
|
||||
|
||||
get supportsSetTiltPosition() {
|
||||
return supportsFeature(this.stateObj, 128);
|
||||
}
|
||||
|
||||
get isTiltOnly() {
|
||||
const supportsCover =
|
||||
this.supportsOpen || this.supportsClose || this.supportsStop;
|
||||
const supportsTilt =
|
||||
this.supportsOpenTilt || this.supportsCloseTilt || this.supportsStopTilt;
|
||||
return supportsTilt && !supportsCover;
|
||||
}
|
||||
|
||||
openCover() {
|
||||
this.callService("open_cover");
|
||||
}
|
||||
|
||||
closeCover() {
|
||||
this.callService("close_cover");
|
||||
}
|
||||
|
||||
stopCover() {
|
||||
this.callService("stop_cover");
|
||||
}
|
||||
|
||||
openCoverTilt() {
|
||||
this.callService("open_cover_tilt");
|
||||
}
|
||||
|
||||
closeCoverTilt() {
|
||||
this.callService("close_cover_tilt");
|
||||
}
|
||||
|
||||
stopCoverTilt() {
|
||||
this.callService("stop_cover_tilt");
|
||||
}
|
||||
|
||||
setCoverPosition(position) {
|
||||
this.callService("set_cover_position", { position });
|
||||
}
|
||||
|
||||
setCoverTiltPosition(tiltPosition) {
|
||||
this.callService("set_cover_tilt_position", {
|
||||
tilt_position: tiltPosition,
|
||||
});
|
||||
}
|
||||
|
||||
// helper method
|
||||
|
||||
callService(service, data = {}) {
|
||||
data.entity_id = this.stateObj.entity_id;
|
||||
this.hass.callService("cover", service, data);
|
||||
}
|
||||
}
|
||||
|
||||
export const supportsOpen = (stateObj) => supportsFeature(stateObj, 1);
|
||||
|
||||
export const supportsClose = (stateObj) => supportsFeature(stateObj, 2);
|
||||
|
||||
export const supportsSetPosition = (stateObj) => supportsFeature(stateObj, 4);
|
||||
|
||||
export const supportsStop = (stateObj) => supportsFeature(stateObj, 8);
|
||||
|
||||
export const supportsOpenTilt = (stateObj) => supportsFeature(stateObj, 16);
|
||||
|
||||
export const supportsCloseTilt = (stateObj) => supportsFeature(stateObj, 32);
|
||||
|
||||
export const supportsStopTilt = (stateObj) => supportsFeature(stateObj, 64);
|
||||
|
||||
export const supportsSetTiltPosition = (stateObj) =>
|
||||
supportsFeature(stateObj, 128);
|
||||
|
||||
export function isTiltOnly(stateObj) {
|
||||
const supportsCover =
|
||||
supportsOpen(stateObj) || supportsClose(stateObj) || supportsStop(stateObj);
|
||||
const supportsTilt =
|
||||
supportsOpenTilt(stateObj) ||
|
||||
supportsCloseTilt(stateObj) ||
|
||||
supportsStopTilt(stateObj);
|
||||
return supportsTilt && !supportsCover;
|
||||
}
|
||||
Reference in New Issue
Block a user