Merge pull request #5620 from home-assistant/dev

This commit is contained in:
Bram Kragten 2020-04-24 16:14:09 +02:00 committed by GitHub
commit eb4ba4fc78
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
133 changed files with 1657 additions and 798 deletions

View File

@ -2,36 +2,10 @@ build
build-translations/*
translations/*
node_modules/*
npm-debug.log
.DS_Store
hass_frontend/*
.reify-cache
demo/hademo-icons.html
# Python stuff
*.py[cod]
*.egg
*.egg-info
# venv stuff
pyvenv.cfg
pip-selfcheck.json
venv
.venv
lib
bin
dist
# vscode
.vscode/*
!.vscode/extensions.json
# Cast dev settings
src/cast/dev_const.ts
# Secrets
.lokalise_token
yarn-error.log
#asdf
.tool-versions

View File

@ -32,6 +32,7 @@ import {
import "../../../../src/layouts/loading-screen";
import { generateDefaultViewConfig } from "../../../../src/panels/lovelace/common/generate-lovelace-config";
import "./hc-layout";
import "@material/mwc-button/mwc-button";
@customElement("hc-cast")
class HcCast extends LitElement {

View File

@ -24,6 +24,7 @@ import "./hassio-addon-config";
import "./hassio-addon-info";
import "./hassio-addon-logs";
import "./hassio-addon-network";
import "../../../src/layouts/hass-subpage";
@customElement("hassio-addon-view")
class HassioAddonView extends LitElement {

View File

@ -132,7 +132,7 @@ class HassioSnapshots extends LitElement {
(addon, idx) => html`
<paper-checkbox
.idx=${idx}
.checked="{{item.checked}}"
.checked=${addon.checked}
@checked-changed=${this._addonChecked}
>
${addon.name}
@ -202,7 +202,6 @@ class HassioSnapshots extends LitElement {
.icon=${snapshot.type === "full"
? "hassio:package-variant-closed"
: "hassio:package-variant"}
.
.icon-class="snapshot"
></hassio-card-content>
</div>

View File

@ -8,12 +8,12 @@
"version": "1.0.0",
"scripts": {
"build": "script/build_frontend",
"lint:eslint": "eslint '{**/src,src}/**/*.{js,ts,html}' --ignore-path .gitignore",
"format:eslint": "eslint '{**/src,src}/**/*.{js,ts,html}' --fix --ignore-path .gitignore",
"lint:prettier": "prettier '{**/src,src}/**/*.{js,ts,json,css,md}' --check",
"format:prettier": "prettier '{**/src,src}/**/*.{js,ts,json,css,md}' --write",
"lint:eslint": "eslint '**/src/**/*.{js,ts,html}' --ignore-path .gitignore",
"format:eslint": "eslint '**/src/**/*.{js,ts,html}' --fix --ignore-path .gitignore",
"lint:prettier": "prettier '**/src/**/*.{js,ts,json,css,md}' --check",
"format:prettier": "prettier '**/src/**/*.{js,ts,json,css,md}' --write",
"lint:types": "tsc",
"lint:lit": "lit-analyzer '{**/src,src}/**/*.ts'",
"lint:lit": "lit-analyzer '**/src/**/*.ts'",
"lint": "npm run lint:eslint && npm run lint:prettier && npm run lint:types",
"format": "npm run format:eslint && npm run format:prettier",
"mocha": "node_modules/.bin/ts-mocha -p test-mocha/tsconfig.test.json --opts test-mocha/mocha.opts",

View File

