Compare commits

..

1 Commits

Author SHA1 Message Date
Paulus Schoutsen
94215dc50b dev tools dialog 2021-12-05 17:40:15 -08:00
32 changed files with 266 additions and 245 deletions

View File

@@ -48,6 +48,7 @@ import "../../../src/layouts/hass-subpage";
import "../../../src/layouts/hass-tabs-subpage";
import { SUPERVISOR_UPDATE_NAMES } from "../../../src/panels/config/dashboard/ha-config-updates";
import { HomeAssistant, Route } from "../../../src/types";
import { documentationUrl } from "../../../src/util/documentation-url";
import { addonArchIsSupported, extractChangelog } from "../util/addon";
declare global {
@@ -59,6 +60,7 @@ declare global {
type updateType = "os" | "supervisor" | "core" | "addon";
const changelogUrl = (
hass: HomeAssistant,
entry: updateType,
version: string
): string | undefined => {
@@ -66,19 +68,17 @@ const changelogUrl = (
return undefined;
}
if (entry === "core") {
return version.includes("dev")
return version?.includes("dev")
? "https://github.com/home-assistant/core/commits/dev"
: version.includes("b")
? "https://next.home-assistant.io/latest-release-notes/"
: "https://www.home-assistant.io/latest-release-notes/";
: documentationUrl(hass, "/latest-release-notes/");
}
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/releases/tag/${version}`;
}
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/releases/tag/${version}`;
}
@@ -120,7 +120,7 @@ class UpdateAvailableCard extends LitElement {
return html``;
}
const changelog = changelogUrl(this._updateType, this._version);
const changelog = changelogUrl(this.hass, this._updateType, this._version);
return html`
<ha-card

View File

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

View File

@@ -96,11 +96,7 @@ export class HaDateInput extends LitElement {
attr-for-value="value"
.i18n=${i18n}
>
<paper-input
.label=${this.label}
.disabled=${this.disabled}
no-label-float
>
<paper-input .label=${this.label} no-label-float>
<ha-svg-icon slot="suffix" .path=${mdiCalendar}></ha-svg-icon>
</paper-input>
</vaadin-date-picker-light>`;

View File

@@ -39,7 +39,6 @@ export class HaPictureUpload extends LitElement {
.uploading=${this._uploading}
.value=${this.value ? html`<img .src=${this.value} />` : ""}
@file-picked=${this._handleFilePicked}
@change=${this._handleFileCleared}
accept="image/png, image/jpeg, image/gif"
></ha-file-upload>
`;
@@ -54,10 +53,6 @@ export class HaPictureUpload extends LitElement {
}
}
private async _handleFileCleared() {
this.value = null;
}
private async _cropFile(file: File) {
if (!["image/png", "image/jpeg", "image/gif"].includes(file.type)) {
showAlertDialog(this, {

View File

@@ -208,11 +208,11 @@ export const enum NodeStatus {
export interface ZwaveJSProvisioningEntry {
/** The device specific key (DSK) in the form aaaaa-bbbbb-ccccc-ddddd-eeeee-fffff-11111-22222 */
dsk: string;
security_classes: SecurityClass[];
additional_properties: {
nodeId?: number;
[prop: string]: any;
};
securityClasses: SecurityClass[];
/**
* Additional properties to be stored in this provisioning entry, e.g. the device ID from a scanned QR code
*/
[prop: string]: any;
}
export interface RequestedGrant {
@@ -278,7 +278,7 @@ export const setZwaveDataCollectionPreference = (
export const fetchZwaveProvisioningEntries = (
hass: HomeAssistant,
entry_id: string
): Promise<ZwaveJSProvisioningEntry[]> =>
): Promise<any> =>
hass.callWS({
type: "zwave_js/get_provisioning_entries",
entry_id,

View File

@@ -0,0 +1,138 @@
import { mdiClose } from "@mdi/js";
import "@polymer/paper-tabs";
import {
css,
CSSResultGroup,
html,
LitElement,
PropertyValues,
TemplateResult,
} from "lit";
import { customElement, property, state, query } from "lit/decorators";
import { fireEvent } from "../../common/dom/fire_event";
import { haStyleDialog } from "../../resources/styles";
import type { HomeAssistant, Route } from "../../types";
import "../../components/ha-dialog";
import "../../components/ha-tabs";
import "../../components/ha-icon-button";
import "../../panels/developer-tools/developer-tools-router";
import type { HaDialog } from "../../components/ha-dialog";
import "@material/mwc-button/mwc-button";
@customElement("ha-developer-tools-dialog")
export class HaDeveloperToolsDialog extends LitElement {
@property({ attribute: false }) public hass!: HomeAssistant;
@state() private _opened = false;
@state() private _route: Route = {
prefix: "/developer-tools",
path: "/state",
};
@query("ha-dialog", true) private _dialog!: HaDialog;
public async showDialog(): Promise<void> {
this._opened = true;
}
public async closeDialog(): Promise<void> {
this._opened = false;
fireEvent(this, "dialog-closed", { dialog: this.localName });
}
protected render(): TemplateResult {
if (!this._opened) {
return html``;
}
return html`
<ha-dialog open @closed=${this.closeDialog}>
<div class="header">
<ha-tabs
scrollable
attr-for-selected="page-name"
.selected=${this._route.path.substr(1)}
@iron-activate=${this.handlePageSelected}
>
<paper-tab page-name="state">
${this.hass.localize(
"ui.panel.developer-tools.tabs.states.title"
)}
</paper-tab>
<paper-tab page-name="service">
${this.hass.localize(
"ui.panel.developer-tools.tabs.services.title"
)}
</paper-tab>
<paper-tab page-name="template">
${this.hass.localize(
"ui.panel.developer-tools.tabs.templates.title"
)}
</paper-tab>
<paper-tab page-name="event">
${this.hass.localize(
"ui.panel.developer-tools.tabs.events.title"
)}
</paper-tab>
<paper-tab page-name="statistics">
${this.hass.localize(
"ui.panel.developer-tools.tabs.statistics.title"
)}
</paper-tab>
</ha-tabs>
<ha-icon-button
.path=${mdiClose}
@click=${this.closeDialog}
></ha-icon-button>
</div>
<developer-tools-router
.route=${this._route}
.narrow=${document.body.clientWidth < 600}
.hass=${this.hass}
></developer-tools-router>
</ha-dialog>
`;
}
protected firstUpdated(changedProps: PropertyValues) {
super.updated(changedProps);
this.hass.loadBackendTranslation("title");
this.hass.loadFragmentTranslation("developer-tools");
}
private handlePageSelected(ev) {
const newPage = ev.detail.item.getAttribute("page-name");
if (newPage !== this._route.path.substr(1)) {
this._route = {
prefix: "/developer-tools",
path: `/${newPage}`,
};
} else {
// scrollTo(0, 0);
}
}
static get styles(): CSSResultGroup {
return [
haStyleDialog,
css`
ha-dialog {
--mdc-dialog-min-width: 100vw;
--mdc-dialog-min-height: 100vh;
}
.header {
display: flex;
}
ha-tabs {
flex: 1;
}
`,
];
}
}
declare global {
interface HTMLElementTagNameMap {
"ha-developer-tools-dialog": HaDeveloperToolsDialog;
}
}

View File

@@ -0,0 +1,12 @@
import { fireEvent } from "../../common/dom/fire_event";
export const loadDeveloperToolDialog = () =>
import("./ha-developer-tools-dialog");
export const showDeveloperToolDialog = (element: HTMLElement): void => {
fireEvent(element, "show-dialog", {
dialogTag: "ha-developer-tools-dialog",
dialogImport: loadDeveloperToolDialog,
dialogParams: {},
});
};

View File

@@ -1,27 +1,17 @@
import "@polymer/paper-input/paper-input";
import { html, LitElement, PropertyValues } from "lit";
import { customElement, property } from "lit/decorators";
import { assert, literal, object, optional, string, union } from "superstruct";
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-picker";
import "../../../../../components/ha-duration-input";
import { StateCondition } from "../../../../../data/automation";
import { HomeAssistant } from "../../../../../types";
import { forDictStruct } from "../../structs";
import {
ConditionElement,
handleChangeEvent,
} from "../ha-automation-condition-row";
const stateConditionStruct = object({
condition: literal("state"),
entity_id: string(),
attribute: optional(string()),
state: string(),
for: optional(union([string(), forDictStruct])),
});
import "../../../../../components/ha-duration-input";
import { fireEvent } from "../../../../../common/dom/fire_event";
@customElement("ha-automation-condition-state")
export class HaStateCondition extends LitElement implements ConditionElement {
@@ -33,14 +23,19 @@ export class HaStateCondition extends LitElement implements ConditionElement {
return { entity_id: "", state: "" };
}
public shouldUpdate(changedProperties: PropertyValues) {
if (changedProperties.has("condition")) {
try {
assert(this.condition, stateConditionStruct);
} catch (e: any) {
fireEvent(this, "ui-mode-not-available", e);
return false;
}
public willUpdate(changedProperties: PropertyValues): boolean {
if (
changedProperties.has("condition") &&
Array.isArray(this.condition?.state)
) {
fireEvent(
this,
"ui-mode-not-available",
Error(this.hass.localize("ui.errors.config.no_state_array_support"))
);
// We have to stop the update if state is an array.
// Otherwise the state will be changed to a comma-separated string by the input element.
return false;
}
return true;
}

View File

@@ -1,8 +0,0 @@
import { object, optional, number } from "superstruct";
export const forDictStruct = object({
days: optional(number()),
hours: optional(number()),
minutes: optional(number()),
seconds: optional(number()),
});

View File

@@ -68,7 +68,7 @@ export const handleChangeEvent = (element: TriggerElement, ev: CustomEvent) => {
}
let newTrigger: Trigger;
if (newVal === undefined || newVal === "") {
if (!newVal) {
newTrigger = { ...element.trigger };
delete newTrigger[name];
} else {

View File

@@ -1,30 +1,19 @@
import "@polymer/paper-input/paper-input";
import { html, LitElement, PropertyValues } from "lit";
import { customElement, property } from "lit/decorators";
import { assert, literal, object, optional, string, union } from "superstruct";
import { createDurationData } from "../../../../../common/datetime/create_duration_data";
import { fireEvent } from "../../../../../common/dom/fire_event";
import { hasTemplate } from "../../../../../common/string/has-template";
import "../../../../../components/entity/ha-entity-attribute-picker";
import "../../../../../components/entity/ha-entity-picker";
import "../../../../../components/ha-duration-input";
import { StateTrigger } from "../../../../../data/automation";
import { HomeAssistant } from "../../../../../types";
import { forDictStruct } from "../../structs";
import "../../../../../components/ha-duration-input";
import {
handleChangeEvent,
TriggerElement,
} 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")
export class HaStateTrigger extends LitElement implements TriggerElement {
@property({ attribute: false }) public hass!: HomeAssistant;
@@ -35,9 +24,9 @@ export class HaStateTrigger extends LitElement implements TriggerElement {
return { entity_id: "" };
}
public shouldUpdate(changedProperties: PropertyValues) {
public willUpdate(changedProperties: PropertyValues) {
if (!changedProperties.has("trigger")) {
return true;
return;
}
// Check for templates in trigger. If found, revert to YAML mode.
if (this.trigger && hasTemplate(this.trigger)) {
@@ -46,15 +35,7 @@ export class HaStateTrigger extends LitElement implements TriggerElement {
"ui-mode-not-available",
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() {

View File

@@ -224,7 +224,7 @@ class HaBlueprintOverview extends LitElement {
.narrow=${this.narrow}
back-path="/config"
.route=${this.route}
.tabs=${configSections.blueprints}
.tabs=${configSections.automations}
.columns=${this._columns(this.narrow, this.hass.language)}
.data=${this._processedBlueprints(this.blueprints)}
id="entity_id"

View File

@@ -1,4 +1,4 @@
import { mdiCloudLock } from "@mdi/js";
import { mdiCellphoneCog, mdiCloudLock } from "@mdi/js";
import "@polymer/app-layout/app-header/app-header";
import "@polymer/app-layout/app-toolbar/app-toolbar";
import {
@@ -110,10 +110,29 @@ class HaConfigDashboard extends LitElement {
></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
.hass=${this.hass}
.narrow=${this.narrow}
.externalConfig=${this._externalConfig}
.showAdvanced=${this.showAdvanced}
.pages=${configSections.dashboard}
></ha-config-navigation>
@@ -123,6 +142,13 @@ class HaConfigDashboard extends LitElement {
`;
}
private _handleExternalAppConfiguration(ev: Event) {
ev.preventDefault();
this.hass.auth.external!.fireMessage({
type: "config_screen/show",
});
}
static get styles(): CSSResultGroup {
return [
haStyle,

View File

@@ -6,7 +6,6 @@ import { canShowPage } from "../../../common/config/can_show_page";
import "../../../components/ha-card";
import "../../../components/ha-icon-next";
import { CloudStatus, CloudStatusLoggedIn } from "../../../data/cloud";
import { ExternalConfig } from "../../../external_app/external_config";
import { PageNavigation } from "../../../layouts/hass-tabs-subpage";
import { HomeAssistant } from "../../../types";
@@ -20,16 +19,10 @@ class HaConfigNavigation extends LitElement {
@property() public pages!: PageNavigation[];
@property() public externalConfig?: ExternalConfig;
protected render(): TemplateResult {
return html`
${this.pages.map((page) =>
(
page.path === "#external-app-configuration"
? this.externalConfig?.hasSettingsScreen
: canShowPage(this.hass, page)
)
canShowPage(this.hass, page)
? html`
<a href=${page.path} aria-role="option" tabindex="-1">
<paper-icon-item @click=${this._entryClicked}>
@@ -84,16 +77,6 @@ class HaConfigNavigation extends LitElement {
private _entryClicked(ev) {
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 {

View File

@@ -1,7 +1,6 @@
import {
mdiAccount,
mdiBadgeAccountHorizontal,
mdiCellphoneCog,
mdiCog,
mdiDevices,
mdiHomeAssistant,
@@ -58,22 +57,22 @@ export const configSections: { [name: string]: PageNavigation[] } = {
{
path: "/config/automation",
name: "Automations & Scenes",
description: "Manage automations, scenes, scripts and helpers",
description: "Automations, blueprints, scenes and scripts",
iconPath: mdiRobot,
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,
},
{
path: "/config/blueprint",
name: "Blueprints",
description: "Manage blueprints",
iconPath: mdiPaletteSwatch,
iconColor: "#64B5F6",
component: "blueprint",
},
{
path: "/hassio",
name: "Add-ons, Backups & Supervisor",
name: "Add-ons & Backups (Supervisor)",
description: "Create backups, check logs or reboot your system",
iconPath: mdiHomeAssistant,
iconColor: "#4084CD",
@@ -112,13 +111,6 @@ export const configSections: { [name: string]: PageNavigation[] } = {
iconColor: "#E48629",
components: ["person", "zone", "users"],
},
{
path: "#external-app-configuration",
name: "Companion App",
description: "Location and notifications",
iconPath: mdiCellphoneCog,
iconColor: "#8E24AA",
},
{
path: "/config/core",
name: "Settings",
@@ -163,6 +155,13 @@ export const configSections: { [name: string]: PageNavigation[] } = {
},
],
automations: [
{
component: "blueprint",
path: "/config/blueprint",
translationKey: "ui.panel.config.blueprint.caption",
iconPath: mdiPaletteSwatch,
iconColor: "#518C43",
},
{
component: "automation",
path: "/config/automation",
@@ -184,6 +183,8 @@ export const configSections: { [name: string]: PageNavigation[] } = {
iconPath: mdiScriptText,
iconColor: "#518C43",
},
],
helpers: [
{
component: "helpers",
path: "/config/helpers",
@@ -193,15 +194,6 @@ export const configSections: { [name: string]: PageNavigation[] } = {
core: true,
},
],
blueprints: [
{
component: "blueprint",
path: "/config/blueprint",
translationKey: "ui.panel.config.blueprint.caption",
iconPath: mdiPaletteSwatch,
iconColor: "#518C43",
},
],
tags: [
{
component: "tag",
@@ -455,19 +447,9 @@ class HaPanelConfig extends HassRouterPage {
this.hass.loadBackendTranslation("title");
if (isComponentLoaded(this.hass, "cloud")) {
this._updateCloudStatus();
this.addEventListener("connection-status", (ev) => {
if (ev.detail === "connected") {
this._updateCloudStatus();
}
});
}
if (isComponentLoaded(this.hass, "hassio")) {
this._loadSupervisorUpdates();
this.addEventListener("connection-status", (ev) => {
if (ev.detail === "connected") {
this._loadSupervisorUpdates();
}
});
} else {
this._supervisorUpdates = null;
}

View File

@@ -132,7 +132,7 @@ export class HaConfigHelpers extends LitElement {
.narrow=${this.narrow}
back-path="/config"
.route=${this.route}
.tabs=${configSections.automations}
.tabs=${configSections.helpers}
.columns=${this._columns(this.narrow, this.hass.language)}
.data=${this._getItems(this._stateItems)}
@row-click=${this._openEditDialog}

View File

@@ -1,7 +1,6 @@
import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit";
import { property } from "lit/decorators";
import "../../../layouts/hass-tabs-subpage";
import "../../../components/ha-logo-svg";
import { haStyle } from "../../../resources/styles";
import { HomeAssistant, Route } from "../../../types";
import { documentationUrl } from "../../../util/documentation-url";
@@ -41,14 +40,13 @@ class HaConfigInfo extends LitElement {
href=${documentationUrl(this.hass, "")}
target="_blank"
rel="noreferrer"
>
<ha-logo-svg
title=${this.hass.localize(
><img
src="/static/icons/favicon-192x192.png"
height="192"
alt=${this.hass.localize(
"ui.panel.config.info.home_assistant_logo"
)}
>
</ha-logo-svg>
</a>
/></a>
<br />
<h2>Home Assistant ${hass.connection.haVersion}</h2>
<p>
@@ -195,11 +193,6 @@ class HaConfigInfo extends LitElement {
margin: 0 auto;
padding-bottom: 16px;
}
ha-logo-svg {
padding: 12px;
height: 180px;
width: 180px;
}
`,
];
}

View File

@@ -45,8 +45,6 @@ export interface ZWaveJSAddNodeDevice {
class DialogZWaveJSAddNode extends LitElement {
@property({ attribute: false }) public hass!: HomeAssistant;
@state() private _params?: ZWaveJSAddNodeDialogParams;
@state() private _entryId?: string;
@state() private _status?:
@@ -93,7 +91,6 @@ class DialogZWaveJSAddNode extends LitElement {
}
public async showDialog(params: ZWaveJSAddNodeDialogParams): Promise<void> {
this._params = params;
this._entryId = params.entry_id;
this._status = "loading";
this._checkSmartStartSupport();
@@ -565,9 +562,6 @@ class DialogZWaveJSAddNode extends LitElement {
provisioningInfo
);
this._status = "provisioned";
if (this._params?.addedCallback) {
this._params.addedCallback();
}
} catch (err: any) {
this._error = err.message;
this._status = "failed";
@@ -699,9 +693,6 @@ class DialogZWaveJSAddNode extends LitElement {
if (message.event === "interview completed") {
this._unsubscribe();
this._status = "finished";
if (this._params?.addedCallback) {
this._params.addedCallback();
}
}
if (message.event === "interview stage completed") {

View File

@@ -2,7 +2,6 @@ import { fireEvent } from "../../../../../common/dom/fire_event";
export interface ZWaveJSAddNodeDialogParams {
entry_id: string;
addedCallback?: () => void;
}
export const loadAddNodeDialog = () => import("./dialog-zwave_js-add-node");

View File

@@ -411,7 +411,6 @@ class ZWaveJSConfigDashboard extends LitElement {
private async _addNodeClicked() {
showZWaveJSAddNodeDialog(this, {
entry_id: this.configEntryId!,
addedCallback: () => this._fetchData(),
});
}

View File

@@ -327,9 +327,6 @@ class ZWaveJSNodeConfig extends SubscribeMixin(LitElement) {
if (!("states" in item.metadata)) {
return false;
}
if (Object.keys(item.metadata.states).length !== 2) {
return false;
}
if (!(0 in item.metadata.states) || !(1 in item.metadata.states)) {
return false;
}

View File

@@ -1,4 +1,4 @@
import { mdiCheckCircle, mdiCloseCircleOutline, mdiDelete } from "@mdi/js";
import { mdiDelete } from "@mdi/js";
import { html, LitElement } from "lit";
import { customElement, property, state } from "lit/decorators";
import memoizeOne from "memoize-one";
@@ -42,42 +42,17 @@ class ZWaveJSProvisioned extends LitElement {
private _columns = memoizeOne(
(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: {
title: this.hass.localize("ui.panel.config.zwave_js.provisioned.dsk"),
sortable: true,
filterable: true,
grows: true,
},
security_classes: {
securityClasses: {
title: this.hass.localize(
"ui.panel.config.zwave_js.provisioned.security_classes"
),
width: "30%",
width: "15%",
hidden: narrow,
filterable: true,
sortable: true,
@@ -85,7 +60,7 @@ class ZWaveJSProvisioned extends LitElement {
securityClasses
.map((secClass) =>
this.hass.localize(
`ui.panel.config.zwave_js.security_classes.${SecurityClass[secClass]}.title`
`ui.panel.config.zwave_js.security_classes.${SecurityClass[secClass]}`
)
)
.join(", "),
@@ -95,7 +70,6 @@ class ZWaveJSProvisioned extends LitElement {
"ui.panel.config.zwave_js.provisioned.unprovison"
),
type: "icon-button",
width: "100px",
template: (_info, provisioningEntry: any) => html`
<ha-icon-button
.label=${this.hass.localize(
@@ -123,8 +97,6 @@ class ZWaveJSProvisioned extends LitElement {
}
private _unprovision = async (ev) => {
const dsk = ev.currentTarget.provisioningEntry.dsk;
const confirm = await showConfirmationDialog(this, {
title: this.hass.localize(
"ui.panel.config.zwave_js.provisioned.confirm_unprovision_title"
@@ -141,8 +113,11 @@ class ZWaveJSProvisioned extends LitElement {
return;
}
await unprovisionZwaveSmartStartNode(this.hass, this.configEntryId, dsk);
this._fetchData();
await unprovisionZwaveSmartStartNode(
this.hass,
this.configEntryId,
ev.currentTarget.provisioningEntry.dsk
);
};
}

View File

@@ -25,7 +25,6 @@ import { computeDomain } from "../../../common/entity/compute_domain";
import { domainIcon } from "../../../common/entity/domain_icon";
import { navigate } from "../../../common/navigate";
import { formatNumber } from "../../../common/number/format_number";
import { subscribeOne } from "../../../common/util/subscribe-one";
import "../../../components/entity/state-badge";
import "../../../components/ha-card";
import "../../../components/ha-icon-button";
@@ -84,11 +83,8 @@ export class HuiAreaCard
return document.createElement("hui-area-card-editor");
}
public static async getStubConfig(
hass: HomeAssistant
): Promise<AreaCardConfig> {
const areas = await subscribeOne(hass.connection, subscribeAreaRegistry);
return { type: "area", area: areas[0]?.area_id || "" };
public static getStubConfig(): AreaCardConfig {
return { type: "area", area: "" };
}
@property({ attribute: false }) public hass!: HomeAssistant;
@@ -362,12 +358,12 @@ export class HuiAreaCard
});
let cameraEntityId: string | undefined;
if (this._config.show_camera && "camera" in entitiesByDomain) {
if ("camera" in entitiesByDomain) {
cameraEntityId = entitiesByDomain.camera[0].entity_id;
}
return html`
<ha-card class=${area.picture || cameraEntityId ? "image" : ""}>
<ha-card class=${area.picture ? "image" : ""}>
${area.picture || cameraEntityId
? html`<hui-image
.config=${this._config}

View File

@@ -79,7 +79,6 @@ export interface EntitiesCardConfig extends LovelaceCardConfig {
export interface AreaCardConfig extends LovelaceCardConfig {
area: string;
navigation_path?: string;
show_camera?: boolean;
}
export interface ButtonCardConfig extends LovelaceCardConfig {

View File

@@ -1,7 +1,7 @@
import "@polymer/paper-input/paper-input";
import { CSSResultGroup, html, LitElement, TemplateResult } from "lit";
import { customElement, property, state } from "lit/decorators";
import { assert, assign, boolean, object, optional, string } from "superstruct";
import { assert, assign, object, optional, string } from "superstruct";
import { fireEvent } from "../../../../common/dom/fire_event";
import "../../../../components/ha-area-picker";
import { HomeAssistant } from "../../../../types";
@@ -11,8 +11,6 @@ import { LovelaceCardEditor } from "../../types";
import { baseLovelaceCardConfig } from "../structs/base-card-struct";
import { EditorTarget } from "../types";
import { configElementStyle } from "./config-elements-style";
import "../../../../components/ha-formfield";
import { computeRTLDirection } from "../../../../common/util/compute_rtl";
const cardConfigStruct = assign(
baseLovelaceCardConfig,
@@ -20,7 +18,6 @@ const cardConfigStruct = assign(
area: optional(string()),
navigation_path: optional(string()),
theme: optional(string()),
show_camera: optional(boolean()),
})
);
@@ -50,10 +47,6 @@ export class HuiAreaCardEditor
return this._config!.theme || "";
}
get _show_camera(): boolean {
return this._config!.show_camera || false;
}
protected render(): TemplateResult {
if (!this.hass || !this._config) {
return html``;
@@ -71,18 +64,6 @@ export class HuiAreaCardEditor
)}
@value-changed=${this._valueChanged}
></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
.label=${this.hass!.localize(
"ui.panel.lovelace.editor.action-editor.navigation_path"
@@ -107,8 +88,7 @@ export class HuiAreaCardEditor
return;
}
const target = ev.target! as EditorTarget;
const value =
target.checked !== undefined ? target.checked : ev.detail.value;
const value = ev.detail.value;
if (this[`_${target.configValue}`] === value) {
return;

View File

@@ -13,7 +13,7 @@ export const getCardStubConfig = async (
const elClass = await getCardElementClass(type);
if (elClass && elClass.getStubConfig) {
const classStubConfig = await elClass.getStubConfig(
const classStubConfig = elClass.getStubConfig(
hass,
entities,
entitiesFallback

View File

@@ -13,7 +13,7 @@ export const getHeaderFooterStubConfig = async (
const elClass = await getHeaderFooterElementClass(type);
if (elClass && elClass.getStubConfig) {
const classStubConfig = await elClass.getStubConfig(
const classStubConfig = elClass.getStubConfig(
hass,
entities,
entitiesFallback

View File

@@ -91,7 +91,6 @@ export const coreCards: Card[] = [
},
{
type: "area",
showElement: true,
},
{
type: "conditional",

View File

@@ -1,7 +1,7 @@
import { PaperInputElement } from "@polymer/paper-input/paper-input";
import { html, LitElement, PropertyValues, TemplateResult } from "lit";
import { customElement, property, state } from "lit/decorators";
import { UNAVAILABLE, UNAVAILABLE_STATES } from "../../../data/entity";
import { UNAVAILABLE } from "../../../data/entity";
import { setValue } from "../../../data/input_text";
import { HomeAssistant } from "../../../types";
import { hasConfigOrEntityChanged } from "../common/has-changed";
@@ -67,12 +67,6 @@ class HuiInputTextEntityRow extends LitElement implements LovelaceRow {
const element = this._inputEl;
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) {
setValue(this.hass!, stateObj.entity_id, element.value!);
}

View File

@@ -95,7 +95,6 @@ export const derivedStyles = {
"mdc-theme-text-disabled-on-light": "var(--disabled-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-hint-on-background": "var(--secondary-text-color)",
"mdc-theme-text-icon-on-background": "var(--secondary-text-color)",
"mdc-theme-error": "var(--error-color)",
"app-header-text-color": "var(--text-primary-color)",

View File

@@ -1,5 +1,6 @@
import type { PropertyValues } from "lit";
import tinykeys from "tinykeys";
import { showDeveloperToolDialog } from "../dialogs/developert-tools/show-dialog-developer-tools";
import {
QuickBarParams,
showQuickBar,
@@ -32,6 +33,7 @@ export default <T extends Constructor<HassElement>>(superClass: T) =>
tinykeys(window, {
e: (ev) => this._showQuickBar(ev),
c: (ev) => this._showQuickBar(ev, true),
d: () => showDeveloperToolDialog(this),
});
}

View File

@@ -878,7 +878,8 @@
"key_missing": "Required key ''{key}'' is missing.",
"key_not_expected": "Key ''{key}'' is not expected or not supported by the visual editor.",
"key_wrong_type": "The provided value for ''{key}'' is not supported by the visual editor. We support ({type_correct}) but received ({type_wrong}).",
"no_template_editor_support": "Templates not supported in visual editor"
"no_template_editor_support": "Templates not supported in visual editor",
"no_state_array_support": "Multiple state values not supported in visual editor"
},
"supervisor": {
"title": "Could not load the Supervisor panel!",
@@ -1513,7 +1514,7 @@
"extra_fields": {
"above": "Above",
"below": "Below",
"for": "Duration (optional)",
"for": "Duration",
"zone": "[%key:ui::panel::config::automation::editor::triggers::type::zone::label%]"
}
},
@@ -1536,9 +1537,9 @@
"state": {
"label": "State",
"attribute": "Attribute (optional)",
"from": "From (optional)",
"for": "For (optional)",
"to": "To (optional)"
"from": "From",
"for": "For",
"to": "To"
},
"homeassistant": {
"label": "Home Assistant",
@@ -2896,8 +2897,6 @@
"dsk": "DSK",
"security_classes": "Security classes",
"unprovison": "Unprovison",
"included": "Included",
"not_included": "Not Included",
"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."
},
@@ -3256,8 +3255,7 @@
},
"area": {
"name": "Area",
"description": "The Area card automatically displays entities of a specific area.",
"show_camera": "Show camera feed instead of area picture"
"description": "The Area card automatically displays entities of a specific area."
},
"calendar": {
"name": "Calendar",