mirror of
https://github.com/home-assistant/frontend.git
synced 2025-07-19 07:16:39 +00:00
Merge pull request #10818 from home-assistant/dev
This commit is contained in:
commit
8f729e2a95
@ -48,7 +48,6 @@ import "../../../src/layouts/hass-subpage";
|
|||||||
import "../../../src/layouts/hass-tabs-subpage";
|
import "../../../src/layouts/hass-tabs-subpage";
|
||||||
import { SUPERVISOR_UPDATE_NAMES } from "../../../src/panels/config/dashboard/ha-config-updates";
|
import { SUPERVISOR_UPDATE_NAMES } from "../../../src/panels/config/dashboard/ha-config-updates";
|
||||||
import { HomeAssistant, Route } from "../../../src/types";
|
import { HomeAssistant, Route } from "../../../src/types";
|
||||||
import { documentationUrl } from "../../../src/util/documentation-url";
|
|
||||||
import { addonArchIsSupported, extractChangelog } from "../util/addon";
|
import { addonArchIsSupported, extractChangelog } from "../util/addon";
|
||||||
|
|
||||||
declare global {
|
declare global {
|
||||||
@ -60,7 +59,6 @@ declare global {
|
|||||||
type updateType = "os" | "supervisor" | "core" | "addon";
|
type updateType = "os" | "supervisor" | "core" | "addon";
|
||||||
|
|
||||||
const changelogUrl = (
|
const changelogUrl = (
|
||||||
hass: HomeAssistant,
|
|
||||||
entry: updateType,
|
entry: updateType,
|
||||||
version: string
|
version: string
|
||||||
): string | undefined => {
|
): string | undefined => {
|
||||||
@ -68,17 +66,19 @@ const changelogUrl = (
|
|||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
if (entry === "core") {
|
if (entry === "core") {
|
||||||
return version?.includes("dev")
|
return version.includes("dev")
|
||||||
? "https://github.com/home-assistant/core/commits/dev"
|
? "https://github.com/home-assistant/core/commits/dev"
|
||||||
: documentationUrl(hass, "/latest-release-notes/");
|
: version.includes("b")
|
||||||
|
? "https://next.home-assistant.io/latest-release-notes/"
|
||||||
|
: "https://www.home-assistant.io/latest-release-notes/";
|
||||||
}
|
}
|
||||||
if (entry === "os") {
|
if (entry === "os") {
|
||||||
return version?.includes("dev")
|
return version.includes("dev")
|
||||||
? "https://github.com/home-assistant/operating-system/commits/dev"
|
? "https://github.com/home-assistant/operating-system/commits/dev"
|
||||||
: `https://github.com/home-assistant/operating-system/releases/tag/${version}`;
|
: `https://github.com/home-assistant/operating-system/releases/tag/${version}`;
|
||||||
}
|
}
|
||||||
if (entry === "supervisor") {
|
if (entry === "supervisor") {
|
||||||
return version?.includes("dev")
|
return version.includes("dev")
|
||||||
? "https://github.com/home-assistant/supervisor/commits/main"
|
? "https://github.com/home-assistant/supervisor/commits/main"
|
||||||
: `https://github.com/home-assistant/supervisor/releases/tag/${version}`;
|
: `https://github.com/home-assistant/supervisor/releases/tag/${version}`;
|
||||||
}
|
}
|
||||||
@ -120,7 +120,7 @@ class UpdateAvailableCard extends LitElement {
|
|||||||
return html``;
|
return html``;
|
||||||
}
|
}
|
||||||
|
|
||||||
const changelog = changelogUrl(this.hass, this._updateType, this._version);
|
const changelog = changelogUrl(this._updateType, this._version);
|
||||||
|
|
||||||
return html`
|
return html`
|
||||||
<ha-card
|
<ha-card
|
||||||
|
2
setup.py
2
setup.py
@ -2,7 +2,7 @@ from setuptools import setup, find_packages
|
|||||||
|
|
||||||
setup(
|
setup(
|
||||||
name="home-assistant-frontend",
|
name="home-assistant-frontend",
|
||||||
version="20211203.0",
|
version="20211206.0",
|
||||||
description="The Home Assistant frontend",
|
description="The Home Assistant frontend",
|
||||||
url="https://github.com/home-assistant/frontend",
|
url="https://github.com/home-assistant/frontend",
|
||||||
author="The Home Assistant Authors",
|
author="The Home Assistant Authors",
|
||||||
|
@ -221,6 +221,7 @@ export const DOMAINS_INPUT_ROW = [
|
|||||||
"scene",
|
"scene",
|
||||||
"script",
|
"script",
|
||||||
"select",
|
"select",
|
||||||
|
"switch",
|
||||||
];
|
];
|
||||||
|
|
||||||
/** Domains that should have the history hidden in the more info dialog. */
|
/** Domains that should have the history hidden in the more info dialog. */
|
||||||
|
@ -96,7 +96,11 @@ export class HaDateInput extends LitElement {
|
|||||||
attr-for-value="value"
|
attr-for-value="value"
|
||||||
.i18n=${i18n}
|
.i18n=${i18n}
|
||||||
>
|
>
|
||||||
<paper-input .label=${this.label} no-label-float>
|
<paper-input
|
||||||
|
.label=${this.label}
|
||||||
|
.disabled=${this.disabled}
|
||||||
|
no-label-float
|
||||||
|
>
|
||||||
<ha-svg-icon slot="suffix" .path=${mdiCalendar}></ha-svg-icon>
|
<ha-svg-icon slot="suffix" .path=${mdiCalendar}></ha-svg-icon>
|
||||||
</paper-input>
|
</paper-input>
|
||||||
</vaadin-date-picker-light>`;
|
</vaadin-date-picker-light>`;
|
||||||
|
@ -39,6 +39,7 @@ export class HaPictureUpload extends LitElement {
|
|||||||
.uploading=${this._uploading}
|
.uploading=${this._uploading}
|
||||||
.value=${this.value ? html`<img .src=${this.value} />` : ""}
|
.value=${this.value ? html`<img .src=${this.value} />` : ""}
|
||||||
@file-picked=${this._handleFilePicked}
|
@file-picked=${this._handleFilePicked}
|
||||||
|
@change=${this._handleFileCleared}
|
||||||
accept="image/png, image/jpeg, image/gif"
|
accept="image/png, image/jpeg, image/gif"
|
||||||
></ha-file-upload>
|
></ha-file-upload>
|
||||||
`;
|
`;
|
||||||
@ -53,6 +54,10 @@ export class HaPictureUpload extends LitElement {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async _handleFileCleared() {
|
||||||
|
this.value = null;
|
||||||
|
}
|
||||||
|
|
||||||
private async _cropFile(file: File) {
|
private async _cropFile(file: File) {
|
||||||
if (!["image/png", "image/jpeg", "image/gif"].includes(file.type)) {
|
if (!["image/png", "image/jpeg", "image/gif"].includes(file.type)) {
|
||||||
showAlertDialog(this, {
|
showAlertDialog(this, {
|
||||||
|
@ -208,11 +208,11 @@ export const enum NodeStatus {
|
|||||||
export interface ZwaveJSProvisioningEntry {
|
export interface ZwaveJSProvisioningEntry {
|
||||||
/** The device specific key (DSK) in the form aaaaa-bbbbb-ccccc-ddddd-eeeee-fffff-11111-22222 */
|
/** The device specific key (DSK) in the form aaaaa-bbbbb-ccccc-ddddd-eeeee-fffff-11111-22222 */
|
||||||
dsk: string;
|
dsk: string;
|
||||||
securityClasses: SecurityClass[];
|
security_classes: SecurityClass[];
|
||||||
/**
|
additional_properties: {
|
||||||
* Additional properties to be stored in this provisioning entry, e.g. the device ID from a scanned QR code
|
nodeId?: number;
|
||||||
*/
|
|
||||||
[prop: string]: any;
|
[prop: string]: any;
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface RequestedGrant {
|
export interface RequestedGrant {
|
||||||
@ -278,7 +278,7 @@ export const setZwaveDataCollectionPreference = (
|
|||||||
export const fetchZwaveProvisioningEntries = (
|
export const fetchZwaveProvisioningEntries = (
|
||||||
hass: HomeAssistant,
|
hass: HomeAssistant,
|
||||||
entry_id: string
|
entry_id: string
|
||||||
): Promise<any> =>
|
): Promise<ZwaveJSProvisioningEntry[]> =>
|
||||||
hass.callWS({
|
hass.callWS({
|
||||||
type: "zwave_js/get_provisioning_entries",
|
type: "zwave_js/get_provisioning_entries",
|
||||||
entry_id,
|
entry_id,
|
||||||
|
@ -1,17 +1,27 @@
|
|||||||
import "@polymer/paper-input/paper-input";
|
import "@polymer/paper-input/paper-input";
|
||||||
import { html, LitElement, PropertyValues } from "lit";
|
import { html, LitElement, PropertyValues } from "lit";
|
||||||
import { customElement, property } from "lit/decorators";
|
import { customElement, property } from "lit/decorators";
|
||||||
|
import { assert, literal, object, optional, string, union } from "superstruct";
|
||||||
import { createDurationData } from "../../../../../common/datetime/create_duration_data";
|
import { createDurationData } from "../../../../../common/datetime/create_duration_data";
|
||||||
|
import { fireEvent } from "../../../../../common/dom/fire_event";
|
||||||
import "../../../../../components/entity/ha-entity-attribute-picker";
|
import "../../../../../components/entity/ha-entity-attribute-picker";
|
||||||
import "../../../../../components/entity/ha-entity-picker";
|
import "../../../../../components/entity/ha-entity-picker";
|
||||||
|
import "../../../../../components/ha-duration-input";
|
||||||
import { StateCondition } from "../../../../../data/automation";
|
import { StateCondition } from "../../../../../data/automation";
|
||||||
import { HomeAssistant } from "../../../../../types";
|
import { HomeAssistant } from "../../../../../types";
|
||||||
|
import { forDictStruct } from "../../structs";
|
||||||
import {
|
import {
|
||||||
ConditionElement,
|
ConditionElement,
|
||||||
handleChangeEvent,
|
handleChangeEvent,
|
||||||
} from "../ha-automation-condition-row";
|
} from "../ha-automation-condition-row";
|
||||||
import "../../../../../components/ha-duration-input";
|
|
||||||
import { fireEvent } from "../../../../../common/dom/fire_event";
|
const stateConditionStruct = object({
|
||||||
|
condition: literal("state"),
|
||||||
|
entity_id: string(),
|
||||||
|
attribute: optional(string()),
|
||||||
|
state: string(),
|
||||||
|
for: optional(union([string(), forDictStruct])),
|
||||||
|
});
|
||||||
|
|
||||||
@customElement("ha-automation-condition-state")
|
@customElement("ha-automation-condition-state")
|
||||||
export class HaStateCondition extends LitElement implements ConditionElement {
|
export class HaStateCondition extends LitElement implements ConditionElement {
|
||||||
@ -23,20 +33,15 @@ export class HaStateCondition extends LitElement implements ConditionElement {
|
|||||||
return { entity_id: "", state: "" };
|
return { entity_id: "", state: "" };
|
||||||
}
|
}
|
||||||
|
|
||||||
public willUpdate(changedProperties: PropertyValues): boolean {
|
public shouldUpdate(changedProperties: PropertyValues) {
|
||||||
if (
|
if (changedProperties.has("condition")) {
|
||||||
changedProperties.has("condition") &&
|
try {
|
||||||
Array.isArray(this.condition?.state)
|
assert(this.condition, stateConditionStruct);
|
||||||
) {
|
} catch (e: any) {
|
||||||
fireEvent(
|
fireEvent(this, "ui-mode-not-available", e);
|
||||||
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 false;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
8
src/panels/config/automation/structs.ts
Normal file
8
src/panels/config/automation/structs.ts
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
import { object, optional, number } from "superstruct";
|
||||||
|
|
||||||
|
export const forDictStruct = object({
|
||||||
|
days: optional(number()),
|
||||||
|
hours: optional(number()),
|
||||||
|
minutes: optional(number()),
|
||||||
|
seconds: optional(number()),
|
||||||
|
});
|
@ -68,7 +68,7 @@ export const handleChangeEvent = (element: TriggerElement, ev: CustomEvent) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let newTrigger: Trigger;
|
let newTrigger: Trigger;
|
||||||
if (!newVal) {
|
if (newVal === undefined || newVal === "") {
|
||||||
newTrigger = { ...element.trigger };
|
newTrigger = { ...element.trigger };
|
||||||
delete newTrigger[name];
|
delete newTrigger[name];
|
||||||
} else {
|
} else {
|
||||||
|
@ -1,19 +1,30 @@
|
|||||||
import "@polymer/paper-input/paper-input";
|
import "@polymer/paper-input/paper-input";
|
||||||
import { html, LitElement, PropertyValues } from "lit";
|
import { html, LitElement, PropertyValues } from "lit";
|
||||||
import { customElement, property } from "lit/decorators";
|
import { customElement, property } from "lit/decorators";
|
||||||
|
import { assert, literal, object, optional, string, union } from "superstruct";
|
||||||
import { createDurationData } from "../../../../../common/datetime/create_duration_data";
|
import { createDurationData } from "../../../../../common/datetime/create_duration_data";
|
||||||
import { fireEvent } from "../../../../../common/dom/fire_event";
|
import { fireEvent } from "../../../../../common/dom/fire_event";
|
||||||
import { hasTemplate } from "../../../../../common/string/has-template";
|
import { hasTemplate } from "../../../../../common/string/has-template";
|
||||||
import "../../../../../components/entity/ha-entity-attribute-picker";
|
import "../../../../../components/entity/ha-entity-attribute-picker";
|
||||||
import "../../../../../components/entity/ha-entity-picker";
|
import "../../../../../components/entity/ha-entity-picker";
|
||||||
|
import "../../../../../components/ha-duration-input";
|
||||||
import { StateTrigger } from "../../../../../data/automation";
|
import { StateTrigger } from "../../../../../data/automation";
|
||||||
import { HomeAssistant } from "../../../../../types";
|
import { HomeAssistant } from "../../../../../types";
|
||||||
import "../../../../../components/ha-duration-input";
|
import { forDictStruct } from "../../structs";
|
||||||
import {
|
import {
|
||||||
handleChangeEvent,
|
handleChangeEvent,
|
||||||
TriggerElement,
|
TriggerElement,
|
||||||
} from "../ha-automation-trigger-row";
|
} from "../ha-automation-trigger-row";
|
||||||
|
|
||||||
|
const stateTriggerStruct = object({
|
||||||
|
platform: literal("state"),
|
||||||
|
entity_id: string(),
|
||||||
|
attribute: optional(string()),
|
||||||
|
from: optional(string()),
|
||||||
|
to: optional(string()),
|
||||||
|
for: optional(union([string(), forDictStruct])),
|
||||||
|
});
|
||||||
|
|
||||||
@customElement("ha-automation-trigger-state")
|
@customElement("ha-automation-trigger-state")
|
||||||
export class HaStateTrigger extends LitElement implements TriggerElement {
|
export class HaStateTrigger extends LitElement implements TriggerElement {
|
||||||
@property({ attribute: false }) public hass!: HomeAssistant;
|
@property({ attribute: false }) public hass!: HomeAssistant;
|
||||||
@ -24,9 +35,9 @@ export class HaStateTrigger extends LitElement implements TriggerElement {
|
|||||||
return { entity_id: "" };
|
return { entity_id: "" };
|
||||||
}
|
}
|
||||||
|
|
||||||
public willUpdate(changedProperties: PropertyValues) {
|
public shouldUpdate(changedProperties: PropertyValues) {
|
||||||
if (!changedProperties.has("trigger")) {
|
if (!changedProperties.has("trigger")) {
|
||||||
return;
|
return true;
|
||||||
}
|
}
|
||||||
// Check for templates in trigger. If found, revert to YAML mode.
|
// Check for templates in trigger. If found, revert to YAML mode.
|
||||||
if (this.trigger && hasTemplate(this.trigger)) {
|
if (this.trigger && hasTemplate(this.trigger)) {
|
||||||
@ -35,7 +46,15 @@ export class HaStateTrigger extends LitElement implements TriggerElement {
|
|||||||
"ui-mode-not-available",
|
"ui-mode-not-available",
|
||||||
Error(this.hass.localize("ui.errors.config.no_template_editor_support"))
|
Error(this.hass.localize("ui.errors.config.no_template_editor_support"))
|
||||||
);
|
);
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
try {
|
||||||
|
assert(this.trigger, stateTriggerStruct);
|
||||||
|
} catch (e: any) {
|
||||||
|
fireEvent(this, "ui-mode-not-available", e);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected render() {
|
protected render() {
|
||||||
|
@ -224,7 +224,7 @@ class HaBlueprintOverview extends LitElement {
|
|||||||
.narrow=${this.narrow}
|
.narrow=${this.narrow}
|
||||||
back-path="/config"
|
back-path="/config"
|
||||||
.route=${this.route}
|
.route=${this.route}
|
||||||
.tabs=${configSections.automations}
|
.tabs=${configSections.blueprints}
|
||||||
.columns=${this._columns(this.narrow, this.hass.language)}
|
.columns=${this._columns(this.narrow, this.hass.language)}
|
||||||
.data=${this._processedBlueprints(this.blueprints)}
|
.data=${this._processedBlueprints(this.blueprints)}
|
||||||
id="entity_id"
|
id="entity_id"
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { mdiCellphoneCog, mdiCloudLock } from "@mdi/js";
|
import { mdiCloudLock } from "@mdi/js";
|
||||||
import "@polymer/app-layout/app-header/app-header";
|
import "@polymer/app-layout/app-header/app-header";
|
||||||
import "@polymer/app-layout/app-toolbar/app-toolbar";
|
import "@polymer/app-layout/app-toolbar/app-toolbar";
|
||||||
import {
|
import {
|
||||||
@ -110,29 +110,10 @@ class HaConfigDashboard extends LitElement {
|
|||||||
></ha-config-navigation>
|
></ha-config-navigation>
|
||||||
`
|
`
|
||||||
: ""}
|
: ""}
|
||||||
${this._externalConfig?.hasSettingsScreen
|
|
||||||
? html`
|
|
||||||
<ha-config-navigation
|
|
||||||
.hass=${this.hass}
|
|
||||||
.narrow=${this.narrow}
|
|
||||||
.showAdvanced=${this.showAdvanced}
|
|
||||||
.pages=${[
|
|
||||||
{
|
|
||||||
path: "#external-app-configuration",
|
|
||||||
name: "Companion App",
|
|
||||||
description: "Location and notifications",
|
|
||||||
iconPath: mdiCellphoneCog,
|
|
||||||
iconColor: "#37474F",
|
|
||||||
core: true,
|
|
||||||
},
|
|
||||||
]}
|
|
||||||
@click=${this._handleExternalAppConfiguration}
|
|
||||||
></ha-config-navigation>
|
|
||||||
`
|
|
||||||
: ""}
|
|
||||||
<ha-config-navigation
|
<ha-config-navigation
|
||||||
.hass=${this.hass}
|
.hass=${this.hass}
|
||||||
.narrow=${this.narrow}
|
.narrow=${this.narrow}
|
||||||
|
.externalConfig=${this._externalConfig}
|
||||||
.showAdvanced=${this.showAdvanced}
|
.showAdvanced=${this.showAdvanced}
|
||||||
.pages=${configSections.dashboard}
|
.pages=${configSections.dashboard}
|
||||||
></ha-config-navigation>
|
></ha-config-navigation>
|
||||||
@ -142,13 +123,6 @@ class HaConfigDashboard extends LitElement {
|
|||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
private _handleExternalAppConfiguration(ev: Event) {
|
|
||||||
ev.preventDefault();
|
|
||||||
this.hass.auth.external!.fireMessage({
|
|
||||||
type: "config_screen/show",
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
static get styles(): CSSResultGroup {
|
static get styles(): CSSResultGroup {
|
||||||
return [
|
return [
|
||||||
haStyle,
|
haStyle,
|
||||||
|
@ -6,6 +6,7 @@ import { canShowPage } from "../../../common/config/can_show_page";
|
|||||||
import "../../../components/ha-card";
|
import "../../../components/ha-card";
|
||||||
import "../../../components/ha-icon-next";
|
import "../../../components/ha-icon-next";
|
||||||
import { CloudStatus, CloudStatusLoggedIn } from "../../../data/cloud";
|
import { CloudStatus, CloudStatusLoggedIn } from "../../../data/cloud";
|
||||||
|
import { ExternalConfig } from "../../../external_app/external_config";
|
||||||
import { PageNavigation } from "../../../layouts/hass-tabs-subpage";
|
import { PageNavigation } from "../../../layouts/hass-tabs-subpage";
|
||||||
import { HomeAssistant } from "../../../types";
|
import { HomeAssistant } from "../../../types";
|
||||||
|
|
||||||
@ -19,10 +20,16 @@ class HaConfigNavigation extends LitElement {
|
|||||||
|
|
||||||
@property() public pages!: PageNavigation[];
|
@property() public pages!: PageNavigation[];
|
||||||
|
|
||||||
|
@property() public externalConfig?: ExternalConfig;
|
||||||
|
|
||||||
protected render(): TemplateResult {
|
protected render(): TemplateResult {
|
||||||
return html`
|
return html`
|
||||||
${this.pages.map((page) =>
|
${this.pages.map((page) =>
|
||||||
canShowPage(this.hass, page)
|
(
|
||||||
|
page.path === "#external-app-configuration"
|
||||||
|
? this.externalConfig?.hasSettingsScreen
|
||||||
|
: canShowPage(this.hass, page)
|
||||||
|
)
|
||||||
? html`
|
? html`
|
||||||
<a href=${page.path} aria-role="option" tabindex="-1">
|
<a href=${page.path} aria-role="option" tabindex="-1">
|
||||||
<paper-icon-item @click=${this._entryClicked}>
|
<paper-icon-item @click=${this._entryClicked}>
|
||||||
@ -77,6 +84,16 @@ class HaConfigNavigation extends LitElement {
|
|||||||
|
|
||||||
private _entryClicked(ev) {
|
private _entryClicked(ev) {
|
||||||
ev.currentTarget.blur();
|
ev.currentTarget.blur();
|
||||||
|
if (
|
||||||
|
ev.currentTarget.parentElement.href.endsWith(
|
||||||
|
"#external-app-configuration"
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
ev.preventDefault();
|
||||||
|
this.hass.auth.external!.fireMessage({
|
||||||
|
type: "config_screen/show",
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static get styles(): CSSResultGroup {
|
static get styles(): CSSResultGroup {
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import {
|
import {
|
||||||
mdiAccount,
|
mdiAccount,
|
||||||
mdiBadgeAccountHorizontal,
|
mdiBadgeAccountHorizontal,
|
||||||
|
mdiCellphoneCog,
|
||||||
mdiCog,
|
mdiCog,
|
||||||
mdiDevices,
|
mdiDevices,
|
||||||
mdiHomeAssistant,
|
mdiHomeAssistant,
|
||||||
@ -57,22 +58,22 @@ export const configSections: { [name: string]: PageNavigation[] } = {
|
|||||||
{
|
{
|
||||||
path: "/config/automation",
|
path: "/config/automation",
|
||||||
name: "Automations & Scenes",
|
name: "Automations & Scenes",
|
||||||
description: "Automations, blueprints, scenes and scripts",
|
description: "Manage automations, scenes, scripts and helpers",
|
||||||
iconPath: mdiRobot,
|
iconPath: mdiRobot,
|
||||||
iconColor: "#518C43",
|
iconColor: "#518C43",
|
||||||
components: ["automation", "blueprint", "scene", "script"],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: "/config/helpers",
|
|
||||||
name: "Automation Helpers",
|
|
||||||
description: "Elements that help build automations",
|
|
||||||
iconPath: mdiTools,
|
|
||||||
iconColor: "#4D2EA4",
|
|
||||||
core: true,
|
core: true,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
path: "/config/blueprint",
|
||||||
|
name: "Blueprints",
|
||||||
|
description: "Manage blueprints",
|
||||||
|
iconPath: mdiPaletteSwatch,
|
||||||
|
iconColor: "#64B5F6",
|
||||||
|
component: "blueprint",
|
||||||
|
},
|
||||||
{
|
{
|
||||||
path: "/hassio",
|
path: "/hassio",
|
||||||
name: "Add-ons & Backups (Supervisor)",
|
name: "Add-ons, Backups & Supervisor",
|
||||||
description: "Create backups, check logs or reboot your system",
|
description: "Create backups, check logs or reboot your system",
|
||||||
iconPath: mdiHomeAssistant,
|
iconPath: mdiHomeAssistant,
|
||||||
iconColor: "#4084CD",
|
iconColor: "#4084CD",
|
||||||
@ -111,6 +112,13 @@ export const configSections: { [name: string]: PageNavigation[] } = {
|
|||||||
iconColor: "#E48629",
|
iconColor: "#E48629",
|
||||||
components: ["person", "zone", "users"],
|
components: ["person", "zone", "users"],
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
path: "#external-app-configuration",
|
||||||
|
name: "Companion App",
|
||||||
|
description: "Location and notifications",
|
||||||
|
iconPath: mdiCellphoneCog,
|
||||||
|
iconColor: "#8E24AA",
|
||||||
|
},
|
||||||
{
|
{
|
||||||
path: "/config/core",
|
path: "/config/core",
|
||||||
name: "Settings",
|
name: "Settings",
|
||||||
@ -155,13 +163,6 @@ export const configSections: { [name: string]: PageNavigation[] } = {
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
automations: [
|
automations: [
|
||||||
{
|
|
||||||
component: "blueprint",
|
|
||||||
path: "/config/blueprint",
|
|
||||||
translationKey: "ui.panel.config.blueprint.caption",
|
|
||||||
iconPath: mdiPaletteSwatch,
|
|
||||||
iconColor: "#518C43",
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
component: "automation",
|
component: "automation",
|
||||||
path: "/config/automation",
|
path: "/config/automation",
|
||||||
@ -183,8 +184,6 @@ export const configSections: { [name: string]: PageNavigation[] } = {
|
|||||||
iconPath: mdiScriptText,
|
iconPath: mdiScriptText,
|
||||||
iconColor: "#518C43",
|
iconColor: "#518C43",
|
||||||
},
|
},
|
||||||
],
|
|
||||||
helpers: [
|
|
||||||
{
|
{
|
||||||
component: "helpers",
|
component: "helpers",
|
||||||
path: "/config/helpers",
|
path: "/config/helpers",
|
||||||
@ -194,6 +193,15 @@ export const configSections: { [name: string]: PageNavigation[] } = {
|
|||||||
core: true,
|
core: true,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
blueprints: [
|
||||||
|
{
|
||||||
|
component: "blueprint",
|
||||||
|
path: "/config/blueprint",
|
||||||
|
translationKey: "ui.panel.config.blueprint.caption",
|
||||||
|
iconPath: mdiPaletteSwatch,
|
||||||
|
iconColor: "#518C43",
|
||||||
|
},
|
||||||
|
],
|
||||||
tags: [
|
tags: [
|
||||||
{
|
{
|
||||||
component: "tag",
|
component: "tag",
|
||||||
@ -447,9 +455,19 @@ class HaPanelConfig extends HassRouterPage {
|
|||||||
this.hass.loadBackendTranslation("title");
|
this.hass.loadBackendTranslation("title");
|
||||||
if (isComponentLoaded(this.hass, "cloud")) {
|
if (isComponentLoaded(this.hass, "cloud")) {
|
||||||
this._updateCloudStatus();
|
this._updateCloudStatus();
|
||||||
|
this.addEventListener("connection-status", (ev) => {
|
||||||
|
if (ev.detail === "connected") {
|
||||||
|
this._updateCloudStatus();
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
if (isComponentLoaded(this.hass, "hassio")) {
|
if (isComponentLoaded(this.hass, "hassio")) {
|
||||||
this._loadSupervisorUpdates();
|
this._loadSupervisorUpdates();
|
||||||
|
this.addEventListener("connection-status", (ev) => {
|
||||||
|
if (ev.detail === "connected") {
|
||||||
|
this._loadSupervisorUpdates();
|
||||||
|
}
|
||||||
|
});
|
||||||
} else {
|
} else {
|
||||||
this._supervisorUpdates = null;
|
this._supervisorUpdates = null;
|
||||||
}
|
}
|
||||||
|
@ -132,7 +132,7 @@ export class HaConfigHelpers extends LitElement {
|
|||||||
.narrow=${this.narrow}
|
.narrow=${this.narrow}
|
||||||
back-path="/config"
|
back-path="/config"
|
||||||
.route=${this.route}
|
.route=${this.route}
|
||||||
.tabs=${configSections.helpers}
|
.tabs=${configSections.automations}
|
||||||
.columns=${this._columns(this.narrow, this.hass.language)}
|
.columns=${this._columns(this.narrow, this.hass.language)}
|
||||||
.data=${this._getItems(this._stateItems)}
|
.data=${this._getItems(this._stateItems)}
|
||||||
@row-click=${this._openEditDialog}
|
@row-click=${this._openEditDialog}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit";
|
import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit";
|
||||||
import { property } from "lit/decorators";
|
import { property } from "lit/decorators";
|
||||||
import "../../../layouts/hass-tabs-subpage";
|
import "../../../layouts/hass-tabs-subpage";
|
||||||
|
import "../../../components/ha-logo-svg";
|
||||||
import { haStyle } from "../../../resources/styles";
|
import { haStyle } from "../../../resources/styles";
|
||||||
import { HomeAssistant, Route } from "../../../types";
|
import { HomeAssistant, Route } from "../../../types";
|
||||||
import { documentationUrl } from "../../../util/documentation-url";
|
import { documentationUrl } from "../../../util/documentation-url";
|
||||||
@ -40,13 +41,14 @@ class HaConfigInfo extends LitElement {
|
|||||||
href=${documentationUrl(this.hass, "")}
|
href=${documentationUrl(this.hass, "")}
|
||||||
target="_blank"
|
target="_blank"
|
||||||
rel="noreferrer"
|
rel="noreferrer"
|
||||||
><img
|
>
|
||||||
src="/static/icons/favicon-192x192.png"
|
<ha-logo-svg
|
||||||
height="192"
|
title=${this.hass.localize(
|
||||||
alt=${this.hass.localize(
|
|
||||||
"ui.panel.config.info.home_assistant_logo"
|
"ui.panel.config.info.home_assistant_logo"
|
||||||
)}
|
)}
|
||||||
/></a>
|
>
|
||||||
|
</ha-logo-svg>
|
||||||
|
</a>
|
||||||
<br />
|
<br />
|
||||||
<h2>Home Assistant ${hass.connection.haVersion}</h2>
|
<h2>Home Assistant ${hass.connection.haVersion}</h2>
|
||||||
<p>
|
<p>
|
||||||
@ -193,6 +195,11 @@ class HaConfigInfo extends LitElement {
|
|||||||
margin: 0 auto;
|
margin: 0 auto;
|
||||||
padding-bottom: 16px;
|
padding-bottom: 16px;
|
||||||
}
|
}
|
||||||
|
ha-logo-svg {
|
||||||
|
padding: 12px;
|
||||||
|
height: 180px;
|
||||||
|
width: 180px;
|
||||||
|
}
|
||||||
`,
|
`,
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
@ -45,6 +45,8 @@ export interface ZWaveJSAddNodeDevice {
|
|||||||
class DialogZWaveJSAddNode extends LitElement {
|
class DialogZWaveJSAddNode extends LitElement {
|
||||||
@property({ attribute: false }) public hass!: HomeAssistant;
|
@property({ attribute: false }) public hass!: HomeAssistant;
|
||||||
|
|
||||||
|
@state() private _params?: ZWaveJSAddNodeDialogParams;
|
||||||
|
|
||||||
@state() private _entryId?: string;
|
@state() private _entryId?: string;
|
||||||
|
|
||||||
@state() private _status?:
|
@state() private _status?:
|
||||||
@ -91,6 +93,7 @@ class DialogZWaveJSAddNode extends LitElement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public async showDialog(params: ZWaveJSAddNodeDialogParams): Promise<void> {
|
public async showDialog(params: ZWaveJSAddNodeDialogParams): Promise<void> {
|
||||||
|
this._params = params;
|
||||||
this._entryId = params.entry_id;
|
this._entryId = params.entry_id;
|
||||||
this._status = "loading";
|
this._status = "loading";
|
||||||
this._checkSmartStartSupport();
|
this._checkSmartStartSupport();
|
||||||
@ -562,6 +565,9 @@ class DialogZWaveJSAddNode extends LitElement {
|
|||||||
provisioningInfo
|
provisioningInfo
|
||||||
);
|
);
|
||||||
this._status = "provisioned";
|
this._status = "provisioned";
|
||||||
|
if (this._params?.addedCallback) {
|
||||||
|
this._params.addedCallback();
|
||||||
|
}
|
||||||
} catch (err: any) {
|
} catch (err: any) {
|
||||||
this._error = err.message;
|
this._error = err.message;
|
||||||
this._status = "failed";
|
this._status = "failed";
|
||||||
@ -693,6 +699,9 @@ class DialogZWaveJSAddNode extends LitElement {
|
|||||||
if (message.event === "interview completed") {
|
if (message.event === "interview completed") {
|
||||||
this._unsubscribe();
|
this._unsubscribe();
|
||||||
this._status = "finished";
|
this._status = "finished";
|
||||||
|
if (this._params?.addedCallback) {
|
||||||
|
this._params.addedCallback();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (message.event === "interview stage completed") {
|
if (message.event === "interview stage completed") {
|
||||||
|
@ -2,6 +2,7 @@ import { fireEvent } from "../../../../../common/dom/fire_event";
|
|||||||
|
|
||||||
export interface ZWaveJSAddNodeDialogParams {
|
export interface ZWaveJSAddNodeDialogParams {
|
||||||
entry_id: string;
|
entry_id: string;
|
||||||
|
addedCallback?: () => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const loadAddNodeDialog = () => import("./dialog-zwave_js-add-node");
|
export const loadAddNodeDialog = () => import("./dialog-zwave_js-add-node");
|
||||||
|
@ -411,6 +411,7 @@ class ZWaveJSConfigDashboard extends LitElement {
|
|||||||
private async _addNodeClicked() {
|
private async _addNodeClicked() {
|
||||||
showZWaveJSAddNodeDialog(this, {
|
showZWaveJSAddNodeDialog(this, {
|
||||||
entry_id: this.configEntryId!,
|
entry_id: this.configEntryId!,
|
||||||
|
addedCallback: () => this._fetchData(),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -327,6 +327,9 @@ class ZWaveJSNodeConfig extends SubscribeMixin(LitElement) {
|
|||||||
if (!("states" in item.metadata)) {
|
if (!("states" in item.metadata)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
if (Object.keys(item.metadata.states).length !== 2) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
if (!(0 in item.metadata.states) || !(1 in item.metadata.states)) {
|
if (!(0 in item.metadata.states) || !(1 in item.metadata.states)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { mdiDelete } from "@mdi/js";
|
import { mdiCheckCircle, mdiCloseCircleOutline, mdiDelete } from "@mdi/js";
|
||||||
import { html, LitElement } from "lit";
|
import { html, LitElement } from "lit";
|
||||||
import { customElement, property, state } from "lit/decorators";
|
import { customElement, property, state } from "lit/decorators";
|
||||||
import memoizeOne from "memoize-one";
|
import memoizeOne from "memoize-one";
|
||||||
@ -42,17 +42,42 @@ class ZWaveJSProvisioned extends LitElement {
|
|||||||
|
|
||||||
private _columns = memoizeOne(
|
private _columns = memoizeOne(
|
||||||
(narrow: boolean): DataTableColumnContainer => ({
|
(narrow: boolean): DataTableColumnContainer => ({
|
||||||
|
included: {
|
||||||
|
title: this.hass.localize(
|
||||||
|
"ui.panel.config.zwave_js.provisioned.included"
|
||||||
|
),
|
||||||
|
type: "icon",
|
||||||
|
width: "100px",
|
||||||
|
template: (_info, provisioningEntry: any) =>
|
||||||
|
provisioningEntry.additional_properties.nodeId
|
||||||
|
? html`
|
||||||
|
<ha-svg-icon
|
||||||
|
.label=${this.hass.localize(
|
||||||
|
"ui.panel.config.zwave_js.provisioned.included"
|
||||||
|
)}
|
||||||
|
.path=${mdiCheckCircle}
|
||||||
|
></ha-svg-icon>
|
||||||
|
`
|
||||||
|
: html`
|
||||||
|
<ha-svg-icon
|
||||||
|
.label=${this.hass.localize(
|
||||||
|
"ui.panel.config.zwave_js.provisioned.not_included"
|
||||||
|
)}
|
||||||
|
.path=${mdiCloseCircleOutline}
|
||||||
|
></ha-svg-icon>
|
||||||
|
`,
|
||||||
|
},
|
||||||
dsk: {
|
dsk: {
|
||||||
title: this.hass.localize("ui.panel.config.zwave_js.provisioned.dsk"),
|
title: this.hass.localize("ui.panel.config.zwave_js.provisioned.dsk"),
|
||||||
sortable: true,
|
sortable: true,
|
||||||
filterable: true,
|
filterable: true,
|
||||||
grows: true,
|
grows: true,
|
||||||
},
|
},
|
||||||
securityClasses: {
|
security_classes: {
|
||||||
title: this.hass.localize(
|
title: this.hass.localize(
|
||||||
"ui.panel.config.zwave_js.provisioned.security_classes"
|
"ui.panel.config.zwave_js.provisioned.security_classes"
|
||||||
),
|
),
|
||||||
width: "15%",
|
width: "30%",
|
||||||
hidden: narrow,
|
hidden: narrow,
|
||||||
filterable: true,
|
filterable: true,
|
||||||
sortable: true,
|
sortable: true,
|
||||||
@ -60,7 +85,7 @@ class ZWaveJSProvisioned extends LitElement {
|
|||||||
securityClasses
|
securityClasses
|
||||||
.map((secClass) =>
|
.map((secClass) =>
|
||||||
this.hass.localize(
|
this.hass.localize(
|
||||||
`ui.panel.config.zwave_js.security_classes.${SecurityClass[secClass]}`
|
`ui.panel.config.zwave_js.security_classes.${SecurityClass[secClass]}.title`
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
.join(", "),
|
.join(", "),
|
||||||
@ -70,6 +95,7 @@ class ZWaveJSProvisioned extends LitElement {
|
|||||||
"ui.panel.config.zwave_js.provisioned.unprovison"
|
"ui.panel.config.zwave_js.provisioned.unprovison"
|
||||||
),
|
),
|
||||||
type: "icon-button",
|
type: "icon-button",
|
||||||
|
width: "100px",
|
||||||
template: (_info, provisioningEntry: any) => html`
|
template: (_info, provisioningEntry: any) => html`
|
||||||
<ha-icon-button
|
<ha-icon-button
|
||||||
.label=${this.hass.localize(
|
.label=${this.hass.localize(
|
||||||
@ -97,6 +123,8 @@ class ZWaveJSProvisioned extends LitElement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private _unprovision = async (ev) => {
|
private _unprovision = async (ev) => {
|
||||||
|
const dsk = ev.currentTarget.provisioningEntry.dsk;
|
||||||
|
|
||||||
const confirm = await showConfirmationDialog(this, {
|
const confirm = await showConfirmationDialog(this, {
|
||||||
title: this.hass.localize(
|
title: this.hass.localize(
|
||||||
"ui.panel.config.zwave_js.provisioned.confirm_unprovision_title"
|
"ui.panel.config.zwave_js.provisioned.confirm_unprovision_title"
|
||||||
@ -113,11 +141,8 @@ class ZWaveJSProvisioned extends LitElement {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
await unprovisionZwaveSmartStartNode(
|
await unprovisionZwaveSmartStartNode(this.hass, this.configEntryId, dsk);
|
||||||
this.hass,
|
this._fetchData();
|
||||||
this.configEntryId,
|
|
||||||
ev.currentTarget.provisioningEntry.dsk
|
|
||||||
);
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -25,6 +25,7 @@ import { computeDomain } from "../../../common/entity/compute_domain";
|
|||||||
import { domainIcon } from "../../../common/entity/domain_icon";
|
import { domainIcon } from "../../../common/entity/domain_icon";
|
||||||
import { navigate } from "../../../common/navigate";
|
import { navigate } from "../../../common/navigate";
|
||||||
import { formatNumber } from "../../../common/number/format_number";
|
import { formatNumber } from "../../../common/number/format_number";
|
||||||
|
import { subscribeOne } from "../../../common/util/subscribe-one";
|
||||||
import "../../../components/entity/state-badge";
|
import "../../../components/entity/state-badge";
|
||||||
import "../../../components/ha-card";
|
import "../../../components/ha-card";
|
||||||
import "../../../components/ha-icon-button";
|
import "../../../components/ha-icon-button";
|
||||||
@ -83,8 +84,11 @@ export class HuiAreaCard
|
|||||||
return document.createElement("hui-area-card-editor");
|
return document.createElement("hui-area-card-editor");
|
||||||
}
|
}
|
||||||
|
|
||||||
public static getStubConfig(): AreaCardConfig {
|
public static async getStubConfig(
|
||||||
return { type: "area", area: "" };
|
hass: HomeAssistant
|
||||||
|
): Promise<AreaCardConfig> {
|
||||||
|
const areas = await subscribeOne(hass.connection, subscribeAreaRegistry);
|
||||||
|
return { type: "area", area: areas[0]?.area_id || "" };
|
||||||
}
|
}
|
||||||
|
|
||||||
@property({ attribute: false }) public hass!: HomeAssistant;
|
@property({ attribute: false }) public hass!: HomeAssistant;
|
||||||
@ -358,12 +362,12 @@ export class HuiAreaCard
|
|||||||
});
|
});
|
||||||
|
|
||||||
let cameraEntityId: string | undefined;
|
let cameraEntityId: string | undefined;
|
||||||
if ("camera" in entitiesByDomain) {
|
if (this._config.show_camera && "camera" in entitiesByDomain) {
|
||||||
cameraEntityId = entitiesByDomain.camera[0].entity_id;
|
cameraEntityId = entitiesByDomain.camera[0].entity_id;
|
||||||
}
|
}
|
||||||
|
|
||||||
return html`
|
return html`
|
||||||
<ha-card class=${area.picture ? "image" : ""}>
|
<ha-card class=${area.picture || cameraEntityId ? "image" : ""}>
|
||||||
${area.picture || cameraEntityId
|
${area.picture || cameraEntityId
|
||||||
? html`<hui-image
|
? html`<hui-image
|
||||||
.config=${this._config}
|
.config=${this._config}
|
||||||
|
@ -79,6 +79,7 @@ export interface EntitiesCardConfig extends LovelaceCardConfig {
|
|||||||
export interface AreaCardConfig extends LovelaceCardConfig {
|
export interface AreaCardConfig extends LovelaceCardConfig {
|
||||||
area: string;
|
area: string;
|
||||||
navigation_path?: string;
|
navigation_path?: string;
|
||||||
|
show_camera?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ButtonCardConfig extends LovelaceCardConfig {
|
export interface ButtonCardConfig extends LovelaceCardConfig {
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import "@polymer/paper-input/paper-input";
|
import "@polymer/paper-input/paper-input";
|
||||||
import { CSSResultGroup, html, LitElement, TemplateResult } from "lit";
|
import { CSSResultGroup, html, LitElement, TemplateResult } from "lit";
|
||||||
import { customElement, property, state } from "lit/decorators";
|
import { customElement, property, state } from "lit/decorators";
|
||||||
import { assert, assign, object, optional, string } from "superstruct";
|
import { assert, assign, boolean, object, optional, string } from "superstruct";
|
||||||
import { fireEvent } from "../../../../common/dom/fire_event";
|
import { fireEvent } from "../../../../common/dom/fire_event";
|
||||||
import "../../../../components/ha-area-picker";
|
import "../../../../components/ha-area-picker";
|
||||||
import { HomeAssistant } from "../../../../types";
|
import { HomeAssistant } from "../../../../types";
|
||||||
@ -11,6 +11,8 @@ import { LovelaceCardEditor } from "../../types";
|
|||||||
import { baseLovelaceCardConfig } from "../structs/base-card-struct";
|
import { baseLovelaceCardConfig } from "../structs/base-card-struct";
|
||||||
import { EditorTarget } from "../types";
|
import { EditorTarget } from "../types";
|
||||||
import { configElementStyle } from "./config-elements-style";
|
import { configElementStyle } from "./config-elements-style";
|
||||||
|
import "../../../../components/ha-formfield";
|
||||||
|
import { computeRTLDirection } from "../../../../common/util/compute_rtl";
|
||||||
|
|
||||||
const cardConfigStruct = assign(
|
const cardConfigStruct = assign(
|
||||||
baseLovelaceCardConfig,
|
baseLovelaceCardConfig,
|
||||||
@ -18,6 +20,7 @@ const cardConfigStruct = assign(
|
|||||||
area: optional(string()),
|
area: optional(string()),
|
||||||
navigation_path: optional(string()),
|
navigation_path: optional(string()),
|
||||||
theme: optional(string()),
|
theme: optional(string()),
|
||||||
|
show_camera: optional(boolean()),
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -47,6 +50,10 @@ export class HuiAreaCardEditor
|
|||||||
return this._config!.theme || "";
|
return this._config!.theme || "";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get _show_camera(): boolean {
|
||||||
|
return this._config!.show_camera || false;
|
||||||
|
}
|
||||||
|
|
||||||
protected render(): TemplateResult {
|
protected render(): TemplateResult {
|
||||||
if (!this.hass || !this._config) {
|
if (!this.hass || !this._config) {
|
||||||
return html``;
|
return html``;
|
||||||
@ -59,9 +66,23 @@ export class HuiAreaCardEditor
|
|||||||
.value=${this._area}
|
.value=${this._area}
|
||||||
.placeholder=${this._area}
|
.placeholder=${this._area}
|
||||||
.configValue=${"area"}
|
.configValue=${"area"}
|
||||||
.label=${this.hass.localize("ui.dialogs.entity_registry.editor.area")}
|
.label=${this.hass.localize(
|
||||||
|
"ui.panel.lovelace.editor.card.area.name"
|
||||||
|
)}
|
||||||
@value-changed=${this._valueChanged}
|
@value-changed=${this._valueChanged}
|
||||||
></ha-area-picker>
|
></ha-area-picker>
|
||||||
|
<ha-formfield
|
||||||
|
.label=${this.hass.localize(
|
||||||
|
"ui.panel.lovelace.editor.card.area.show_camera"
|
||||||
|
)}
|
||||||
|
.dir=${computeRTLDirection(this.hass)}
|
||||||
|
>
|
||||||
|
<ha-switch
|
||||||
|
.checked=${this._show_camera}
|
||||||
|
.configValue=${"show_camera"}
|
||||||
|
@change=${this._valueChanged}
|
||||||
|
></ha-switch>
|
||||||
|
</ha-formfield>
|
||||||
<paper-input
|
<paper-input
|
||||||
.label=${this.hass!.localize(
|
.label=${this.hass!.localize(
|
||||||
"ui.panel.lovelace.editor.action-editor.navigation_path"
|
"ui.panel.lovelace.editor.action-editor.navigation_path"
|
||||||
@ -86,7 +107,8 @@ export class HuiAreaCardEditor
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const target = ev.target! as EditorTarget;
|
const target = ev.target! as EditorTarget;
|
||||||
const value = ev.detail.value;
|
const value =
|
||||||
|
target.checked !== undefined ? target.checked : ev.detail.value;
|
||||||
|
|
||||||
if (this[`_${target.configValue}`] === value) {
|
if (this[`_${target.configValue}`] === value) {
|
||||||
return;
|
return;
|
||||||
|
@ -13,7 +13,7 @@ export const getCardStubConfig = async (
|
|||||||
const elClass = await getCardElementClass(type);
|
const elClass = await getCardElementClass(type);
|
||||||
|
|
||||||
if (elClass && elClass.getStubConfig) {
|
if (elClass && elClass.getStubConfig) {
|
||||||
const classStubConfig = elClass.getStubConfig(
|
const classStubConfig = await elClass.getStubConfig(
|
||||||
hass,
|
hass,
|
||||||
entities,
|
entities,
|
||||||
entitiesFallback
|
entitiesFallback
|
||||||
|
@ -13,7 +13,7 @@ export const getHeaderFooterStubConfig = async (
|
|||||||
const elClass = await getHeaderFooterElementClass(type);
|
const elClass = await getHeaderFooterElementClass(type);
|
||||||
|
|
||||||
if (elClass && elClass.getStubConfig) {
|
if (elClass && elClass.getStubConfig) {
|
||||||
const classStubConfig = elClass.getStubConfig(
|
const classStubConfig = await elClass.getStubConfig(
|
||||||
hass,
|
hass,
|
||||||
entities,
|
entities,
|
||||||
entitiesFallback
|
entitiesFallback
|
||||||
|
@ -91,6 +91,7 @@ export const coreCards: Card[] = [
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
type: "area",
|
type: "area",
|
||||||
|
showElement: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
type: "conditional",
|
type: "conditional",
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import { PaperInputElement } from "@polymer/paper-input/paper-input";
|
import { PaperInputElement } from "@polymer/paper-input/paper-input";
|
||||||
import { html, LitElement, PropertyValues, TemplateResult } from "lit";
|
import { html, LitElement, PropertyValues, TemplateResult } from "lit";
|
||||||
import { customElement, property, state } from "lit/decorators";
|
import { customElement, property, state } from "lit/decorators";
|
||||||
import { UNAVAILABLE } from "../../../data/entity";
|
import { UNAVAILABLE, UNAVAILABLE_STATES } from "../../../data/entity";
|
||||||
import { setValue } from "../../../data/input_text";
|
import { setValue } from "../../../data/input_text";
|
||||||
import { HomeAssistant } from "../../../types";
|
import { HomeAssistant } from "../../../types";
|
||||||
import { hasConfigOrEntityChanged } from "../common/has-changed";
|
import { hasConfigOrEntityChanged } from "../common/has-changed";
|
||||||
@ -67,6 +67,12 @@ class HuiInputTextEntityRow extends LitElement implements LovelaceRow {
|
|||||||
const element = this._inputEl;
|
const element = this._inputEl;
|
||||||
const stateObj = this.hass!.states[this._config!.entity];
|
const stateObj = this.hass!.states[this._config!.entity];
|
||||||
|
|
||||||
|
// Filter out invalid text states
|
||||||
|
if (element.value && UNAVAILABLE_STATES.includes(element.value)) {
|
||||||
|
element.value = stateObj.state;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (element.value !== stateObj.state) {
|
if (element.value !== stateObj.state) {
|
||||||
setValue(this.hass!, stateObj.entity_id, element.value!);
|
setValue(this.hass!, stateObj.entity_id, element.value!);
|
||||||
}
|
}
|
||||||
|
@ -95,6 +95,7 @@ export const derivedStyles = {
|
|||||||
"mdc-theme-text-disabled-on-light": "var(--disabled-text-color)",
|
"mdc-theme-text-disabled-on-light": "var(--disabled-text-color)",
|
||||||
"mdc-theme-text-primary-on-background": "var(--primary-text-color)",
|
"mdc-theme-text-primary-on-background": "var(--primary-text-color)",
|
||||||
"mdc-theme-text-secondary-on-background": "var(--secondary-text-color)",
|
"mdc-theme-text-secondary-on-background": "var(--secondary-text-color)",
|
||||||
|
"mdc-theme-text-hint-on-background": "var(--secondary-text-color)",
|
||||||
"mdc-theme-text-icon-on-background": "var(--secondary-text-color)",
|
"mdc-theme-text-icon-on-background": "var(--secondary-text-color)",
|
||||||
"mdc-theme-error": "var(--error-color)",
|
"mdc-theme-error": "var(--error-color)",
|
||||||
"app-header-text-color": "var(--text-primary-color)",
|
"app-header-text-color": "var(--text-primary-color)",
|
||||||
|
@ -878,8 +878,7 @@
|
|||||||
"key_missing": "Required key ''{key}'' is missing.",
|
"key_missing": "Required key ''{key}'' is missing.",
|
||||||
"key_not_expected": "Key ''{key}'' is not expected or not supported by the visual editor.",
|
"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}).",
|
"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_template_editor_support": "Templates not supported in visual editor"
|
||||||
"no_state_array_support": "Multiple state values not supported in visual editor"
|
|
||||||
},
|
},
|
||||||
"supervisor": {
|
"supervisor": {
|
||||||
"title": "Could not load the Supervisor panel!",
|
"title": "Could not load the Supervisor panel!",
|
||||||
@ -1514,7 +1513,7 @@
|
|||||||
"extra_fields": {
|
"extra_fields": {
|
||||||
"above": "Above",
|
"above": "Above",
|
||||||
"below": "Below",
|
"below": "Below",
|
||||||
"for": "Duration",
|
"for": "Duration (optional)",
|
||||||
"zone": "[%key:ui::panel::config::automation::editor::triggers::type::zone::label%]"
|
"zone": "[%key:ui::panel::config::automation::editor::triggers::type::zone::label%]"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -1537,9 +1536,9 @@
|
|||||||
"state": {
|
"state": {
|
||||||
"label": "State",
|
"label": "State",
|
||||||
"attribute": "Attribute (optional)",
|
"attribute": "Attribute (optional)",
|
||||||
"from": "From",
|
"from": "From (optional)",
|
||||||
"for": "For",
|
"for": "For (optional)",
|
||||||
"to": "To"
|
"to": "To (optional)"
|
||||||
},
|
},
|
||||||
"homeassistant": {
|
"homeassistant": {
|
||||||
"label": "Home Assistant",
|
"label": "Home Assistant",
|
||||||
@ -2897,6 +2896,8 @@
|
|||||||
"dsk": "DSK",
|
"dsk": "DSK",
|
||||||
"security_classes": "Security classes",
|
"security_classes": "Security classes",
|
||||||
"unprovison": "Unprovison",
|
"unprovison": "Unprovison",
|
||||||
|
"included": "Included",
|
||||||
|
"not_included": "Not Included",
|
||||||
"confirm_unprovision_title": "Are you sure you want to unprovision the device?",
|
"confirm_unprovision_title": "Are you sure you want to unprovision the device?",
|
||||||
"confirm_unprovision_text": "If you unprovision the device it will not be added to Home Assistant when it is powered on. If it is already added to Home Assistant, removing the provisioned device will not remove it from Home Assistant."
|
"confirm_unprovision_text": "If you unprovision the device it will not be added to Home Assistant when it is powered on. If it is already added to Home Assistant, removing the provisioned device will not remove it from Home Assistant."
|
||||||
},
|
},
|
||||||
@ -3251,11 +3252,12 @@
|
|||||||
"alarm-panel": {
|
"alarm-panel": {
|
||||||
"name": "Alarm Panel",
|
"name": "Alarm Panel",
|
||||||
"available_states": "Available States",
|
"available_states": "Available States",
|
||||||
"description": "The Alarm Panel card allows you to Arm and Disarm your alarm control panel integrations."
|
"description": "The Alarm Panel card allows you to arm and disarm your alarm control panel integrations."
|
||||||
},
|
},
|
||||||
"area": {
|
"area": {
|
||||||
"name": "Area",
|
"name": "Area",
|
||||||
"description": "The Area card automatically displays entities of a specific area."
|
"description": "The Area card automatically displays entities of a specific area.",
|
||||||
|
"show_camera": "Show camera feed instead of area picture"
|
||||||
},
|
},
|
||||||
"calendar": {
|
"calendar": {
|
||||||
"name": "Calendar",
|
"name": "Calendar",
|
||||||
|
Loading…
x
Reference in New Issue
Block a user