@ -2,7 +2,7 @@ from setuptools import setup, find_packages
setup(
name="home-assistant-frontend",
version="20200422.0",
version="20200424.0",
description="The Home Assistant frontend",
url="https://github.com/home-assistant/home-assistant-polymer",
author="The Home Assistant Authors",

View File

@ -1,11 +1,11 @@
import { HassEntity } from "home-assistant-js-websocket";
import { UNAVAILABLE, UNKNOWN } from "../../data/entity";
import { atLeastCachedVersion } from "../config/version";
import { formatDate } from "../datetime/format_date";
import { formatDateTime } from "../datetime/format_date_time";
import { formatTime } from "../datetime/format_time";
import { LocalizeFunc } from "../translations/localize";
import { computeStateDomain } from "./compute_state_domain";
import { UNKNOWN, UNAVAILABLE } from "../../data/entity";
import { atLeastCachedVersion } from "../config/version";
const legacyComputeStateDisplay = (
localize: LocalizeFunc,
@ -96,7 +96,6 @@ export const computeStateDisplay = (
return legacyComputeStateDisplay(localize, stateObj, language);
}
// Real code.
if (stateObj.state === UNKNOWN || stateObj.state === UNAVAILABLE) {
return localize(`state.default.${stateObj.state}`);
}
@ -141,9 +140,15 @@ export const computeStateDisplay = (
return formatDateTime(date, language);
}
const deviceClass = stateObj.attributes.device_class || "_";
return (
localize(`component.${domain}.state.${deviceClass}.${stateObj.state}`) ||
// Return device class translation
(stateObj.attributes.device_class &&
localize(
`component.${domain}.state.${stateObj.attributes.device_class}.${stateObj.state}`
)) ||
// Return default translation
localize(`component.${domain}.state._.${stateObj.state}`) ||
// We don't know! Return the raw state.
stateObj.state
);
};

View File

@ -1,3 +1,5 @@
import "@material/mwc-button/mwc-button";
import "@polymer/paper-icon-button/paper-icon-button";
import "@polymer/paper-input/paper-input";
import "@polymer/paper-item/paper-item";
import "@polymer/paper-item/paper-item-body";

View File

@ -1,3 +1,4 @@
import "@polymer/paper-icon-button/paper-icon-button";
import "@polymer/paper-input/paper-input";
import "@polymer/paper-item/paper-item";
import "@polymer/paper-item/paper-item-body";

View File

@ -11,6 +11,7 @@ import {
LitElement,
property,
PropertyValues,
query,
TemplateResult,
} from "lit-element";
import memoizeOne from "memoize-one";
@ -91,12 +92,13 @@ class HaEntityPicker extends LitElement {
@property() public entityFilter?: HaEntityPickerEntityFilterFunc;
@property({ type: Boolean }) private _opened?: boolean;
@property({ type: Boolean }) private _opened = false;
@property() private _hass?: HomeAssistant;
@query("vaadin-combo-box-light") private _comboBox!: HTMLElement;
private _getStates = memoizeOne(
(
_opened: boolean,
hass: this["hass"],
includeDomains: this["includeDomains"],
excludeDomains: this["excludeDomains"],
@ -147,27 +149,28 @@ class HaEntityPicker extends LitElement {
);
protected updated(changedProps: PropertyValues) {
super.updated(changedProps);
if (changedProps.has("hass") && !this._opened) {
this._hass = this.hass;
if (changedProps.has("_opened") && this._opened) {
const states = this._getStates(
this._opened,
this.hass,
this.includeDomains,
this.excludeDomains,
this.entityFilter,
this.includeDeviceClasses
);
(this._comboBox as any).items = states;
}
}
protected render(): TemplateResult {
const states = this._getStates(
this._hass,
this.includeDomains,
this.excludeDomains,
this.entityFilter,
this.includeDeviceClasses
);
if (!this.hass) {
return html``;
}
return html`
<vaadin-combo-box-light
item-value-path="entity_id"
item-label-path="entity_id"
.items=${states}
.value=${this._value}
.allowCustomValue=${this.allowCustomEntity}
.renderer=${rowRenderer}
@ -176,8 +179,8 @@ class HaEntityPicker extends LitElement {
>
<paper-input
.autofocus=${this.autofocus}
.label=${this.label === undefined && this._hass
? this._hass.localize("ui.components.entity.entity-picker.entity")
.label=${this.label === undefined
? this.hass.localize("ui.components.entity.entity-picker.entity")
: this.label}
.value=${this._value}
.disabled=${this.disabled}
@ -190,7 +193,7 @@ class HaEntityPicker extends LitElement {
${this.value
? html`
<paper-icon-button
aria-label=${this.hass!.localize(
aria-label=${this.hass.localize(
"ui.components.entity.entity-picker.clear"
)}
slot="suffix"
@ -203,20 +206,17 @@ class HaEntityPicker extends LitElement {
</paper-icon-button>
`
: ""}
${states.length > 0
? html`
<paper-icon-button
aria-label=${this.hass!.localize(
"ui.components.entity.entity-picker.show_entities"
)}
slot="suffix"
class="toggle-button"
.icon=${this._opened ? "hass:menu-up" : "hass:menu-down"}
>
Toggle
</paper-icon-button>
`
: ""}
<paper-icon-button
aria-label=${this.hass.localize(
"ui.components.entity.entity-picker.show_entities"
)}
slot="suffix"
class="toggle-button"
.icon=${this._opened ? "hass:menu-up" : "hass:menu-down"}
>
Toggle
</paper-icon-button>
</paper-input>
</vaadin-combo-box-light>
`;

View File

@ -11,6 +11,7 @@ import {
} from "lit-element";
import { classMap } from "lit-html/directives/class-map";
import secondsToDuration from "../../common/datetime/seconds_to_duration";
import { computeStateDisplay } from "../../common/entity/compute_state_display";
import { computeStateDomain } from "../../common/entity/compute_state_domain";
import { computeStateName } from "../../common/entity/compute_state_name";
import { domainIcon } from "../../common/entity/domain_icon";
@ -18,7 +19,6 @@ import { stateIcon } from "../../common/entity/state_icon";
import { timerTimeRemaining } from "../../common/entity/timer_time_remaining";
import { HomeAssistant } from "../../types";
import "../ha-label-badge";
import { computeStateDisplay } from "../../common/entity/compute_state_display";
@customElement("ha-state-label-badge")
export class HaStateLabelBadge extends LitElement {

View File

@ -1,3 +1,4 @@
import "@polymer/paper-icon-button/paper-icon-button";
import "@polymer/paper-input/paper-input";
import "@polymer/paper-item/paper-item";
import "@polymer/paper-item/paper-item-body";

View File

@ -110,7 +110,7 @@ class HaClimateState extends LocalizeMixin(PolymerElement) {
}
_localizeState(localize, stateObj) {
const stateString = localize(`state.climate.${stateObj.state}`);
const stateString = localize(`component.climate.state._.${stateObj.state}`);
return stateObj.attributes.hvac_action
? `${localize(
`state_attributes.climate.hvac_action.${stateObj.attributes.hvac_action}`

View File

@ -4,6 +4,7 @@ import { ripple } from "@material/mwc-ripple/ripple-directive";
import { customElement, html, TemplateResult } from "lit-element";
import { classMap } from "lit-html/directives/class-map";
import type { Constructor } from "../types";
import "./ha-icon";
const MwcFab = customElements.get("mwc-fab") as Constructor<Fab>;

View File

@ -1,3 +1,4 @@
import "@polymer/iron-icon/iron-icon";
import "@polymer/paper-checkbox/paper-checkbox";
import "@polymer/paper-input/paper-input";
import "@polymer/paper-item/paper-icon-item";

View File

@ -7,6 +7,7 @@ import {
TemplateResult,
} from "lit-element";
import { fireEvent } from "../../common/dom/fire_event";
import "../paper-time-input";
import { HaFormElement, HaFormTimeData, HaFormTimeSchema } from "./ha-form";
@customElement("ha-form-positive_time_period_dict")

View File

@ -1,4 +1,3 @@
/* eslint-disable lit/no-invalid-html */
import { HassEntity, UnsubscribeFunc } from "home-assistant-js-websocket";
import {
css,
@ -96,7 +95,7 @@ export class HaRelatedItems extends SubscribeMixin(LitElement) {
)}:
</h3>
<a
href="/config/integrations#config_entry=${relatedConfigEntryId}"
href=${`/config/integrations#config_entry=${relatedConfigEntryId}`}
@click=${this._close}
>
${this.hass.localize(`component.${entry.domain}.title`)}:

View File

@ -76,7 +76,7 @@ class HaVacuumState extends LocalizeMixin(PolymerElement) {
? this.localize(
`ui.card.vacuum.actions.${STATES_INTERCEPTABLE[state].action}`
)
: this.localize(`state.vacuum.${state}`);
: this.localize(`component.vacuum._.${state}`);
}
_callService(ev) {

View File

@ -1,6 +1,7 @@
import { html } from "@polymer/polymer/lib/utils/html-tag";
/* eslint-plugin-disable lit */
import { PolymerElement } from "@polymer/polymer/polymer-element";
import { computeStateDisplay } from "../common/entity/compute_state_display";
import LocalizeMixin from "../mixins/localize-mixin";
/*
@ -32,7 +33,7 @@ class HaWaterHeaterState extends LocalizeMixin(PolymerElement) {
</style>
<div class="target">
<span class="state-label"> [[_localizeState(stateObj.state)]] </span>
<span class="state-label"> [[_localizeState(stateObj)]] </span>
[[computeTarget(hass, stateObj)]]
</div>
@ -67,8 +68,8 @@ class HaWaterHeaterState extends LocalizeMixin(PolymerElement) {
return "";
}
_localizeState(state) {
return this.localize(`state.water_heater.${state}`) || state;
_localizeState(stateObj) {
return computeStateDisplay(this.hass.localize, stateObj);
}
}
customElements.define("ha-water_heater-state", HaWaterHeaterState);

View File

@ -17,6 +17,7 @@ import { fireEvent } from "../../common/dom/fire_event";
import { compare } from "../../common/string/compare";
import { fetchUsers, User } from "../../data/user";
import { HomeAssistant } from "../../types";
import "./ha-user-badge";
class HaUserPicker extends LitElement {
public hass?: HomeAssistant;

View File

@ -8,12 +8,12 @@ import {
getConfigFlowHandlers,
handleConfigFlowStep,
} from "../../data/config_flow";
import { domainToName } from "../../data/integration";
import {
DataEntryFlowDialogParams,
loadDataEntryFlowDialog,
showFlowDialog,
} from "./show-dialog-data-entry-flow";
import { domainToName } from "../../data/integration";
export const loadConfigFlowDialog = loadDataEntryFlowDialog;

View File

@ -16,12 +16,12 @@ import { styleMap } from "lit-html/directives/style-map";
import memoizeOne from "memoize-one";
import { fireEvent } from "../../common/dom/fire_event";
import "../../common/search/search-input";
import { LocalizeFunc } from "../../common/translations/localize";
import "../../components/ha-icon-next";
import { domainToName } from "../../data/integration";
import { HomeAssistant } from "../../types";
import { FlowConfig } from "./show-dialog-data-entry-flow";
import { configFlowContentStyles } from "./styles";
import { domainToName } from "../../data/integration";
import { LocalizeFunc } from "../../common/translations/localize";
interface HandlerObj {
name: string;

View File

@ -1,3 +1,4 @@
import "@material/mwc-button/mwc-button";
import {
css,
CSSResultArray,
@ -8,11 +9,11 @@ import {
TemplateResult,
} from "lit-element";
import "../../components/dialog/ha-paper-dialog";
import { domainToName } from "../../data/integration";
import { PolymerChangedEvent } from "../../polymer-types";
import { haStyleDialog } from "../../resources/styles";
import { HomeAssistant } from "../../types";
import { HaDomainTogglerDialogParams } from "./show-dialog-domain-toggler";
import { domainToName } from "../../data/integration";
@customElement("dialog-domain-toggler")
class DomainTogglerDialog extends LitElement {

View File

@ -1,3 +1,4 @@
import "@material/mwc-button/mwc-button";
import "@polymer/paper-dialog-scrollable/paper-dialog-scrollable";
import "@polymer/paper-input/paper-input";
import {
@ -72,6 +73,7 @@ class DialogBox extends LitElement {
autofocus
.value=${this._value}
@value-changed=${this._valueChanged}
@keyup=${this._handleKeyUp}
.label=${this._params.inputLabel
? this._params.inputLabel
: ""}
@ -112,6 +114,12 @@ class DialogBox extends LitElement {
this._params = undefined;
}
private _handleKeyUp(ev: KeyboardEvent) {
if (ev.keyCode === 13) {
this._confirm();
}
}
private async _confirm(): Promise<void> {
if (this._params!.confirm) {
this._params!.confirm(this._value);

View File

@ -185,7 +185,7 @@ class MoreInfoClimate extends LitElement {
.map(
(mode) => html`
<paper-item item-name=${mode}>
${hass.localize(`state.climate.${mode}`)}
${hass.localize(`component.climate.state._.${mode}`)}
</paper-item>
`
)}

View File

@ -11,6 +11,7 @@ import {
} from "lit-element";
import memoizeOne from "memoize-one";
import { fireEvent } from "../../../common/dom/fire_event";
import "../../../components/ha-attributes";
import "../../../components/map/ha-map";
import { showZoneEditor } from "../../../data/zone";
import { HomeAssistant } from "../../../types";

View File

@ -8,6 +8,7 @@ import {
property,
TemplateResult,
} from "lit-element";
import "../../../components/ha-attributes";
import { TimerEntity } from "../../../data/timer";
import { HomeAssistant } from "../../../types";

View File

@ -246,7 +246,7 @@ class MoreInfoWaterHeater extends LocalizeMixin(EventsMixin(PolymerElement)) {
}
_localizeOperationMode(localize, mode) {
return localize(`state.water_heater.${mode}`) || mode;
return localize(`component.water_heater.state._.${mode}`) || mode;
}
}

View File

@ -1,23 +1,24 @@
import "@material/mwc-button/mwc-button";
import {
LitElement,
css,
html,
CSSResult,
TemplateResult,
customElement,
html,
LitElement,
property,
TemplateResult,
} from "lit-element";
import { computeStateName } from "../../common/entity/compute_state_name";
import "../../components/ha-dialog";
import "../../components/ha-switch";
import { computeDeviceName } from "../../data/device_registry";
import { computeStateName } from "../../common/entity/compute_state_name";
import { haStyleDialog } from "../../resources/styles";
import type { HaSwitch } from "../../components/ha-switch";
import { computeDeviceName } from "../../data/device_registry";
import { fetchMQTTDebugInfo, MQTTDeviceDebugInfo } from "../../data/mqtt";
import { haStyleDialog } from "../../resources/styles";
import { HomeAssistant } from "../../types";
import { MQTTDeviceDebugInfoDialogParams } from "./show-dialog-mqtt-device-debug-info";
import { MQTTDeviceDebugInfo, fetchMQTTDebugInfo } from "../../data/mqtt";
import "./mqtt-messages";
import "./mqtt-discovery-payload";
import "./mqtt-messages";
import { MQTTDeviceDebugInfoDialogParams } from "./show-dialog-mqtt-device-debug-info";
@customElement("dialog-mqtt-device-debug-info")
class DialogMQTTDeviceDebugInfo extends LitElement {

View File

@ -1,11 +1,11 @@
import {
LitElement,
html,
TemplateResult,
customElement,
property,
} from "lit-element";
import { safeDump } from "js-yaml";
import {
customElement,
html,
LitElement,
property,
TemplateResult,
} from "lit-element";
@customElement("mqtt-discovery-payload")
class MQTTDiscoveryPayload extends LitElement {

View File

@ -1,11 +1,11 @@
import {
LitElement,
html,
TemplateResult,
customElement,
property,
} from "lit-element";
import { safeDump } from "js-yaml";
import {
customElement,
html,
LitElement,
property,
TemplateResult,
} from "lit-element";
import { MQTTMessage } from "../../data/mqtt";
@customElement("mqtt-messages")

View File

@ -7,10 +7,11 @@ import {
TemplateResult,
} from "lit-element";
import { fireEvent } from "../../common/dom/fire_event";
import { computeStateDisplay } from "../../common/entity/compute_state_display";
import { domainToName } from "../../data/integration";
import { PersitentNotificationEntity } from "../../data/persistent_notification";
import { HomeAssistant } from "../../types";
import "./notification-item-template";
import { domainToName } from "../../data/integration";
@customElement("configurator-notification-item")
export class HuiConfiguratorNotificationItem extends LitElement {
@ -38,8 +39,10 @@ export class HuiConfiguratorNotificationItem extends LitElement {
</div>
<mwc-button slot="actions" @click="${this._handleClick}"
>${this.hass.localize(
`state.configurator.${this.notification.state}`
>${computeStateDisplay(
this.hass.localize,
this.notification,
this.hass.language
)}</mwc-button
>
</notification-item-template>

View File

@ -1,3 +1,5 @@
import "@material/mwc-button/mwc-button";
import "@polymer/paper-tooltip/paper-tooltip";
import {
css,
CSSResult,
@ -8,6 +10,7 @@ import {
query,
TemplateResult,
} from "lit-element";
import { navigate } from "../common/navigate";
import "../components/data-table/ha-data-table";
import type {
DataTableColumnContainer,
@ -17,9 +20,6 @@ import type {
import type { HomeAssistant, Route } from "../types";
import "./hass-tabs-subpage";
import type { PageNavigation } from "./hass-tabs-subpage";
import "@material/mwc-button/mwc-button";
import { navigate } from "../common/navigate";
import "@polymer/paper-tooltip/paper-tooltip";
@customElement("hass-tabs-subpage-data-table")
export class HaTabsSubpageDataTable extends LitElement {

View File

@ -16,6 +16,7 @@ import { navigate } from "../common/navigate";
import "../components/ha-menu-button";
import "../components/ha-paper-icon-button-arrow-prev";
import { HomeAssistant, Route } from "../types";
import "../components/ha-icon";
export interface PageNavigation {
path: string;
@ -228,6 +229,10 @@ class HassTabsSubpage extends LitElement {
min-width: 0;
}
:host(:not([narrow])) #toolbar-icon {
min-width: 40px;
}
ha-menu-button,
ha-paper-icon-button-arrow-prev,
::slotted([slot="toolbar-icon"]) {

View File

@ -1,5 +1,6 @@
import "@polymer/app-route/app-location";
import { html, property, PropertyValues } from "lit-element";
import { setHAVersion } from "../common/config/version";
import { navigate } from "../common/navigate";
import { getStorageDefaultPanelUrlPath } from "../data/panel";
import "../resources/custom-card-support";
@ -12,7 +13,6 @@ import {
} from "../util/register-service-worker";
import "./ha-init-page";
import "./home-assistant-main";
import { setHAVersion } from "../common/config/version";
export class HomeAssistantAppEl extends HassElement {
@property() private _route?: Route;

View File

@ -24,10 +24,10 @@ import {
import { subscribeUser } from "../data/ws-user";
import { litLocalizeLiteMixin } from "../mixins/lit-localize-lite-mixin";
import { HassElement } from "../state/hass-element";
import { HomeAssistant } from "../types";
import { registerServiceWorker } from "../util/register-service-worker";
import "./onboarding-create-user";
import "./onboarding-loading";
import { HomeAssistant } from "../types";
interface OnboardingEvent<T extends ValidOnboardingStep> {
type: T;

View File

@ -20,6 +20,7 @@ import {
subscribeConfigFlowInProgress,
} from "../data/config_flow";
import { DataEntryFlowProgress } from "../data/data_entry_flow";
import { domainToName } from "../data/integration";
import { onboardIntegrationStep } from "../data/onboarding";
import {
loadConfigFlowDialog,
@ -28,7 +29,6 @@ import {
import { HomeAssistant } from "../types";
import "./action-badge";
import "./integration-badge";
import { domainToName } from "../data/integration";
@customElement("onboarding-integrations")
class OnboardingIntegrations extends LitElement {

View File

@ -1,3 +1,4 @@
import "@polymer/paper-dropdown-menu/paper-dropdown-menu-light";
import "@polymer/paper-icon-button/paper-icon-button";
import "@polymer/paper-item/paper-item";
import "@polymer/paper-listbox/paper-listbox";

View File

@ -6,6 +6,8 @@ import { PolymerChangedEvent } from "../../../../../polymer-types";
import { HomeAssistant } from "../../../../../types";
import { ActionElement } from "../ha-automation-action-row";
const includeDomains = ["scene"];
@customElement("ha-automation-action-scene")
export class HaSceneAction extends LitElement implements ActionElement {
@property() public hass!: HomeAssistant;
@ -24,7 +26,7 @@ export class HaSceneAction extends LitElement implements ActionElement {
.hass=${this.hass}
.value=${scene}
@value-changed=${this._entityPicked}
.includeDomains=${["scene"]}
.includeDomains=${includeDomains}
allow-custom-entity
></ha-entity-picker>
`;

View File

@ -34,6 +34,8 @@ export class HaServiceAction extends LitElement implements ActionElement {
return { service: "", data: {} };
}
private _domain = memoizeOne((service: string) => [computeDomain(service)]);
private _getServiceData = memoizeOne((service: string) => {
if (!service) {
return [];
@ -85,7 +87,7 @@ export class HaServiceAction extends LitElement implements ActionElement {
.value=${entity_id}
.label=${entity.description}
@value-changed=${this._entityPicked}
.includeDomains=${[computeDomain(service)]}
.includeDomains=${this._domain(service)}
allow-custom-entity
></ha-entity-picker>
`

View File

@ -1,3 +1,4 @@
import "@polymer/paper-dropdown-menu/paper-dropdown-menu-light";
import "@polymer/paper-item/paper-item";
import "@polymer/paper-listbox/paper-listbox";
import type { PaperListboxElement } from "@polymer/paper-listbox/paper-listbox";
@ -7,6 +8,7 @@ import { fireEvent } from "../../../../common/dom/fire_event";
import "../../../../components/ha-card";
import type { Condition } from "../../../../data/automation";
import type { HomeAssistant } from "../../../../types";
import "../../../../components/ha-yaml-editor";
import "./types/ha-automation-condition-and";
import "./types/ha-automation-condition-device";
import "./types/ha-automation-condition-numeric_state";

View File

@ -12,6 +12,8 @@ function zoneAndLocationFilter(stateObj) {
return hasLocation(stateObj) && computeStateDomain(stateObj) !== "zone";
}
const includeDomains = ["zone"];
@customElement("ha-automation-condition-zone")
export class HaZoneCondition extends LitElement {
@property() public hass!: HomeAssistant;
@ -46,7 +48,7 @@ export class HaZoneCondition extends LitElement {
@value-changed=${this._zonePicked}
.hass=${this.hass}
allow-custom-entity
.includeDomains=${["zone"]}
.includeDomains=${includeDomains}
></ha-entity-picker>
<label id="eventlabel">
${this.hass.localize(

View File

@ -45,7 +45,9 @@ import { HaDeviceTrigger } from "./trigger/types/ha-automation-trigger-device";
export class HaAutomationEditor extends LitElement {
@property() public hass!: HomeAssistant;
@property() public automation!: AutomationEntity;
@property() public automationId!: string;
@property() public automations!: AutomationEntity[];
@property() public isWide?: boolean;
@ -53,15 +55,18 @@ export class HaAutomationEditor extends LitElement {
@property() public route!: Route;
@property() public creatingNew?: boolean;
@property() private _config?: AutomationConfig;
@property() private _dirty?: boolean;
@property() private _errors?: string;
@property() private _entityId?: string;
protected render(): TemplateResult {
const stateObj = this._entityId
? this.hass.states[this._entityId]
: undefined;
return html`
<hass-tabs-subpage
.hass=${this.hass}
@ -70,7 +75,7 @@ export class HaAutomationEditor extends LitElement {
.backCallback=${() => this._backTapped()}
.tabs=${configSections.automation}
>
${this.creatingNew
${!this.automationId
? ""
: html`
<paper-icon-button
@ -82,153 +87,162 @@ export class HaAutomationEditor extends LitElement {
@click=${this._deleteConfirm}
></paper-icon-button>
`}
${this._errors ? html` <div class="errors">${this._errors}</div> ` : ""}
${this._config
? html`
${this.narrow
? html` <span slot="header">${this._config?.alias}</span> `
: ""}
<ha-config-section .isWide=${this.isWide}>
${!this.narrow
? html` <span slot="header">${this._config.alias}</span> `
<div class="content">
${this._errors
? html` <div class="errors">${this._errors}</div> `
: ""}
<span slot="introduction">
${this.hass.localize(
"ui.panel.config.automation.editor.introduction"
)}
</span>
<ha-card>
<div class="card-content">
<paper-input
.label=${this.hass.localize(
"ui.panel.config.automation.editor.alias"
)}
name="alias"
.value=${this._config.alias}
@value-changed=${this._valueChanged}
>
</paper-input>
<ha-textarea
.label=${this.hass.localize(
"ui.panel.config.automation.editor.description.label"
)}
.placeholder=${this.hass.localize(
"ui.panel.config.automation.editor.description.placeholder"
)}
name="description"
.value=${this._config.description}
@value-changed=${this._valueChanged}
></ha-textarea>
</div>
${this.creatingNew
? ""
: html`
<div
class="card-actions layout horizontal justified center"
>
<div class="layout horizontal center">
<ha-entity-toggle
.hass=${this.hass}
.stateObj=${this.automation}
></ha-entity-toggle>
${this.hass.localize(
"ui.panel.config.automation.editor.enable_disable"
)}
<ha-config-section .isWide=${this.isWide}>
${!this.narrow
? html` <span slot="header">${this._config.alias}</span> `
: ""}
<span slot="introduction">
${this.hass.localize(
"ui.panel.config.automation.editor.introduction"
)}
</span>
<ha-card>
<div class="card-content">
<paper-input
.label=${this.hass.localize(
"ui.panel.config.automation.editor.alias"
)}
name="alias"
.value=${this._config.alias}
@value-changed=${this._valueChanged}
>
</paper-input>
<ha-textarea
.label=${this.hass.localize(
"ui.panel.config.automation.editor.description.label"
)}
.placeholder=${this.hass.localize(
"ui.panel.config.automation.editor.description.placeholder"
)}
name="description"
.value=${this._config.description}
@value-changed=${this._valueChanged}
></ha-textarea>
</div>
${stateObj
? html`
<div
class="card-actions layout horizontal justified center"
>
<div class="layout horizontal center">
<ha-entity-toggle
.hass=${this.hass}
.stateObj=${stateObj}
></ha-entity-toggle>
${this.hass.localize(
"ui.panel.config.automation.editor.enable_disable"
)}
</div>
<mwc-button
@click=${this._excuteAutomation}
.stateObj=${stateObj}
>
${this.hass.localize(
"ui.card.automation.trigger"
)}
</mwc-button>
</div>
<mwc-button @click=${this._excuteAutomation}>
${this.hass.localize("ui.card.automation.trigger")}
</mwc-button>
</div>
`}
</ha-card>
</ha-config-section>
`
: ""}
</ha-card>
</ha-config-section>
<ha-config-section .isWide=${this.isWide}>
<span slot="header">
${this.hass.localize(
"ui.panel.config.automation.editor.triggers.header"
)}
</span>
<span slot="introduction">
<p>
<ha-config-section .isWide=${this.isWide}>
<span slot="header">
${this.hass.localize(
"ui.panel.config.automation.editor.triggers.introduction"
"ui.panel.config.automation.editor.triggers.header"
)}
</p>
<a
href="https://home-assistant.io/docs/automation/trigger/"
target="_blank"
rel="noreferrer"
>
${this.hass.localize(
"ui.panel.config.automation.editor.triggers.learn_more"
)}
</a>
</span>
<ha-automation-trigger
.triggers=${this._config.trigger}
@value-changed=${this._triggerChanged}
.hass=${this.hass}
></ha-automation-trigger>
</ha-config-section>
</span>
<span slot="introduction">
<p>
${this.hass.localize(
"ui.panel.config.automation.editor.triggers.introduction"
)}
</p>
<a
href="https://home-assistant.io/docs/automation/trigger/"
target="_blank"
rel="noreferrer"
>
${this.hass.localize(
"ui.panel.config.automation.editor.triggers.learn_more"
)}
</a>
</span>
<ha-automation-trigger
.triggers=${this._config.trigger}
@value-changed=${this._triggerChanged}
.hass=${this.hass}
></ha-automation-trigger>
</ha-config-section>
<ha-config-section .isWide=${this.isWide}>
<span slot="header">
${this.hass.localize(
"ui.panel.config.automation.editor.conditions.header"
)}
</span>
<span slot="introduction">
<p>
<ha-config-section .isWide=${this.isWide}>
<span slot="header">
${this.hass.localize(
"ui.panel.config.automation.editor.conditions.introduction"
"ui.panel.config.automation.editor.conditions.header"
)}
</p>
<a
href="https://home-assistant.io/docs/scripts/conditions/"
target="_blank"
rel="noreferrer"
>
${this.hass.localize(
"ui.panel.config.automation.editor.conditions.learn_more"
)}
</a>
</span>
<ha-automation-condition
.conditions=${this._config.condition || []}
@value-changed=${this._conditionChanged}
.hass=${this.hass}
></ha-automation-condition>
</ha-config-section>
</span>
<span slot="introduction">
<p>
${this.hass.localize(
"ui.panel.config.automation.editor.conditions.introduction"
)}
</p>
<a
href="https://home-assistant.io/docs/scripts/conditions/"
target="_blank"
rel="noreferrer"
>
${this.hass.localize(
"ui.panel.config.automation.editor.conditions.learn_more"
)}
</a>
</span>
<ha-automation-condition
.conditions=${this._config.condition || []}
@value-changed=${this._conditionChanged}
.hass=${this.hass}
></ha-automation-condition>
</ha-config-section>
<ha-config-section .isWide=${this.isWide}>
<span slot="header">
${this.hass.localize(
"ui.panel.config.automation.editor.actions.header"
)}
</span>
<span slot="introduction">
<p>
<ha-config-section .isWide=${this.isWide}>
<span slot="header">
${this.hass.localize(
"ui.panel.config.automation.editor.actions.introduction"
"ui.panel.config.automation.editor.actions.header"
)}
</p>
<a
href="https://home-assistant.io/docs/automation/action/"
target="_blank"
rel="noreferrer"
>
${this.hass.localize(
"ui.panel.config.automation.editor.actions.learn_more"
)}
</a>
</span>
<ha-automation-action
.actions=${this._config.action}
@value-changed=${this._actionChanged}
.hass=${this.hass}
></ha-automation-action>
</ha-config-section>
</span>
<span slot="introduction">
<p>
${this.hass.localize(
"ui.panel.config.automation.editor.actions.introduction"
)}
</p>
<a
href="https://home-assistant.io/docs/automation/action/"
target="_blank"
rel="noreferrer"
>
${this.hass.localize(
"ui.panel.config.automation.editor.actions.learn_more"
)}
</a>
</span>
<ha-automation-action
.actions=${this._config.action}
@value-changed=${this._actionChanged}
.hass=${this.hass}
></ha-automation-action>
</ha-config-section>
</div>
`
: ""}
<ha-fab
@ -251,19 +265,19 @@ export class HaAutomationEditor extends LitElement {
protected updated(changedProps: PropertyValues): void {
super.updated(changedProps);
const oldAutomation = changedProps.get("automation") as AutomationEntity;
const oldAutomationId = changedProps.get("automationId");
if (
changedProps.has("automation") &&
this.automation &&
changedProps.has("automationId") &&
this.automationId &&
this.hass &&
// Only refresh config if we picked a new automation. If same ID, don't fetch it.
(!oldAutomation ||
oldAutomation.attributes.id !== this.automation.attributes.id)
oldAutomationId !== this.automationId
) {
this._setEntityId();
this.hass
.callApi<AutomationConfig>(
"GET",
`config/automation/config/${this.automation.attributes.id}`
`config/automation/config/${this.automationId}`
)
.then(
(config) => {
@ -290,13 +304,12 @@ export class HaAutomationEditor extends LitElement {
"err_no",
resp.status_code
),
});
history.back();
}).then(() => history.back());
}
);
}
if (changedProps.has("creatingNew") && this.creatingNew && this.hass) {
if (changedProps.has("automationId") && !this.automationId && this.hass) {
const initData = getAutomationEditorInitData();
this._dirty = !!initData;
this._config = {
@ -310,6 +323,21 @@ export class HaAutomationEditor extends LitElement {
...initData,
};
}
if (
changedProps.has("automations") &&
this.automationId &&
!this._entityId
) {
this._setEntityId();
}
}
private _setEntityId() {
const automation = this.automations.find(
(entity: AutomationEntity) => entity.attributes.id === this.automationId
);
this._entityId = automation?.entity_id;
}
private _valueChanged(ev: CustomEvent) {
@ -348,8 +376,8 @@ export class HaAutomationEditor extends LitElement {
this._dirty = true;
}
private _excuteAutomation() {
triggerAutomation(this.hass, this.automation.entity_id);
private _excuteAutomation(ev: Event) {
triggerAutomation(this.hass, (ev.target as any).stateObj.entity_id);
}
private _backTapped(): void {
@ -379,14 +407,12 @@ export class HaAutomationEditor extends LitElement {
}
private async _delete() {
await deleteAutomation(this.hass, this.automation.attributes.id!);
await deleteAutomation(this.hass, this.automationId);
history.back();
}
private _saveAutomation(): void {
const id = this.creatingNew
? "" + Date.now()
: this.automation.attributes.id;
const id = this.automationId || String(Date.now());
this.hass!.callApi(
"POST",
"config/automation/config/" + id,
@ -395,7 +421,7 @@ export class HaAutomationEditor extends LitElement {
() => {
this._dirty = false;
if (this.creatingNew) {
if (!this.automationId) {
navigate(this, `/config/automation/edit/${id}`, true);
}
},

View File

@ -10,6 +10,7 @@ import {
import { HomeAssistant } from "../../../types";
import "./ha-automation-editor";
import "./ha-automation-picker";
import { debounce } from "../../../common/util/debounce";
@customElement("ha-config-automation")
class HaConfigAutomation extends HassRouterPage {
@ -23,6 +24,13 @@ class HaConfigAutomation extends HassRouterPage {
@property() public automations: AutomationEntity[] = [];
private _debouncedUpdateAutomations = debounce((pageEl) => {
const newAutomations = this._getAutomations(this.hass.states);
if (!this._equal(newAutomations, pageEl.automations)) {
pageEl.automations = newAutomations;
}
}, 10);
protected routerOptions: RouterOptions = {
defaultPage: "dashboard",
routes: {
@ -36,19 +44,15 @@ class HaConfigAutomation extends HassRouterPage {
},
};
private _computeAutomations = memoizeOne((states: HassEntities) => {
const automations: AutomationEntity[] = [];
Object.values(states).forEach((state) => {
if (
computeStateDomain(state) === "automation" &&
!state.attributes.hidden
) {
automations.push(state as AutomationEntity);
}
});
return automations;
});
private _getAutomations = memoizeOne(
(states: HassEntities): AutomationEntity[] => {
return Object.values(states).filter(
(entity) =>
computeStateDomain(entity) === "automation" &&
!entity.attributes.hidden
) as AutomationEntity[];
}
);
protected firstUpdated(changedProps) {
super.firstUpdated(changedProps);
@ -63,25 +67,28 @@ class HaConfigAutomation extends HassRouterPage {
pageEl.showAdvanced = this.showAdvanced;
if (this.hass) {
pageEl.automations = this._computeAutomations(this.hass.states);
if (!pageEl.automations || !changedProps) {
pageEl.automations = this._getAutomations(this.hass.states);
} else if (changedProps && changedProps.has("hass")) {
this._debouncedUpdateAutomations(pageEl);
}
}
if (
(!changedProps || changedProps.has("route")) &&
this._currentPage === "edit"
) {
pageEl.creatingNew = undefined;
const automationId = this.routeTail.path.substr(1);
pageEl.creatingNew = automationId === "new";
pageEl.automation =
automationId === "new"
? undefined
: pageEl.automations.find(
(entity: AutomationEntity) =>
entity.attributes.id === automationId
);
pageEl.automationId = automationId === "new" ? null : automationId;
}
}
private _equal(a: AutomationEntity[], b: AutomationEntity[]): boolean {
if (a.length !== b.length) {
return false;
}
return a.every((automation, index) => automation === b[index]);
}
}
declare global {

View File

@ -22,12 +22,13 @@ import {
subscribeDeviceRegistry,
} from "../../../../data/device_registry";
import { subscribeEntityRegistry } from "../../../../data/entity_registry";
import { domainToName } from "../../../../data/integration";
import { SubscribeMixin } from "../../../../mixins/subscribe-mixin";
import { PolymerChangedEvent } from "../../../../polymer-types";
import { haStyleDialog } from "../../../../resources/styles";
import { HomeAssistant } from "../../../../types";
import "../../../../components/entity/ha-entity-picker";
import { Placeholder, PlaceholderContainer } from "./dialog-thingtalk";
import { domainToName } from "../../../../data/integration";
declare global {
// for fire event

View File

@ -1,3 +1,4 @@
import "@polymer/paper-dropdown-menu/paper-dropdown-menu-light";
import "@polymer/paper-icon-button/paper-icon-button";
import "@polymer/paper-item/paper-item";
import "@polymer/paper-listbox/paper-listbox";

View File

@ -8,6 +8,8 @@ import type { GeoLocationTrigger } from "../../../../../data/automation";
import type { HomeAssistant } from "../../../../../types";
import { handleChangeEvent } from "../ha-automation-trigger-row";
const includeDomains = ["zone"];
@customElement("ha-automation-trigger-geo_location")
export default class HaGeolocationTrigger extends LitElement {
@property() public hass!: HomeAssistant;
@ -42,7 +44,7 @@ export default class HaGeolocationTrigger extends LitElement {
@value-changed=${this._zonePicked}
.hass=${this.hass}
allow-custom-entity
.includeDomains=${["zone"]}
.includeDomains=${includeDomains}
></ha-entity-picker>
<label id="eventlabel">
${this.hass.localize(

View File

@ -14,6 +14,8 @@ function zoneAndLocationFilter(stateObj) {
return hasLocation(stateObj) && computeStateDomain(stateObj) !== "zone";
}
const includeDomains = ["zone"];
@customElement("ha-automation-trigger-zone")
export class HaZoneTrigger extends LitElement {
@property() public hass!: HomeAssistant;
@ -49,7 +51,7 @@ export class HaZoneTrigger extends LitElement {
@value-changed=${this._zonePicked}
.hass=${this.hass}
allow-custom-entity
.includeDomains=${["zone"]}
.includeDomains=${includeDomains}
></ha-entity-picker>
<label id="eventlabel">
${this.hass.localize(

View File

@ -42,7 +42,8 @@ class HaConfigNavigation extends LitElement {
<ha-icon .icon=${page.icon} slot="item-icon"></ha-icon>
<paper-item-body two-line>
${this.hass.localize(
`ui.panel.config.${page.component}.caption`
page.translationKey ||
`ui.panel.config.${page.component}.caption`
)}
${page.component === "cloud" && (page.info as CloudStatus)
? page.info.logged_in

View File

@ -1,17 +1,17 @@
import { DeviceRegistryEntry } from "../../../../data/device_registry";
import { removeMQTTDeviceEntry } from "../../../../data/mqtt";
import {
LitElement,
html,
CSSResult,
customElement,
html,
LitElement,
property,
TemplateResult,
CSSResult,
} from "lit-element";
import { DeviceRegistryEntry } from "../../../../data/device_registry";
import { removeMQTTDeviceEntry } from "../../../../data/mqtt";
import { showConfirmationDialog } from "../../../../dialogs/generic/show-dialog-box";
import { showMQTTDeviceDebugInfoDialog } from "../../../../dialogs/mqtt-device-debug-info-dialog/show-dialog-mqtt-device-debug-info";
import { HomeAssistant } from "../../../../types";
import { haStyle } from "../../../../resources/styles";
import { HomeAssistant } from "../../../../types";
@customElement("ha-device-card-mqtt")
export class HaDeviceCardMqtt extends LitElement {

View File

@ -14,6 +14,7 @@ import {
DataTableRowData,
RowClickedEvent,
} from "../../../components/data-table/ha-data-table";
import "../../../components/entity/ha-state-icon";
import { AreaRegistryEntry } from "../../../data/area_registry";
import { ConfigEntry } from "../../../data/config_entries";
import {
@ -25,11 +26,10 @@ import {
EntityRegistryEntry,
findBatteryEntity,
} from "../../../data/entity_registry";
import { domainToName } from "../../../data/integration";
import "../../../layouts/hass-tabs-subpage-data-table";
import "../../../components/entity/ha-state-icon";
import { HomeAssistant, Route } from "../../../types";
import { configSections } from "../ha-panel-config";
import { domainToName } from "../../../data/integration";
interface DeviceRowData extends DeviceRegistryEntry {
device?: DeviceRowData;

View File

@ -1,4 +1,6 @@
import "@polymer/app-layout/app-toolbar/app-toolbar";
import "@polymer/paper-dialog-scrollable/paper-dialog-scrollable";
import "@polymer/paper-icon-button/paper-icon-button";
import "@polymer/paper-tabs/paper-tab";
import "@polymer/paper-tabs/paper-tabs";
import { HassEntity } from "home-assistant-js-websocket";

View File

@ -1,3 +1,4 @@
import "@material/mwc-button/mwc-button";
import "@polymer/paper-input/paper-input";
import { HassEntity } from "home-assistant-js-websocket";
import {

View File

@ -22,7 +22,9 @@ import { computeDomain } from "../../../common/entity/compute_domain";
import { computeStateName } from "../../../common/entity/compute_state_name";
import { domainIcon } from "../../../common/entity/domain_icon";
import { stateIcon } from "../../../common/entity/state_icon";
import { navigate } from "../../../common/navigate";
import "../../../common/search/search-input";
import { LocalizeFunc } from "../../../common/translations/localize";
import type {
DataTableColumnContainer,
DataTableColumnData,
@ -30,6 +32,7 @@ import type {
SelectionChangedEvent,
} from "../../../components/data-table/ha-data-table";
import "../../../components/ha-icon";
import { ConfigEntry, getConfigEntries } from "../../../data/config_entries";
import {
computeEntityRegistryName,
EntityRegistryEntry,
@ -37,6 +40,7 @@ import {
subscribeEntityRegistry,
updateEntityRegistryEntry,
} from "../../../data/entity_registry";
import { domainToName } from "../../../data/integration";
import { showConfirmationDialog } from "../../../dialogs/generic/show-dialog-box";
import "../../../layouts/hass-loading-screen";
import "../../../layouts/hass-tabs-subpage-data-table";
@ -49,10 +53,6 @@ import {
loadEntityEditorDialog,
showEntityEditorDialog,
} from "./show-dialog-entity-editor";
import { getConfigEntries, ConfigEntry } from "../../../data/config_entries";
import { LocalizeFunc } from "../../../common/translations/localize";
import { domainToName } from "../../../data/integration";
import { navigate } from "../../../common/navigate";
export interface StateEntity extends EntityRegistryEntry {
readonly?: boolean;

View File

@ -132,13 +132,13 @@ export const configSections: { [name: string]: PageNavigation[] } = {
{
component: "zha",
path: "/config/zha",
translationKey: "ui.panel.config.zha.caption",
translationKey: "component.zha.title",
icon: "hass:zigbee",
},
{
component: "zwave",
path: "/config/zwave",
translationKey: "ui.panel.config.zwave.caption",
translationKey: "component.zwave.title",
icon: "hass:z-wave",
},
],

View File

@ -1,3 +1,4 @@
import "@material/mwc-button/mwc-button";
import "@polymer/paper-item/paper-icon-item";
import "@polymer/paper-tooltip/paper-tooltip";
import {

View File

@ -1,5 +1,9 @@
import "@material/mwc-button/mwc-button";
import "@polymer/paper-icon-button/paper-icon-button";
import "@polymer/paper-input/paper-input";
import type { PaperInputElement } from "@polymer/paper-input/paper-input";
import "@polymer/paper-item/paper-item";
import "@polymer/paper-item/paper-item-body";
import {
css,
CSSResult,

View File

@ -1,4 +1,6 @@
import "@polymer/paper-input/paper-input";
import "@polymer/paper-radio-button/paper-radio-button";
import "@polymer/paper-radio-group/paper-radio-group";
import {
css,
CSSResult,

View File

@ -1,18 +1,18 @@
/* eslint-disable lit/no-invalid-html */
import "@polymer/app-route/app-route";
import { UnsubscribeFunc } from "home-assistant-js-websocket";
import {
css,
CSSResult,
customElement,
html,
LitElement,
property,
PropertyValues,
LitElement,
TemplateResult,
html,
CSSResult,
css,
} from "lit-element";
import { compare } from "../../../common/string/compare";
import { computeRTL } from "../../../common/util/compute_rtl";
import { afterNextRender } from "../../../common/util/render-status";
import "../../../components/entity/ha-state-icon";
import "../../../components/ha-card";
import "../../../components/ha-fab";
@ -38,6 +38,7 @@ import {
EntityRegistryEntry,
subscribeEntityRegistry,
} from "../../../data/entity_registry";
import { domainToName } from "../../../data/integration";
import { showConfigEntrySystemOptionsDialog } from "../../../dialogs/config-entry-system-options/show-dialog-config-entry-system-options";
import { showConfigFlowDialog } from "../../../dialogs/config-flow/show-dialog-config-flow";
import { showOptionsFlowDialog } from "../../../dialogs/config-flow/show-dialog-options-flow";
@ -48,11 +49,9 @@ import {
} from "../../../dialogs/generic/show-dialog-box";
import "../../../layouts/hass-tabs-subpage";
import { SubscribeMixin } from "../../../mixins/subscribe-mixin";
import { haStyle } from "../../../resources/styles";
import { HomeAssistant, Route } from "../../../types";
import { configSections } from "../ha-panel-config";
import { domainToName } from "../../../data/integration";
import { haStyle } from "../../../resources/styles";
import { afterNextRender } from "../../../common/util/render-status";
@customElement("ha-config-integrations")
class HaConfigIntegrations extends SubscribeMixin(LitElement) {
@ -253,6 +252,10 @@ class HaConfigIntegrations extends SubscribeMixin(LitElement) {
? this._configEntries.map((item: any) => {
const devices = this._getDevices(item);
const entities = this._getEntities(item);
const integrationName = domainToName(
this.hass.localize,
item.domain
);
return item.source === "ignore"
? ""
: html`
@ -271,10 +274,12 @@ class HaConfigIntegrations extends SubscribeMixin(LitElement) {
/>
</div>
<h1>
${domainToName(this.hass.localize, item.domain)}
${integrationName}
</h1>
<h2>
${item.title}
${integrationName === item.title
? html`&nbsp;`
: item.title}
</h2>
${devices.length || entities.length
? html`
@ -282,7 +287,7 @@ class HaConfigIntegrations extends SubscribeMixin(LitElement) {
${devices.length
? html`
<a
href="/config/devices/dashboard?historyBack=1&config_entry=${item.entry_id}"
href=${`/config/devices/dashboard?historyBack=1&config_entry=${item.entry_id}`}
>${this.hass.localize(
"ui.panel.config.integrations.config_entry.devices",
"count",
@ -297,7 +302,7 @@ class HaConfigIntegrations extends SubscribeMixin(LitElement) {
${entities.length
? html`
<a
href="/config/entities?historyBack=1&config_entry=${item.entry_id}"
href=${`/config/entities?historyBack=1&config_entry=${item.entry_id}`}
>${this.hass.localize(
"ui.panel.config.integrations.config_entry.entities",
"count",
@ -385,8 +390,9 @@ class HaConfigIntegrations extends SubscribeMixin(LitElement) {
aria-label=${this.hass.localize("ui.panel.config.integrations.new")}
title=${this.hass.localize("ui.panel.config.integrations.new")}
@click=${this._createFlow}
?rtl=${computeRTL(this.hass!)}
?is-wide=${this.isWide}
?narrow=${this.narrow}
?rtl=${computeRTL(this.hass!)}
></ha-fab>
</hass-tabs-subpage>
`;
@ -520,7 +526,7 @@ class HaConfigIntegrations extends SubscribeMixin(LitElement) {
"ui.panel.config.integrations.rename_input_label"
),
});
if (!newName) {
if (newName === null) {
return;
}
const newEntry = await updateConfigEntry(this.hass, configEntry.entry_id, {
@ -571,6 +577,7 @@ class HaConfigIntegrations extends SubscribeMixin(LitElement) {
margin-bottom: 64px;
}
ha-card {
max-width: 500px;
display: flex;
flex-direction: column;
justify-content: space-between;
@ -642,6 +649,10 @@ class HaConfigIntegrations extends SubscribeMixin(LitElement) {
right: 16px;
z-index: 1;
}
ha-fab[is-wide] {
bottom: 24px;
right: 24px;
}
ha-fab[narrow] {
bottom: 84px;
}
@ -649,6 +660,11 @@ class HaConfigIntegrations extends SubscribeMixin(LitElement) {
right: auto;
left: 16px;
}
ha-fab[is-wide].rtl {
bottom: 24px;
left: 24px;
right: auto;
}
paper-menu-button {
color: var(--secondary-text-color);
padding: 0;

View File

@ -1,3 +1,4 @@
import "@material/mwc-button/mwc-button";
import {
css,
CSSResult,

View File

@ -1,3 +1,7 @@
import "@material/mwc-button/mwc-button";
import "@polymer/paper-input/paper-input";
import "@polymer/paper-item/paper-item";
import "@polymer/paper-listbox/paper-listbox";
import {
css,
CSSResult,
@ -8,6 +12,7 @@ import {
TemplateResult,
} from "lit-element";
import { createCloseHeading } from "../../../../components/ha-dialog";
import "../../../../components/ha-paper-dropdown-menu";
import {
LovelaceResource,
LovelaceResourcesMutableParams,

View File

@ -18,6 +18,8 @@ import { haStyleDialog } from "../../../resources/styles";
import { HomeAssistant } from "../../../types";
import { PersonDetailDialogParams } from "./show-dialog-person-detail";
const includeDomains = ["device_tracker"];
class DialogPersonDetail extends LitElement {
@property() public hass!: HomeAssistant;
@ -106,7 +108,7 @@ class DialogPersonDetail extends LitElement {
<ha-entities-picker
.hass=${this.hass}
.value=${this._deviceTrackers}
.include-domains=${["device_tracker"]}
.includeDomains=${includeDomains}
.pickedEntityLabel=${this.hass.localize(
"ui.panel.config.person.detail.device_tracker_picked"
)}

View File

@ -1,5 +1,3 @@
import "@polymer/app-layout/app-header/app-header";
import "@polymer/app-layout/app-toolbar/app-toolbar";
import "@polymer/paper-icon-button/paper-icon-button";
import "@polymer/paper-item/paper-icon-item";
import "@polymer/paper-item/paper-item";
@ -49,7 +47,6 @@ import {
SCENE_IGNORED_DOMAINS,
} from "../../../data/scene";
import { showConfirmationDialog } from "../../../dialogs/generic/show-dialog-box";
import "../../../layouts/ha-app-layout";
import { SubscribeMixin } from "../../../mixins/subscribe-mixin";
import { haStyle } from "../../../resources/styles";
import { HomeAssistant, Route } from "../../../types";
@ -180,16 +177,14 @@ export class HaSceneEditor extends SubscribeMixin(LitElement) {
: this.hass.localize("ui.panel.config.scene.editor.default_name");
return html`
<hass-tabs-subpage
<hass-tabs-subpage
.hass=${this.hass}
.narrow=${this.narrow}
.route=${this.route}
.backCallback=${() => this._backTapped()}
.tabs=${configSections.automation}
>
${
this.creatingNew
${this.creatingNew
? ""
: html`
<paper-icon-button
@ -200,201 +195,191 @@ export class HaSceneEditor extends SubscribeMixin(LitElement) {
icon="hass:delete"
@click=${this._deleteTapped}
></paper-icon-button>
`
}
${
this._errors
? html` <div class="errors">${this._errors}</div> `
: ""
}
${this.narrow ? html` <span slot="header">${name}</span> ` : ""}
<div
id="root"
class="${classMap({
rtl: computeRTL(this.hass),
})}"
>
<ha-config-section .isWide=${this.isWide}>
${!this.narrow ? html` <span slot="header">${name}</span> ` : ""}
<div slot="introduction">
${this.hass.localize(
"ui.panel.config.scene.editor.introduction"
)}
</div>
<ha-card>
<div class="card-content">
<paper-input
.value=${this.scene ? computeStateName(this.scene) : ""}
@value-changed=${this._nameChanged}
label=${this.hass.localize(
"ui.panel.config.scene.editor.name"
)}
></paper-input>
</div>
</ha-card>
</ha-config-section>
<ha-config-section .isWide=${this.isWide}>
<div slot="header">
${this.hass.localize(
"ui.panel.config.scene.editor.devices.header"
)}
</div>
<div slot="introduction">
${this.hass.localize(
"ui.panel.config.scene.editor.devices.introduction"
)}
</div>
${devices.map(
(device) =>
html`
<ha-card>
<div class="card-header">
${device.name}
<paper-icon-button
icon="hass:delete"
title="${this.hass.localize(
"ui.panel.config.scene.editor.devices.delete"
)}"
.device=${device.id}
@click=${this._deleteDevice}
></paper-icon-button>
</div>
${device.entities.map((entityId) => {
const stateObj = this.hass.states[entityId];
if (!stateObj) {
return html``;
}
return html`
<paper-icon-item
.entityId=${entityId}
@click=${this._showMoreInfo}
class="device-entity"
>
<state-badge
.stateObj=${stateObj}
slot="item-icon"
></state-badge>
<paper-item-body>
${computeStateName(stateObj)}
</paper-item-body>
</paper-icon-item>
`;
})}
</ha-card>
`
)}
<ha-card
.header=${this.hass.localize(
"ui.panel.config.scene.editor.devices.add"
)}
>
<div class="card-content">
<ha-device-picker
@value-changed=${this._devicePicked}
.hass=${this.hass}
.label=${this.hass.localize(
"ui.panel.config.scene.editor.devices.add"
)}
></ha-device-picker>
</div>
</ha-card>
</ha-config-section>
${
this.showAdvanced
? html`
<ha-config-section .isWide=${this.isWide}>
<div slot="header">
${this.hass.localize(
"ui.panel.config.scene.editor.entities.header"
)}
</div>
<div slot="introduction">
${this.hass.localize(
"ui.panel.config.scene.editor.entities.introduction"
)}
</div>
${entities.length
? html`
<ha-card
class="entities"
.header=${this.hass.localize(
"ui.panel.config.scene.editor.entities.without_device"
)}
>
${entities.map((entityId) => {
const stateObj = this.hass.states[entityId];
if (!stateObj) {
return html``;
}
return html`
<paper-icon-item
.entityId=${entityId}
@click=${this._showMoreInfo}
class="device-entity"
>
<state-badge
.stateObj=${stateObj}
slot="item-icon"
></state-badge>
<paper-item-body>
${computeStateName(stateObj)}
</paper-item-body>
<paper-icon-button
icon="hass:delete"
.entityId=${entityId}
.title="${this.hass.localize(
"ui.panel.config.scene.editor.entities.delete"
)}"
@click=${this._deleteEntity}
></paper-icon-button>
</paper-icon-item>
`;
})}
</ha-card>
`
: ""}
<ha-card
header=${this.hass.localize(
"ui.panel.config.scene.editor.entities.add"
)}
>
<div class="card-content">
${this.hass.localize(
"ui.panel.config.scene.editor.entities.device_entities"
)}
<ha-entity-picker
@value-changed=${this._entityPicked}
.excludeDomains=${SCENE_IGNORED_DOMAINS}
.hass=${this.hass}
label=${this.hass.localize(
"ui.panel.config.scene.editor.entities.add"
)}
></ha-entity-picker>
</div>
</ha-card>
</ha-config-section>
`
: ""
}
</div>
<ha-fab
?is-wide="${this.isWide}"
?narrow="${this.narrow}"
?dirty="${this._dirty}"
icon="hass:content-save"
.title="${this.hass.localize("ui.panel.config.scene.editor.save")}"
@click=${this._saveScene}
`}
${this._errors ? html` <div class="errors">${this._errors}</div> ` : ""}
${this.narrow ? html` <span slot="header">${name}</span> ` : ""}
<div
id="root"
class="${classMap({
rtl: computeRTL(this.hass),
})}"
>
<ha-config-section .isWide=${this.isWide}>
${!this.narrow ? html` <span slot="header">${name}</span> ` : ""}
<div slot="introduction">
${this.hass.localize("ui.panel.config.scene.editor.introduction")}
</div>
<ha-card>
<div class="card-content">
<paper-input
.value=${this.scene ? computeStateName(this.scene) : ""}
@value-changed=${this._nameChanged}
label=${this.hass.localize(
"ui.panel.config.scene.editor.name"
)}
></paper-input>
</div>
</ha-card>
</ha-config-section>
<ha-config-section .isWide=${this.isWide}>
<div slot="header">
${this.hass.localize(
"ui.panel.config.scene.editor.devices.header"
)}
</div>
<div slot="introduction">
${this.hass.localize(
"ui.panel.config.scene.editor.devices.introduction"
)}
</div>
${devices.map(
(device) =>
html`
<ha-card>
<div class="card-header">
${device.name}
<paper-icon-button
icon="hass:delete"
title="${this.hass.localize(
"ui.panel.config.scene.editor.devices.delete"
)}"
.device=${device.id}
@click=${this._deleteDevice}
></paper-icon-button>
</div>
${device.entities.map((entityId) => {
const stateObj = this.hass.states[entityId];
if (!stateObj) {
return html``;
}
return html`
<paper-icon-item
.entityId=${entityId}
@click=${this._showMoreInfo}
class="device-entity"
>
<state-badge
.stateObj=${stateObj}
slot="item-icon"
></state-badge>
<paper-item-body>
${computeStateName(stateObj)}
</paper-item-body>
</paper-icon-item>
`;
})}
</ha-card>
`
)}
<ha-card
.header=${this.hass.localize(
"ui.panel.config.scene.editor.devices.add"
)}
>
<div class="card-content">
<ha-device-picker
@value-changed=${this._devicePicked}
.hass=${this.hass}
.label=${this.hass.localize(
"ui.panel.config.scene.editor.devices.add"
)}
></ha-device-picker>
</div>
</ha-card>
</ha-config-section>
${this.showAdvanced
? html`
<ha-config-section .isWide=${this.isWide}>
<div slot="header">
${this.hass.localize(
"ui.panel.config.scene.editor.entities.header"
)}
</div>
<div slot="introduction">
${this.hass.localize(
"ui.panel.config.scene.editor.entities.introduction"
)}
</div>
${entities.length
? html`
<ha-card
class="entities"
.header=${this.hass.localize(
"ui.panel.config.scene.editor.entities.without_device"
)}
>
${entities.map((entityId) => {
const stateObj = this.hass.states[entityId];
if (!stateObj) {
return html``;
}
return html`
<paper-icon-item
.entityId=${entityId}
@click=${this._showMoreInfo}
class="device-entity"
>
<state-badge
.stateObj=${stateObj}
slot="item-icon"
></state-badge>
<paper-item-body>
${computeStateName(stateObj)}
</paper-item-body>
<paper-icon-button
icon="hass:delete"
.entityId=${entityId}
.title="${this.hass.localize(
"ui.panel.config.scene.editor.entities.delete"
)}"
@click=${this._deleteEntity}
></paper-icon-button>
</paper-icon-item>
`;
})}
</ha-card>
`
: ""}
<ha-card
header=${this.hass.localize(
"ui.panel.config.scene.editor.entities.add"
)}
>
<div class="card-content">
${this.hass.localize(
"ui.panel.config.scene.editor.entities.device_entities"
)}
<ha-entity-picker
@value-changed=${this._entityPicked}
.excludeDomains=${SCENE_IGNORED_DOMAINS}
.hass=${this.hass}
label=${this.hass.localize(
"ui.panel.config.scene.editor.entities.add"
)}
></ha-entity-picker>
</div>
</ha-card>
</ha-config-section>
`
: ""}
</div>
<ha-fab
?is-wide=${this.isWide}
?narrow=${this.narrow}
?dirty=${this._dirty}
icon="hass:content-save"
.title=${this.hass.localize("ui.panel.config.scene.editor.save")}
@click=${this._saveScene}
class=${classMap({
rtl: computeRTL(this.hass),
})}
></ha-fab>
</ha-app-layout>
</hass-tabs-subpage>
`;
}

View File

@ -1,4 +1,5 @@
import "@material/mwc-button";
import "@polymer/paper-input/paper-input";
import "@polymer/paper-spinner/paper-spinner";
import {
css,

View File

@ -113,7 +113,7 @@ class ZHAConfigDashboard extends LitElement {
protected render(): TemplateResult {
return html`
<hass-subpage .header=${this.hass.localize("ui.panel.config.zha.title")}>
<hass-subpage .header=${this.hass.localize("component.zha.title")}>
<ha-config-section .narrow=${this.narrow} .isWide=${this.isWide}>
<div slot="header">
${this.hass.localize("ui.panel.config.zha.header")}

View File

@ -36,12 +36,12 @@ import {
ZHADevice,
ZHAEntityReference,
} from "../../../data/zha";
import { showZHADeviceZigbeeInfoDialog } from "../../../dialogs/zha-device-zigbee-signature-dialog/show-dialog-zha-device-zigbee-info";
import { haStyle } from "../../../resources/styles";
import { HomeAssistant } from "../../../types";
import { addEntitiesToLovelaceView } from "../../lovelace/editor/add-entities-to-view";
import { formatAsPaddedHex } from "./functions";
import { ItemSelectedEvent, NodeServiceData } from "./types";
import { showZHADeviceZigbeeInfoDialog } from "../../../dialogs/zha-device-zigbee-signature-dialog/show-dialog-zha-device-zigbee-info";
declare global {
// for fire event

View File

@ -8,11 +8,12 @@ import {
TemplateResult,
} from "lit-element";
import memoizeOne from "memoize-one";
import "../../../components/ha-card";
import {
domainToName,
fetchIntegrationManifests,
integrationIssuesUrl,
IntegrationManifest,
fetchIntegrationManifests,
domainToName,
} from "../../../data/integration";
import { HomeAssistant } from "../../../types";

View File

@ -8,12 +8,12 @@ import {
TemplateResult,
} from "lit-element";
import "../../../components/ha-card";
import { domainToName } from "../../../data/integration";
import {
fetchSystemHealthInfo,
SystemHealthInfo,
} from "../../../data/system_health";
import { HomeAssistant } from "../../../types";
import { domainToName } from "../../../data/integration";
const sortKeys = (a: string, b: string) => {
if (a === "homeassistant") {

View File

@ -10,9 +10,9 @@ import {
import "../../../components/dialog/ha-paper-dialog";
import {
domainToName,
fetchIntegrationManifest,
integrationIssuesUrl,
IntegrationManifest,
fetchIntegrationManifest,
} from "../../../data/integration";
import { getLoggedErrorIntegration } from "../../../data/system_log";
import { PolymerChangedEvent } from "../../../polymer-types";

View File

@ -165,7 +165,7 @@ class HuiAlarmPanelCard extends LitElement implements LovelaceCard {
<ha-card
.header="${this._config.name ||
stateObj.attributes.friendly_name ||
this._label(stateObj.state)}"
this._stateDisplay(stateObj.state)}"
>
<ha-label-badge
class="${classMap({ [stateObj.state]: true })}"
@ -184,7 +184,7 @@ class HuiAlarmPanelCard extends LitElement implements LovelaceCard {
@click="${this._handleActionClick}"
outlined
>
${this._label(state)}
${this._stateDisplay(state)}
</mwc-button>
`;
})}
@ -212,7 +212,9 @@ class HuiAlarmPanelCard extends LitElement implements LovelaceCard {
outlined
>
${value === "clear"
? this._label("clear_code")
? this.hass!.localize(
`ui.card.alarm_control_panel.clear_code`
)
: value}
</mwc-button>
`;
@ -232,10 +234,9 @@ class HuiAlarmPanelCard extends LitElement implements LovelaceCard {
: stateLabel;
}
private _label(state: string): string {
return (
this.hass!.localize(`state.alarm_control_panel.${state}`) ||
this.hass!.localize(`ui.card.alarm_control_panel.${state}`)
private _stateDisplay(state: string): string {
return this.hass!.localize(
`component.alarm_control_panel.state._.${state}`
);
}

View File

@ -1,3 +1,4 @@
import "@material/mwc-button/mwc-button";
import {
css,
CSSResult,
@ -49,7 +50,7 @@ export class HuiEmptyStateCard extends LitElement implements LovelaceCard {
</mwc-button>
</a>
</div>
</header-card>
</ha-card>
`;
}

View File

@ -10,6 +10,7 @@ import {
} from "lit-element";
import { applyThemesOnElement } from "../../../common/dom/apply_themes_on_element";
import { fireEvent } from "../../../common/dom/fire_event";
import { computeStateDisplay } from "../../../common/entity/compute_state_display";
import { computeStateName } from "../../../common/entity/compute_state_name";
import { stateIcon } from "../../../common/entity/state_icon";
import { isValidEntityId } from "../../../common/entity/valid_entity_id";
@ -128,13 +129,11 @@ export class HuiEntityCard extends LitElement implements LovelaceCard {
>${"attribute" in this._config
? stateObj.attributes[this._config.attribute!] ||
this.hass.localize("state.default.unknown")
: this.hass.localize(`state.default.${stateObj.state}`) ||
this.hass.localize(
`state.${this._config.entity.split(".")[0]}.${
stateObj.state
}`
) ||
stateObj.state}</span
: computeStateDisplay(
this.hass.localize,
stateObj,
this.hass.language
)}</span
>${showUnit
? html`
<span class="measurement"

View File

@ -28,6 +28,7 @@ import { hasAction } from "../common/has-action";
import { processConfigEntities } from "../common/process-config-entities";
import "../components/hui-warning-element";
import { LovelaceCard, LovelaceCardEditor } from "../types";
import "../components/hui-timestamp-display";
import { GlanceCardConfig, GlanceConfigEntity } from "./types";
@customElement("hui-glance-card")

View File

@ -14,6 +14,7 @@ import { classMap } from "lit-html/directives/class-map";
import { styleMap } from "lit-html/directives/style-map";
import { applyThemesOnElement } from "../../../common/dom/apply_themes_on_element";
import { fireEvent } from "../../../common/dom/fire_event";
import { computeStateDisplay } from "../../../common/entity/compute_state_display";
import { computeStateName } from "../../../common/entity/compute_state_name";
import { stateIcon } from "../../../common/entity/state_icon";
import { supportsFeature } from "../../../common/entity/supports-feature";
@ -154,8 +155,11 @@ export class HuiLightCard extends LitElement implements LovelaceCard {
${UNAVAILABLE_STATES.includes(stateObj.state)
? html`
<div>
${this.hass.localize(`state.default.${stateObj.state}`) ||
stateObj.state}
${computeStateDisplay(
this.hass.localize,
stateObj,
this.hass.language
)}
</div>
`
: html`

View File

@ -37,6 +37,7 @@ import { findEntities } from "../common/find-entites";
import { processConfigEntities } from "../common/process-config-entities";
import { EntityConfig } from "../entity-rows/types";
import { LovelaceCard } from "../types";
import "../../../components/ha-card";
import { MapCardConfig } from "./types";
@customElement("hui-map-card")

View File

@ -45,6 +45,7 @@ import { findEntities } from "../common/find-entites";
import { hasConfigOrEntityChanged } from "../common/has-changed";
import "../components/hui-marquee";
import type { LovelaceCard, LovelaceCardEditor } from "../types";
import "../components/hui-warning";
import { MediaControlCardConfig } from "./types";
function getContrastRatio(

View File

@ -9,6 +9,7 @@ import {
TemplateResult,
} from "lit-element";
import { applyThemesOnElement } from "../../../common/dom/apply_themes_on_element";
import "../../../components/ha-card";
import { HomeAssistant } from "../../../types";
import { findEntities } from "../common/find-entites";
import { LovelaceElement, LovelaceElementConfig } from "../elements/types";
@ -107,7 +108,7 @@ class HuiPictureElementsCard extends LitElement implements LovelaceCard {
}
return html`
<ha-card .header="${this._config.title}">
<ha-card .header=${this._config.title}>
<div id="root">
<hui-image
.hass=${this._hass}

View File

@ -195,7 +195,9 @@ export class HuiThermostatCard extends LitElement implements LovelaceCard {
? this.hass!.localize(
`state_attributes.climate.hvac_action.${stateObj.attributes.hvac_action}`
)
: this.hass!.localize(`state.climate.${stateObj.state}`)
: this.hass!.localize(
`component.climate.state._.${stateObj.state}`
)
}
${
stateObj.attributes.preset_mode &&
@ -384,7 +386,7 @@ export class HuiThermostatCard extends LitElement implements LovelaceCard {
@action=${this._handleAction}
.actionHandler=${actionHandler()}
tabindex="0"
></ha-icon>
></paper-icon-button>
`;
}

View File

@ -8,30 +8,29 @@ import {
PropertyValues,
TemplateResult,
} from "lit-element";
import "../../../components/ha-icon";
import "../../../components/ha-card";
import "../components/hui-warning";
import { WeatherForecastCardConfig } from "./types";
import { LovelaceCard, LovelaceCardEditor } from "../types";
import { HomeAssistant, WeatherEntity } from "../../../types";
import { findEntities } from "../common/find-entites";
import { hasConfigOrEntityChanged } from "../common/has-changed";
import { actionHandler } from "../common/directives/action-handler-directive";
import { isValidEntityId } from "../../../common/entity/valid_entity_id";
import { computeStateName } from "../../../common/entity/compute_state_name";
import { fireEvent } from "../../../common/dom/fire_event";
import { applyThemesOnElement } from "../../../common/dom/apply_themes_on_element";
import { fireEvent } from "../../../common/dom/fire_event";
import { computeStateDisplay } from "../../../common/entity/compute_state_display";
import { computeStateName } from "../../../common/entity/compute_state_name";
import { stateIcon } from "../../../common/entity/state_icon";
import { isValidEntityId } from "../../../common/entity/valid_entity_id";
import { debounce } from "../../../common/util/debounce";
import "../../../components/ha-card";
import "../../../components/ha-icon";
import { UNAVAILABLE } from "../../../data/entity";
import {
weatherIcons,
getSecondaryWeatherAttribute,
getWeatherUnit,
weatherIcons,
weatherImages,
} from "../../../data/weather";
import { stateIcon } from "../../../common/entity/state_icon";
import { HomeAssistant, WeatherEntity } from "../../../types";
import { actionHandler } from "../common/directives/action-handler-directive";
import { findEntities } from "../common/find-entites";
import { hasConfigOrEntityChanged } from "../common/has-changed";
import "../components/hui-warning";
import { LovelaceCard, LovelaceCardEditor } from "../types";
import { WeatherForecastCardConfig } from "./types";
const DAY_IN_MILLISECONDS = 86400000;
@ -185,8 +184,11 @@ class HuiWeatherForecastCard extends LitElement implements LovelaceCard {
${this._config.name || computeStateName(stateObj)}
</div>
<div class="state">
${this.hass.localize(`state.weather.${stateObj.state}`) ||
stateObj.state}
${computeStateDisplay(
this.hass.localize,
stateObj,
this.hass.language
)}
</div>
</div>
</div>

View File

@ -25,6 +25,7 @@ import {
EntityRegistryEntry,
subscribeEntityRegistry,
} from "../../../data/entity_registry";
import { domainToName } from "../../../data/integration";
import {
LovelaceCardConfig,
LovelaceConfig,
@ -41,7 +42,6 @@ import {
} from "../cards/types";
import { processEditorEntities } from "../editor/process-editor-entities";
import { LovelaceRowConfig, WeblinkConfig } from "../entity-rows/types";
import { domainToName } from "../../../data/integration";
const DEFAULT_VIEW_ENTITY_ID = "group.default_view";
const DOMAINS_BADGES = [

View File

@ -13,6 +13,7 @@ import { classMap } from "lit-html/directives/class-map";
import { styleMap } from "lit-html/directives/style-map";
import { STATES_OFF } from "../../../common/const";
import parseAspectRatio from "../../../common/util/parse-aspect-ratio";
import "../../../components/ha-camera-stream";
import { fetchThumbnailUrlWithCache } from "../../../data/camera";
import { CameraEntity, HomeAssistant } from "../../../types";

View File

@ -1,3 +1,4 @@
import "@polymer/paper-icon-button/paper-icon-button";
import "@polymer/paper-input/paper-input";
import {
css,

View File

@ -1,4 +1,7 @@
import "@material/mwc-button";
import "@polymer/paper-dropdown-menu/paper-dropdown-menu";
import "@polymer/paper-item/paper-item";
import "@polymer/paper-listbox/paper-listbox";
import {
css,
CSSResult,

View File

@ -1,3 +1,4 @@
import * as Fuse from "fuse.js";
import {
css,
CSSResult,
@ -11,17 +12,14 @@ import {
import { classMap } from "lit-html/directives/class-map";
import { until } from "lit-html/directives/until";
import memoizeOne from "memoize-one";
import * as Fuse from "fuse.js";
import { CardPickTarget } from "../types";
import { LovelaceCard } from "../../types";
import { LovelaceCardConfig, LovelaceConfig } from "../../../../data/lovelace";
import { fireEvent } from "../../../../common/dom/fire_event";
import "../../../../common/search/search-input";
import { UNAVAILABLE_STATES } from "../../../../data/entity";
import { LovelaceCardConfig, LovelaceConfig } from "../../../../data/lovelace";
import {
CUSTOM_TYPE_PREFIX,
CustomCardEntry,
customCards,
CUSTOM_TYPE_PREFIX,
getCustomCardEntry,
} from "../../../../data/lovelace_custom_cards";
import { HomeAssistant } from "../../../../types";
@ -30,9 +28,9 @@ import {
computeUsedEntities,
} from "../../common/compute-unused-entities";
import { createCardElement } from "../../create-element/create-card-element";
import { LovelaceCard } from "../../types";
import { getCardStubConfig } from "../get-card-stub-config";
import "../../../../common/search/search-input";
import { CardPickTarget } from "../types";
interface Card {
type: string;

View File

@ -35,11 +35,12 @@ export class HuiDialogMoveCardView extends LitElement {
@opened-changed="${this._openedChanged}"
>
<h2>Choose view to move card</h2>
<hui-views-list
.lovelaceConfig=${this._params!.lovelace.config}
.selected=${this._params!.path![0]}
@view-selected=${this._moveCard}>
</hui-view-list>
<hui-views-list
.lovelaceConfig=${this._params!.lovelace.config}
.selected=${this._params!.path![0]}
@view-selected=${this._moveCard}
>
</hui-views-list>
</ha-paper-dialog>
`;
}

View File

@ -29,6 +29,8 @@ const cardConfigStruct = struct({
theme: "string?",
});
const includeDomains = ["alarm_control_panel"];
@customElement("hui-alarm-panel-card-editor")
export class HuiAlarmPanelCardEditor extends LitElement
implements LovelaceCardEditor {
@ -76,7 +78,7 @@ export class HuiAlarmPanelCardEditor extends LitElement
.hass=${this.hass}
.value="${this._entity}"
.configValue=${"entity"}
.include-domains=${["alarm_control_panel"]}
.includeDomains=${includeDomains}
@change="${this._valueChanged}"
allow-custom-entity
></ha-entity-picker>

View File

@ -22,6 +22,7 @@ import {
EditorTarget,
EntitiesEditorEvent,
} from "../types";
import "../../../../components/ha-switch";
import { configElementStyle } from "./config-elements-style";
const cardConfigStruct = struct({

View File

@ -1,4 +1,5 @@
import "@polymer/paper-tabs";
import "@polymer/paper-tabs/paper-tab";
import {
css,
CSSResult,
@ -21,6 +22,7 @@ import {
ConfigChangedEvent,
HuiCardEditor,
} from "../card-editor/hui-card-editor";
import "../card-editor/hui-card-picker";
import { GUIModeChangedEvent } from "../types";
const conditionStruct = struct({

View File

@ -30,6 +30,8 @@ const cardConfigStruct = struct({
theme: "string?",
});
const includeDomains = ["sensor"];
@customElement("hui-gauge-card-editor")
export class HuiGaugeCardEditor extends LitElement
implements LovelaceCardEditor {
@ -87,7 +89,7 @@ export class HuiGaugeCardEditor extends LitElement
.hass=${this.hass}
.value="${this._entity}"
.configValue=${"entity"}
.include-domains=${["sensor"]}
.includeDomains=${includeDomains}
@change="${this._valueChanged}"
allow-custom-entity
></ha-entity-picker>

View File

@ -34,6 +34,8 @@ const cardConfigStruct = struct({
double_tap_action: struct.optional(actionConfigStruct),
});
const includeDomains = ["light"];
@customElement("hui-light-card-editor")
export class HuiLightCardEditor extends LitElement
implements LovelaceCardEditor {
@ -95,7 +97,7 @@ export class HuiLightCardEditor extends LitElement
.hass=${this.hass}
.value=${this._entity}
.configValue=${"entity"}
.include-domains=${["light"]}
.includeDomains=${includeDomains}
@change=${this._valueChanged}
allow-custom-entity
></ha-entity-picker>

View File

@ -23,6 +23,7 @@ import {
entitiesConfigStruct,
EntitiesEditorEvent,
} from "../types";
import "../../../../components/ha-switch";
import { configElementStyle } from "./config-elements-style";
const cardConfigStruct = struct({

View File

@ -18,6 +18,8 @@ const cardConfigStruct = struct({
entity: "string?",
});
const includeDomains = ["media_player"];
@customElement("hui-media-control-card-editor")
export class HuiMediaControlCardEditor extends LitElement
implements LovelaceCardEditor {
@ -50,7 +52,7 @@ export class HuiMediaControlCardEditor extends LitElement
.hass=${this.hass}
.value="${this._entity}"
.configValue=${"entity"}
.include-domains=${["media_player"]}
.includeDomains=${includeDomains}
@change="${this._valueChanged}"
allow-custom-entity
></ha-entity-picker>

View File

@ -41,6 +41,8 @@ const cardConfigStruct = struct({
theme: "string?",
});
const includeDomains = ["camera"];
@customElement("hui-picture-entity-card-editor")
export class HuiPictureEntityCardEditor extends LitElement
implements LovelaceCardEditor {
@ -150,7 +152,7 @@ export class HuiPictureEntityCardEditor extends LitElement
.value="${this._camera_image}"
.configValue=${"camera_image"}
@change="${this._valueChanged}"
.include-domains=${["camera"]}
.includeDomains=${includeDomains}
allow-custom-entity
></ha-entity-picker>
<div class="side-by-side">

View File

@ -43,6 +43,8 @@ const cardConfigStruct = struct({
theme: "string?",
});
const includeDomains = ["camera"];
@customElement("hui-picture-glance-card-editor")
export class HuiPictureGlanceCardEditor extends LitElement
implements LovelaceCardEditor {
@ -150,7 +152,7 @@ export class HuiPictureGlanceCardEditor extends LitElement
.configValue=${"camera_image"}
@change="${this._valueChanged}"
allow-custom-entity
.include-domains=${["camera"]}
.includeDomains=${includeDomains}
></ha-entity-picker>
<div class="side-by-side">
<paper-dropdown-menu

View File

@ -24,6 +24,8 @@ const cardConfigStruct = struct({
theme: "string?",
});
const includeDomains = ["plant"];
@customElement("hui-plant-status-card-editor")
export class HuiPlantStatusCardEditor extends LitElement
implements LovelaceCardEditor {
@ -65,7 +67,7 @@ export class HuiPlantStatusCardEditor extends LitElement
.hass=${this.hass}
.value="${this._entity}"
.configValue=${"entity"}
.include-domains=${["plant"]}
.includeDomains=${includeDomains}
@change="${this._valueChanged}"
allow-custom-entity
></ha-entity-picker>

View File

@ -33,6 +33,8 @@ const cardConfigStruct = struct({
hours_to_show: "number?",
});
const includeDomains = ["sensor"];
@customElement("hui-sensor-card-editor")
export class HuiSensorCardEditor extends LitElement
implements LovelaceCardEditor {
@ -96,7 +98,7 @@ export class HuiSensorCardEditor extends LitElement
.hass=${this.hass}
.value="${this._entity}"
.configValue=${"entity"}
.include-domains=${["sensor"]}
.includeDomains=${includeDomains}
@change="${this._valueChanged}"
allow-custom-entity
></ha-entity-picker>

View File

@ -1,4 +1,6 @@
import "@polymer/paper-icon-button/paper-icon-button";
import "@polymer/paper-tabs";
import "@polymer/paper-tabs/paper-tab";
import {
css,
CSSResult,
@ -19,6 +21,7 @@ import {
ConfigChangedEvent,
HuiCardEditor,
} from "../card-editor/hui-card-editor";
import "../card-editor/hui-card-picker";
import { GUIModeChangedEvent } from "../types";
const cardConfigStruct = struct({
@ -79,63 +82,61 @@ export class HuiStackCardEditor extends LitElement
<paper-tab>
<ha-icon icon="hass:plus"></ha-icon>
</paper-tab>
<paper-tabs>
</paper-tabs>
</div>
<div id="editor">
${
selected < numcards
? html`
<div id="card-options">
<mwc-button
@click=${this._toggleMode}
.disabled=${!this._guiModeAvailable}
class="gui-mode-button"
>
${this.hass!.localize(
!this._cardEditorEl || this._GUImode
? "ui.panel.lovelace.editor.edit_card.show_code_editor"
: "ui.panel.lovelace.editor.edit_card.show_visual_editor"
)}
</mwc-button>
<paper-icon-button
id="move-before"
title="Move card before"
icon="hass:arrow-left"
.disabled=${selected === 0}
@click=${this._handleMove}
></paper-icon-button>
${selected < numcards
? html`
<div id="card-options">
<mwc-button
@click=${this._toggleMode}
.disabled=${!this._guiModeAvailable}
class="gui-mode-button"
>
${this.hass!.localize(
!this._cardEditorEl || this._GUImode
? "ui.panel.lovelace.editor.edit_card.show_code_editor"
: "ui.panel.lovelace.editor.edit_card.show_visual_editor"
)}
</mwc-button>
<paper-icon-button
id="move-before"
title="Move card before"
icon="hass:arrow-left"
.disabled=${selected === 0}
@click=${this._handleMove}
></paper-icon-button>
<paper-icon-button
id="move-after"
title="Move card after"
icon="hass:arrow-right"
.disabled=${selected === numcards - 1}
@click=${this._handleMove}
></paper-icon-button>
<paper-icon-button
id="move-after"
title="Move card after"
icon="hass:arrow-right"
.disabled=${selected === numcards - 1}
@click=${this._handleMove}
></paper-icon-button>
<paper-icon-button
icon="hass:delete"
@click=${this._handleDeleteCard}
></paper-icon-button>
</div>
<paper-icon-button
icon="hass:delete"
@click=${this._handleDeleteCard}
></paper-icon-button>
</div>
<hui-card-editor
.hass=${this.hass}
.value=${this._config.cards[selected]}
.lovelace=${this.lovelace}
@config-changed=${this._handleConfigChanged}
@GUImode-changed=${this._handleGUIModeChanged}
></hui-card-editor>
`
: html`
<hui-card-picker
.hass=${this.hass}
.lovelace=${this.lovelace}
@config-changed="${this._handleCardPicked}"
></hui-card-picker>
`
}
<hui-card-editor
.hass=${this.hass}
.value=${this._config.cards[selected]}
.lovelace=${this.lovelace}
@config-changed=${this._handleConfigChanged}
@GUImode-changed=${this._handleGUIModeChanged}
></hui-card-editor>
`
: html`
<hui-card-picker
.hass=${this.hass}
.lovelace=${this.lovelace}
@config-changed="${this._handleCardPicked}"
></hui-card-picker>
`}
</div>
</div>
`;

View File

@ -23,6 +23,8 @@ const cardConfigStruct = struct({
theme: "string?",
});
const includeDomains = ["climate"];
@customElement("hui-thermostat-card-editor")
export class HuiThermostatCardEditor extends LitElement
implements LovelaceCardEditor {
@ -64,7 +66,7 @@ export class HuiThermostatCardEditor extends LitElement
.hass=${this.hass}
.value="${this._entity}"
.configValue=${"entity"}
.include-domains=${["climate"]}
.includeDomains=${includeDomains}
@change="${this._valueChanged}"
allow-custom-entity
></ha-entity-picker>

View File

@ -8,13 +8,12 @@ import {
import { fireEvent } from "../../../../common/dom/fire_event";
import "../../../../components/entity/ha-entity-picker";
import "../../../../components/ha-switch";
import { EntitiesEditorEvent, EditorTarget } from "../types";
import { HomeAssistant } from "../../../../types";
import { WeatherForecastCardConfig } from "../../cards/types";
import { struct } from "../../common/structs/struct";
import "../../components/hui-theme-select-editor";
import { LovelaceCardEditor } from "../../types";
import { EditorTarget, EntitiesEditorEvent } from "../types";
import { configElementStyle } from "./config-elements-style";
const cardConfigStruct = struct({
@ -25,6 +24,8 @@ const cardConfigStruct = struct({
show_forecast: "boolean?",
});
const includeDomains = ["weather"];
@customElement("hui-weather-forecast-card-editor")
export class HuiWeatherForecastCardEditor extends LitElement
implements LovelaceCardEditor {
@ -70,7 +71,7 @@ export class HuiWeatherForecastCardEditor extends LitElement
.hass=${this.hass}
.value=${this._entity}
.configValue=${"entity"}
.includeDomains=${["weather"]}
.includeDomains=${includeDomains}
@change=${this._valueChanged}
allow-custom-entity
></ha-entity-picker>

View File

@ -1,4 +1,5 @@
import "@material/mwc-button";
import "@polymer/paper-dialog-scrollable/paper-dialog-scrollable";
import "@polymer/paper-spinner/paper-spinner";
import {
css,

Some files were not shown because too many files have changed in this diff Show More