mirror of
https://github.com/home-assistant/frontend.git
synced 2025-11-25 02:37:20 +00:00
Compare commits
34 Commits
fix-button
...
editor-hig
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
aecbfeaaa0 | ||
|
|
498732566e | ||
|
|
b22c51bc2c | ||
|
|
5bc2fd059c | ||
|
|
0183e32267 | ||
|
|
588fd87654 | ||
|
|
e2944b098d | ||
|
|
cbb962f084 | ||
|
|
93f4ae1bea | ||
|
|
6797e17fc8 | ||
|
|
6e58cd5d12 | ||
|
|
a72fd19b73 | ||
|
|
41c61a2895 | ||
|
|
f35af9ed98 | ||
|
|
abf7cb7a74 | ||
|
|
6ec2e32241 | ||
|
|
b7cdd9a22f | ||
|
|
6278eefc5d | ||
|
|
73cf0b54c9 | ||
|
|
00dcecabb7 | ||
|
|
c9df93bc54 | ||
|
|
3550a8c263 | ||
|
|
c0d30c56d6 | ||
|
|
10813d06b6 | ||
|
|
d65e45ecfd | ||
|
|
1b158d8310 | ||
|
|
9d2fcec458 | ||
|
|
60cd6c65f0 | ||
|
|
a39af9c307 | ||
|
|
02af4c2156 | ||
|
|
d02cd122a9 | ||
|
|
8e962fdecb | ||
|
|
1f65193a97 | ||
|
|
24484d0e74 |
2
.vscode/tasks.json
vendored
2
.vscode/tasks.json
vendored
@@ -181,7 +181,7 @@
|
||||
{
|
||||
"label": "Run HA Core for Supervisor in devcontainer",
|
||||
"type": "shell",
|
||||
"command": "HASSIO=${input:supervisorHost} HASSIO_TOKEN=${input:supervisorToken} script/core",
|
||||
"command": "SUPERVISOR=${input:supervisorHost} SUPERVISOR_TOKEN=${input:supervisorToken} script/core",
|
||||
"isBackground": true,
|
||||
"group": {
|
||||
"kind": "build",
|
||||
|
||||
9
cast/public/_redirects
Normal file
9
cast/public/_redirects
Normal file
@@ -0,0 +1,9 @@
|
||||
# These redirects are handled by Netlify
|
||||
#
|
||||
|
||||
# Some custom cards are not prefixing the instance URL when fetching data
|
||||
# and can end up fetching the data from the Cast domain instead of HA.
|
||||
# This will make sure that some common ones are replaced with a placeholder.
|
||||
/api/camera_proxy/* /images/google-nest-hub.png
|
||||
/api/camera_proxy_stream/* /images/google-nest-hub.png
|
||||
/api/media_player_proxy/* /images/google-nest-hub.png
|
||||
@@ -89,8 +89,8 @@
|
||||
"@polymer/paper-tooltip": "^3.0.1",
|
||||
"@polymer/polymer": "3.4.1",
|
||||
"@thomasloven/round-slider": "0.5.4",
|
||||
"@vaadin/combo-box": "^22.0.4",
|
||||
"@vaadin/vaadin-themable-mixin": "^22.0.4",
|
||||
"@vaadin/combo-box": "^23.0.10",
|
||||
"@vaadin/vaadin-themable-mixin": "^23.0.10",
|
||||
"@vibrant/color": "^3.2.1-alpha.1",
|
||||
"@vibrant/core": "^3.2.1-alpha.1",
|
||||
"@vibrant/quantizer-mmcq": "^3.2.1-alpha.1",
|
||||
@@ -108,7 +108,7 @@
|
||||
"fuse.js": "^6.0.0",
|
||||
"google-timezones-json": "^1.0.2",
|
||||
"hls.js": "^1.1.5",
|
||||
"home-assistant-js-websocket": "^7.0.3",
|
||||
"home-assistant-js-websocket": "^7.1.0",
|
||||
"idb-keyval": "^5.1.3",
|
||||
"intl-messageformat": "^9.9.1",
|
||||
"js-yaml": "^4.1.0",
|
||||
|
||||
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
||||
|
||||
[project]
|
||||
name = "home-assistant-frontend"
|
||||
version = "20220525.0"
|
||||
version = "20220526.0"
|
||||
license = {text = "Apache-2.0"}
|
||||
description = "The Home Assistant frontend"
|
||||
readme = "README.md"
|
||||
|
||||
@@ -31,6 +31,7 @@ const rowRenderer: ComboBoxLitRenderer<HassEntityWithCachedName> = (item) =>
|
||||
<span>${item.friendly_name}</span>
|
||||
<span slot="secondary">${item.entity_id}</span>
|
||||
</mwc-list-item>`;
|
||||
|
||||
@customElement("ha-entity-picker")
|
||||
export class HaEntityPicker extends LitElement {
|
||||
@property({ attribute: false }) public hass!: HomeAssistant;
|
||||
|
||||
@@ -1,13 +1,17 @@
|
||||
import "@material/mwc-list/mwc-list-item";
|
||||
import { mdiClose, mdiMenuDown, mdiMenuUp } from "@mdi/js";
|
||||
import "@vaadin/combo-box/theme/material/vaadin-combo-box-light";
|
||||
import type { ComboBoxLight } from "@vaadin/combo-box/vaadin-combo-box-light";
|
||||
import type {
|
||||
ComboBoxLight,
|
||||
ComboBoxLightFilterChangedEvent,
|
||||
ComboBoxLightOpenedChangedEvent,
|
||||
ComboBoxLightValueChangedEvent,
|
||||
} from "@vaadin/combo-box/vaadin-combo-box-light";
|
||||
import { registerStyles } from "@vaadin/vaadin-themable-mixin/register-styles";
|
||||
import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit";
|
||||
import { ComboBoxLitRenderer, comboBoxRenderer } from "lit-vaadin-helpers";
|
||||
import { customElement, property, query } from "lit/decorators";
|
||||
import { fireEvent } from "../common/dom/fire_event";
|
||||
import { PolymerChangedEvent } from "../polymer-types";
|
||||
import { HomeAssistant } from "../types";
|
||||
import "./ha-icon-button";
|
||||
import "./ha-textfield";
|
||||
@@ -96,6 +100,8 @@ export class HaComboBox extends LitElement {
|
||||
|
||||
@query("vaadin-combo-box-light", true) private _comboBox!: ComboBoxLight;
|
||||
|
||||
private _overlayMutationObserver?: MutationObserver;
|
||||
|
||||
public open() {
|
||||
this.updateComplete.then(() => {
|
||||
this._comboBox?.open();
|
||||
@@ -108,6 +114,14 @@ export class HaComboBox extends LitElement {
|
||||
});
|
||||
}
|
||||
|
||||
public disconnectedCallback() {
|
||||
super.disconnectedCallback();
|
||||
if (this._overlayMutationObserver) {
|
||||
this._overlayMutationObserver.disconnect();
|
||||
this._overlayMutationObserver = undefined;
|
||||
}
|
||||
}
|
||||
|
||||
public get selectedItem() {
|
||||
return this._comboBox.selectedItem;
|
||||
}
|
||||
@@ -193,21 +207,64 @@ export class HaComboBox extends LitElement {
|
||||
}
|
||||
}
|
||||
|
||||
private _openedChanged(ev: PolymerChangedEvent<boolean>) {
|
||||
private _openedChanged(ev: ComboBoxLightOpenedChangedEvent) {
|
||||
const opened = ev.detail.value;
|
||||
// delay this so we can handle click event before setting _opened
|
||||
setTimeout(() => {
|
||||
this._opened = ev.detail.value;
|
||||
this._opened = opened;
|
||||
}, 0);
|
||||
// @ts-ignore
|
||||
fireEvent(this, ev.type, ev.detail);
|
||||
|
||||
if (
|
||||
opened &&
|
||||
"MutationObserver" in window &&
|
||||
!this._overlayMutationObserver
|
||||
) {
|
||||
const overlay = document.querySelector<HTMLElement>(
|
||||
"vaadin-combo-box-overlay"
|
||||
);
|
||||
|
||||
if (!overlay) {
|
||||
return;
|
||||
}
|
||||
|
||||
this._overlayMutationObserver = new MutationObserver((mutations) => {
|
||||
mutations.forEach((mutation) => {
|
||||
if (
|
||||
mutation.type === "attributes" &&
|
||||
mutation.attributeName === "inert"
|
||||
) {
|
||||
this._overlayMutationObserver?.disconnect();
|
||||
this._overlayMutationObserver = undefined;
|
||||
// @ts-expect-error
|
||||
overlay.inert = false;
|
||||
} else if (mutation.type === "childList") {
|
||||
mutation.removedNodes.forEach((node) => {
|
||||
if (node.nodeName === "VAADIN-COMBO-BOX-OVERLAY") {
|
||||
this._overlayMutationObserver?.disconnect();
|
||||
this._overlayMutationObserver = undefined;
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
this._overlayMutationObserver.observe(overlay, {
|
||||
attributes: true,
|
||||
});
|
||||
this._overlayMutationObserver.observe(document.body, {
|
||||
childList: true,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private _filterChanged(ev: PolymerChangedEvent<string>) {
|
||||
private _filterChanged(ev: ComboBoxLightFilterChangedEvent) {
|
||||
// @ts-ignore
|
||||
fireEvent(this, ev.type, ev.detail, { composed: false });
|
||||
}
|
||||
|
||||
private _valueChanged(ev: PolymerChangedEvent<string>) {
|
||||
private _valueChanged(ev: ComboBoxLightValueChangedEvent) {
|
||||
ev.stopPropagation();
|
||||
const newValue = ev.detail.value;
|
||||
|
||||
|
||||
@@ -28,10 +28,15 @@ export class HaFormfield extends FormfieldBase {
|
||||
css`
|
||||
:host(:not([alignEnd])) ::slotted(ha-switch) {
|
||||
margin-right: 10px;
|
||||
margin-inline-end: 10px;
|
||||
margin-inline-start: inline;
|
||||
}
|
||||
:host([dir="rtl"]:not([alignEnd])) ::slotted(ha-switch) {
|
||||
margin-left: 10px;
|
||||
margin-right: auto;
|
||||
.mdc-form-field > label {
|
||||
direction: var(--direction);
|
||||
margin-inline-start: 0;
|
||||
margin-inline-end: auto;
|
||||
padding-inline-start: 4px;
|
||||
padding-inline-end: 0;
|
||||
}
|
||||
`,
|
||||
];
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import "@material/mwc-formfield/mwc-formfield";
|
||||
import "@material/mwc-list/mwc-list-item";
|
||||
import { mdiClose } from "@mdi/js";
|
||||
import { css, html, LitElement } from "lit";
|
||||
@@ -47,14 +46,14 @@ export class HaSelectSelector extends LitElement {
|
||||
${this.label}
|
||||
${options.map(
|
||||
(item: SelectOption) => html`
|
||||
<mwc-formfield .label=${item.label}>
|
||||
<ha-formfield .label=${item.label}>
|
||||
<ha-radio
|
||||
.checked=${item.value === this.value}
|
||||
.value=${item.value}
|
||||
.disabled=${this.disabled}
|
||||
@change=${this._valueChanged}
|
||||
></ha-radio>
|
||||
</mwc-formfield>
|
||||
</ha-formfield>
|
||||
`
|
||||
)}
|
||||
</div>
|
||||
|
||||
@@ -28,6 +28,7 @@ import { fireEvent } from "../../common/dom/fire_event";
|
||||
import { computeRTLDirection } from "../../common/util/compute_rtl";
|
||||
import { debounce } from "../../common/util/debounce";
|
||||
import { getSignedPath } from "../../data/auth";
|
||||
import { UNAVAILABLE_STATES } from "../../data/entity";
|
||||
import type { MediaPlayerItem } from "../../data/media-player";
|
||||
import {
|
||||
browseMediaPlayer,
|
||||
@@ -45,6 +46,7 @@ import type { HomeAssistant } from "../../types";
|
||||
import { brandsUrl, extractDomainFromBrandUrl } from "../../util/brands-url";
|
||||
import { documentationUrl } from "../../util/documentation-url";
|
||||
import "../entity/ha-entity-picker";
|
||||
import "../ha-alert";
|
||||
import "../ha-button-menu";
|
||||
import "../ha-card";
|
||||
import "../ha-circular-progress";
|
||||
@@ -246,6 +248,16 @@ export class HaMediaPlayerBrowse extends LitElement {
|
||||
],
|
||||
replace: true,
|
||||
});
|
||||
} else if (
|
||||
err.code === "entity_not_found" &&
|
||||
UNAVAILABLE_STATES.includes(this.hass.states[this.entityId]?.state)
|
||||
) {
|
||||
this._setError({
|
||||
message: this.hass.localize(
|
||||
`ui.components.media-browser.media_player_unavailable`
|
||||
),
|
||||
code: "entity_not_found",
|
||||
});
|
||||
} else {
|
||||
this._setError(err);
|
||||
}
|
||||
@@ -305,7 +317,11 @@ export class HaMediaPlayerBrowse extends LitElement {
|
||||
protected render(): TemplateResult {
|
||||
if (this._error) {
|
||||
return html`
|
||||
<div class="container">${this._renderError(this._error)}</div>
|
||||
<div class="container">
|
||||
<ha-alert alert-type="error">
|
||||
${this._renderError(this._error)}
|
||||
</ha-alert>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
@@ -420,7 +436,9 @@ export class HaMediaPlayerBrowse extends LitElement {
|
||||
this._error
|
||||
? html`
|
||||
<div class="container">
|
||||
${this._renderError(this._error)}
|
||||
<ha-alert alert-type="error">
|
||||
${this._renderError(this._error)}
|
||||
</ha-alert>
|
||||
</div>
|
||||
`
|
||||
: isTTSMediaSource(currentItem.media_content_id)
|
||||
|
||||
@@ -159,6 +159,7 @@ export interface CustomActionConfig extends BaseActionConfig {
|
||||
}
|
||||
|
||||
export interface BaseActionConfig {
|
||||
action: string;
|
||||
confirmation?: ConfirmationRestrictionConfig;
|
||||
}
|
||||
|
||||
|
||||
@@ -78,6 +78,7 @@ class MoreInfoMediaPlayer extends LitElement {
|
||||
@click=${this._showBrowseMedia}
|
||||
>
|
||||
<ha-svg-icon
|
||||
class="browse-media-icon"
|
||||
.path=${mdiPlayBoxMultiple}
|
||||
slot="icon"
|
||||
></ha-svg-icon>
|
||||
@@ -211,6 +212,7 @@ class MoreInfoMediaPlayer extends LitElement {
|
||||
|
||||
.controls {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
--mdc-theme-primary: currentColor;
|
||||
}
|
||||
@@ -242,6 +244,10 @@ class MoreInfoMediaPlayer extends LitElement {
|
||||
mwc-button > ha-svg-icon {
|
||||
vertical-align: text-bottom;
|
||||
}
|
||||
|
||||
.browse-media-icon {
|
||||
margin-left: 8px;
|
||||
}
|
||||
`;
|
||||
}
|
||||
|
||||
|
||||
@@ -14,7 +14,6 @@ import {
|
||||
ApplicationCredential,
|
||||
} from "../../../data/application_credential";
|
||||
import { domainToName } from "../../../data/integration";
|
||||
import { PolymerChangedEvent } from "../../../polymer-types";
|
||||
import { haStyleDialog } from "../../../resources/styles";
|
||||
import { HomeAssistant } from "../../../types";
|
||||
import { AddApplicationCredentialDialogParams } from "./show-dialog-add-application-credential";
|
||||
@@ -169,11 +168,9 @@ export class DialogAddApplicationCredential extends LitElement {
|
||||
fireEvent(this, "dialog-closed", { dialog: this.localName });
|
||||
}
|
||||
|
||||
private async _handleDomainPicked(ev: PolymerChangedEvent<string>) {
|
||||
const target = ev.target as any;
|
||||
if (target.selectedItem) {
|
||||
this._domain = target.selectedItem.id;
|
||||
}
|
||||
private async _handleDomainPicked(ev: CustomEvent) {
|
||||
ev.stopPropagation();
|
||||
this._domain = ev.detail.value;
|
||||
}
|
||||
|
||||
private _handleValueChanged(ev: CustomEvent) {
|
||||
|
||||
@@ -53,7 +53,6 @@ export class HaConfigApplicationCredentials extends LitElement {
|
||||
title: localize(
|
||||
"ui.panel.config.application_credentials.picker.headers.name"
|
||||
),
|
||||
width: "40%",
|
||||
direction: "asc",
|
||||
grows: true,
|
||||
template: (_, entry: ApplicationCredential) => html`${entry.name}`,
|
||||
|
||||
@@ -88,7 +88,10 @@ export class CloudAccount extends SubscribeMixin(LitElement) {
|
||||
>
|
||||
<div class="account-row">
|
||||
<paper-item-body two-line>
|
||||
${this.cloudStatus.email}
|
||||
${this.cloudStatus.email.replace(
|
||||
/(\w{3})[\w.-]+@([\w.]+\w)/,
|
||||
"$1***@$2"
|
||||
)}
|
||||
<div secondary class="wrap">
|
||||
${this._subscription
|
||||
? this._subscription.human_description.replace(
|
||||
|
||||
@@ -51,11 +51,6 @@ export class CloudRemotePref extends LitElement {
|
||||
`;
|
||||
}
|
||||
|
||||
const urlParts = remote_domain!.split(".");
|
||||
const hiddenURL = `https://${urlParts[0].substring(0, 5)}***.${
|
||||
urlParts[1]
|
||||
}.${urlParts[2]}.${urlParts[3]}`;
|
||||
|
||||
return html`
|
||||
<ha-card
|
||||
outlined
|
||||
@@ -92,8 +87,9 @@ export class CloudRemotePref extends LitElement {
|
||||
target="_blank"
|
||||
class="break-word"
|
||||
rel="noreferrer"
|
||||
>
|
||||
${hiddenURL}</a
|
||||
>${this.hass.localize(
|
||||
"ui.panel.config.cloud.account.remote.nabu_casa_url"
|
||||
)}</a
|
||||
>.
|
||||
<ha-svg-icon
|
||||
.url=${`https://${remote_domain}`}
|
||||
|
||||
@@ -8,7 +8,7 @@ import "../../../components/ha-navigation-list";
|
||||
import "../../../components/ha-tip";
|
||||
import { BackupContent, fetchBackupInfo } from "../../../data/backup";
|
||||
import { CloudStatus, fetchCloudStatus } from "../../../data/cloud";
|
||||
import { BOARD_NAMES } from "../../../data/hardware";
|
||||
import { BOARD_NAMES, HardwareInfo } from "../../../data/hardware";
|
||||
import { fetchHassioBackups, HassioBackup } from "../../../data/hassio/backup";
|
||||
import {
|
||||
fetchHassioHassOsInfo,
|
||||
@@ -156,8 +156,8 @@ class HaConfigSystemNavigation extends LitElement {
|
||||
this._fetchNetworkStatus();
|
||||
const isHassioLoaded = isComponentLoaded(this.hass, "hassio");
|
||||
this._fetchBackupInfo(isHassioLoaded);
|
||||
this._fetchHardwareInfo(isHassioLoaded);
|
||||
if (isHassioLoaded) {
|
||||
this._fetchHardwareInfo();
|
||||
this._fetchStorageInfo();
|
||||
}
|
||||
}
|
||||
@@ -202,10 +202,17 @@ class HaConfigSystemNavigation extends LitElement {
|
||||
}
|
||||
}
|
||||
|
||||
private async _fetchHardwareInfo() {
|
||||
const osData: HassioHassOSInfo = await fetchHassioHassOsInfo(this.hass);
|
||||
if (osData.board) {
|
||||
this._boardName = BOARD_NAMES[osData.board];
|
||||
private async _fetchHardwareInfo(isHassioLoaded: boolean) {
|
||||
if (isComponentLoaded(this.hass, "hardware")) {
|
||||
const hardwareInfo: HardwareInfo = await this.hass.callWS({
|
||||
type: "hardware/info",
|
||||
});
|
||||
this._boardName = hardwareInfo?.hardware?.[0].name;
|
||||
} else if (isHassioLoaded) {
|
||||
const osData: HassioHassOSInfo = await fetchHassioHassOsInfo(this.hass);
|
||||
if (osData.board) {
|
||||
this._boardName = BOARD_NAMES[osData.board];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
import { DeviceRegistryEntry } from "../../../../../../data/device_registry";
|
||||
import { fetchZwaveNodeComments } from "../../../../../../data/zwave_js";
|
||||
import { HomeAssistant } from "../../../../../../types";
|
||||
import { DeviceAlert } from "../../../ha-config-device-page";
|
||||
|
||||
export const getZwaveDeviceAlerts = async (
|
||||
hass: HomeAssistant,
|
||||
device: DeviceRegistryEntry
|
||||
): Promise<DeviceAlert[]> => {
|
||||
const nodeComments = await fetchZwaveNodeComments(hass, device.id);
|
||||
|
||||
if (!nodeComments?.comments?.length) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return nodeComments.comments.map((comment) => ({
|
||||
level: comment.level,
|
||||
text: comment.text,
|
||||
}));
|
||||
};
|
||||
@@ -1,52 +0,0 @@
|
||||
import { html, LitElement, PropertyValues, TemplateResult } from "lit";
|
||||
import { customElement, property, state } from "lit/decorators";
|
||||
import { DeviceRegistryEntry } from "../../../../../../data/device_registry";
|
||||
import {
|
||||
ZwaveJSNodeComments,
|
||||
fetchZwaveNodeComments,
|
||||
} from "../../../../../../data/zwave_js";
|
||||
import { HomeAssistant } from "../../../../../../types";
|
||||
|
||||
@customElement("ha-device-alerts-zwave_js")
|
||||
export class HaDeviceAlertsZWaveJS extends LitElement {
|
||||
@property({ attribute: false }) public hass!: HomeAssistant;
|
||||
|
||||
@property({ attribute: false }) public device!: DeviceRegistryEntry;
|
||||
|
||||
@state() private _nodeComments?: ZwaveJSNodeComments;
|
||||
|
||||
protected willUpdate(changedProperties: PropertyValues) {
|
||||
super.willUpdate(changedProperties);
|
||||
if (changedProperties.has("device")) {
|
||||
this._fetchNodeDetails();
|
||||
}
|
||||
}
|
||||
|
||||
private async _fetchNodeDetails() {
|
||||
this._nodeComments = await fetchZwaveNodeComments(
|
||||
this.hass,
|
||||
this.device.id
|
||||
);
|
||||
}
|
||||
|
||||
protected render(): TemplateResult {
|
||||
if (this._nodeComments && this._nodeComments.comments?.length > 0) {
|
||||
return html`
|
||||
<div>
|
||||
${this._nodeComments.comments.map(
|
||||
(comment) => html`<ha-alert .alertType=${comment.level}>
|
||||
${comment.text}
|
||||
</ha-alert>`
|
||||
)}
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
return html``;
|
||||
}
|
||||
}
|
||||
|
||||
declare global {
|
||||
interface HTMLElementTagNameMap {
|
||||
"ha-device-alerts-zwave_js": HaDeviceAlertsZWaveJS;
|
||||
}
|
||||
}
|
||||
@@ -83,6 +83,11 @@ export interface DeviceAction {
|
||||
classes?: string;
|
||||
}
|
||||
|
||||
export interface DeviceAlert {
|
||||
level: "warning" | "error" | "info";
|
||||
text: string;
|
||||
}
|
||||
|
||||
@customElement("ha-config-device-page")
|
||||
export class HaConfigDevicePage extends LitElement {
|
||||
@property({ attribute: false }) public hass!: HomeAssistant;
|
||||
@@ -114,6 +119,8 @@ export class HaConfigDevicePage extends LitElement {
|
||||
|
||||
@state() private _deviceActions?: DeviceAction[];
|
||||
|
||||
@state() private _deviceAlerts?: DeviceAlert[];
|
||||
|
||||
private _logbookTime = { recent: 86400 };
|
||||
|
||||
private _device = memoizeOne(
|
||||
@@ -215,12 +222,14 @@ export class HaConfigDevicePage extends LitElement {
|
||||
this._diagnosticDownloadLinks = undefined;
|
||||
this._deleteButtons = undefined;
|
||||
this._deviceActions = undefined;
|
||||
this._deviceAlerts = undefined;
|
||||
}
|
||||
|
||||
if (
|
||||
(this._diagnosticDownloadLinks &&
|
||||
this._deleteButtons &&
|
||||
this._deviceActions) ||
|
||||
this._deviceActions &&
|
||||
this._deviceAlerts) ||
|
||||
!this.devices ||
|
||||
!this.deviceId ||
|
||||
!this.entries
|
||||
@@ -231,9 +240,11 @@ export class HaConfigDevicePage extends LitElement {
|
||||
this._diagnosticDownloadLinks = Math.random();
|
||||
this._deleteButtons = []; // To prevent re-rendering if no delete buttons
|
||||
this._deviceActions = [];
|
||||
this._deviceAlerts = [];
|
||||
this._getDiagnosticButtons(this._diagnosticDownloadLinks);
|
||||
this._getDeleteActions();
|
||||
this._getDeviceActions();
|
||||
this._getDeviceAlerts();
|
||||
}
|
||||
|
||||
protected firstUpdated(changedProps) {
|
||||
@@ -279,7 +290,6 @@ export class HaConfigDevicePage extends LitElement {
|
||||
const area = this._computeArea(this.areas, device);
|
||||
|
||||
const deviceInfo: TemplateResult[] = [];
|
||||
const deviceAlerts: TemplateResult[] = [];
|
||||
|
||||
const actions = [...(this._deviceActions || [])];
|
||||
if (Array.isArray(this._diagnosticDownloadLinks)) {
|
||||
@@ -320,7 +330,268 @@ export class HaConfigDevicePage extends LitElement {
|
||||
);
|
||||
}
|
||||
|
||||
this._renderIntegrationInfo(device, integrations, deviceInfo, deviceAlerts);
|
||||
this._renderIntegrationInfo(device, integrations, deviceInfo);
|
||||
|
||||
const automationCard = isComponentLoaded(this.hass, "automation")
|
||||
? html`
|
||||
<ha-card outlined>
|
||||
<h1 class="card-header">
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.devices.automation.automations_heading"
|
||||
)}
|
||||
<ha-icon-button
|
||||
@click=${this._showAutomationDialog}
|
||||
.disabled=${device.disabled_by}
|
||||
.label=${device.disabled_by
|
||||
? this.hass.localize(
|
||||
"ui.panel.config.devices.automation.create_disabled",
|
||||
"type",
|
||||
this.hass.localize(
|
||||
`ui.panel.config.devices.type.${
|
||||
device.entry_type || "device"
|
||||
}`
|
||||
)
|
||||
)
|
||||
: this.hass.localize(
|
||||
"ui.panel.config.devices.automation.create",
|
||||
"type",
|
||||
this.hass.localize(
|
||||
`ui.panel.config.devices.type.${
|
||||
device.entry_type || "device"
|
||||
}`
|
||||
)
|
||||
)}
|
||||
.path=${mdiPlusCircle}
|
||||
></ha-icon-button>
|
||||
</h1>
|
||||
${this._related?.automation?.length
|
||||
? html`
|
||||
<div class="items">
|
||||
${this._related.automation.map((automation) => {
|
||||
const entityState = this.hass.states[automation];
|
||||
return entityState
|
||||
? html`<div>
|
||||
<a
|
||||
href=${ifDefined(
|
||||
entityState.attributes.id
|
||||
? `/config/automation/edit/${entityState.attributes.id}`
|
||||
: undefined
|
||||
)}
|
||||
>
|
||||
<paper-item
|
||||
.automation=${entityState}
|
||||
.disabled=${!entityState.attributes.id}
|
||||
>
|
||||
<paper-item-body>
|
||||
${computeStateName(entityState)}
|
||||
</paper-item-body>
|
||||
<ha-icon-next></ha-icon-next>
|
||||
</paper-item>
|
||||
</a>
|
||||
${!entityState.attributes.id
|
||||
? html`
|
||||
<paper-tooltip animation-delay="0">
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.devices.cant_edit"
|
||||
)}
|
||||
</paper-tooltip>
|
||||
`
|
||||
: ""}
|
||||
</div> `
|
||||
: "";
|
||||
})}
|
||||
</div>
|
||||
`
|
||||
: html`
|
||||
<div class="card-content">
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.devices.add_prompt",
|
||||
"name",
|
||||
this.hass.localize(
|
||||
"ui.panel.config.devices.automation.automations"
|
||||
),
|
||||
"type",
|
||||
this.hass.localize(
|
||||
`ui.panel.config.devices.type.${
|
||||
device.entry_type || "device"
|
||||
}`
|
||||
)
|
||||
)}
|
||||
</div>
|
||||
`}
|
||||
</ha-card>
|
||||
`
|
||||
: "";
|
||||
|
||||
const sceneCard =
|
||||
isComponentLoaded(this.hass, "scene") && entities.length
|
||||
? html`
|
||||
<ha-card outlined>
|
||||
<h1 class="card-header">
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.devices.scene.scenes_heading"
|
||||
)}
|
||||
|
||||
<ha-icon-button
|
||||
@click=${this._createScene}
|
||||
.disabled=${device.disabled_by}
|
||||
.label=${device.disabled_by
|
||||
? this.hass.localize(
|
||||
"ui.panel.config.devices.scene.create_disabled",
|
||||
"type",
|
||||
this.hass.localize(
|
||||
`ui.panel.config.devices.type.${
|
||||
device.entry_type || "device"
|
||||
}`
|
||||
)
|
||||
)
|
||||
: this.hass.localize(
|
||||
"ui.panel.config.devices.scene.create",
|
||||
"type",
|
||||
this.hass.localize(
|
||||
`ui.panel.config.devices.type.${
|
||||
device.entry_type || "device"
|
||||
}`
|
||||
)
|
||||
)}
|
||||
.path=${mdiPlusCircle}
|
||||
></ha-icon-button>
|
||||
</h1>
|
||||
${this._related?.scene?.length
|
||||
? html`
|
||||
<div class="items">
|
||||
${this._related.scene.map((scene) => {
|
||||
const entityState = this.hass.states[scene];
|
||||
return entityState
|
||||
? html`
|
||||
<div>
|
||||
<a
|
||||
href=${ifDefined(
|
||||
entityState.attributes.id
|
||||
? `/config/scene/edit/${entityState.attributes.id}`
|
||||
: undefined
|
||||
)}
|
||||
>
|
||||
<paper-item
|
||||
.scene=${entityState}
|
||||
.disabled=${!entityState.attributes.id}
|
||||
>
|
||||
<paper-item-body>
|
||||
${computeStateName(entityState)}
|
||||
</paper-item-body>
|
||||
<ha-icon-next></ha-icon-next>
|
||||
</paper-item>
|
||||
</a>
|
||||
${!entityState.attributes.id
|
||||
? html`
|
||||
<paper-tooltip animation-delay="0">
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.devices.cant_edit"
|
||||
)}
|
||||
</paper-tooltip>
|
||||
`
|
||||
: ""}
|
||||
</div>
|
||||
`
|
||||
: "";
|
||||
})}
|
||||
</div>
|
||||
`
|
||||
: html`
|
||||
<div class="card-content">
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.devices.add_prompt",
|
||||
"name",
|
||||
this.hass.localize(
|
||||
"ui.panel.config.devices.scene.scenes"
|
||||
),
|
||||
"type",
|
||||
this.hass.localize(
|
||||
`ui.panel.config.devices.type.${
|
||||
device.entry_type || "device"
|
||||
}`
|
||||
)
|
||||
)}
|
||||
</div>
|
||||
`}
|
||||
</ha-card>
|
||||
`
|
||||
: "";
|
||||
|
||||
const scriptCard = isComponentLoaded(this.hass, "script")
|
||||
? html`
|
||||
<ha-card outlined>
|
||||
<h1 class="card-header">
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.devices.script.scripts_heading"
|
||||
)}
|
||||
<ha-icon-button
|
||||
@click=${this._showScriptDialog}
|
||||
.disabled=${device.disabled_by}
|
||||
.label=${device.disabled_by
|
||||
? this.hass.localize(
|
||||
"ui.panel.config.devices.script.create_disabled",
|
||||
"type",
|
||||
this.hass.localize(
|
||||
`ui.panel.config.devices.type.${
|
||||
device.entry_type || "device"
|
||||
}`
|
||||
)
|
||||
)
|
||||
: this.hass.localize(
|
||||
"ui.panel.config.devices.script.create",
|
||||
"type",
|
||||
this.hass.localize(
|
||||
`ui.panel.config.devices.type.${
|
||||
device.entry_type || "device"
|
||||
}`
|
||||
)
|
||||
)}
|
||||
.path=${mdiPlusCircle}
|
||||
></ha-icon-button>
|
||||
</h1>
|
||||
${this._related?.script?.length
|
||||
? html`
|
||||
<div class="items">
|
||||
${this._related.script.map((script) => {
|
||||
const entityState = this.hass.states[script];
|
||||
return entityState
|
||||
? html`
|
||||
<a
|
||||
href=${`/config/script/edit/${entityState.entity_id}`}
|
||||
>
|
||||
<paper-item .script=${script}>
|
||||
<paper-item-body>
|
||||
${computeStateName(entityState)}
|
||||
</paper-item-body>
|
||||
<ha-icon-next></ha-icon-next>
|
||||
</paper-item>
|
||||
</a>
|
||||
`
|
||||
: "";
|
||||
})}
|
||||
</div>
|
||||
`
|
||||
: html`
|
||||
<div class="card-content">
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.devices.add_prompt",
|
||||
"name",
|
||||
this.hass.localize(
|
||||
"ui.panel.config.devices.script.scripts"
|
||||
),
|
||||
"type",
|
||||
this.hass.localize(
|
||||
`ui.panel.config.devices.type.${
|
||||
device.entry_type || "device"
|
||||
}`
|
||||
)
|
||||
)}
|
||||
</div>
|
||||
`}
|
||||
</ha-card>
|
||||
`
|
||||
: "";
|
||||
|
||||
return html`
|
||||
<hass-tabs-subpage
|
||||
@@ -411,8 +682,19 @@ export class HaConfigDevicePage extends LitElement {
|
||||
</div>
|
||||
<div class="column">
|
||||
${
|
||||
deviceAlerts.length
|
||||
? html` <div class="fullwidth">${deviceAlerts}</div> `
|
||||
this._deviceAlerts?.length
|
||||
? html`
|
||||
<div>
|
||||
${this._deviceAlerts.map(
|
||||
(alert) =>
|
||||
html`
|
||||
<ha-alert .alertType=${alert.level}>
|
||||
${alert.text}
|
||||
</ha-alert>
|
||||
`
|
||||
)}
|
||||
</div>
|
||||
`
|
||||
: ""
|
||||
}
|
||||
<ha-device-info-card
|
||||
@@ -486,275 +768,7 @@ export class HaConfigDevicePage extends LitElement {
|
||||
: ""
|
||||
}
|
||||
</ha-device-info-card>
|
||||
|
||||
${
|
||||
isComponentLoaded(this.hass, "automation")
|
||||
? html`
|
||||
<ha-card outlined>
|
||||
<h1 class="card-header">
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.devices.automation.automations_heading"
|
||||
)}
|
||||
<ha-icon-button
|
||||
@click=${this._showAutomationDialog}
|
||||
.disabled=${device.disabled_by}
|
||||
.label=${device.disabled_by
|
||||
? this.hass.localize(
|
||||
"ui.panel.config.devices.automation.create_disabled",
|
||||
"type",
|
||||
this.hass.localize(
|
||||
`ui.panel.config.devices.type.${
|
||||
device.entry_type || "device"
|
||||
}`
|
||||
)
|
||||
)
|
||||
: this.hass.localize(
|
||||
"ui.panel.config.devices.automation.create",
|
||||
"type",
|
||||
this.hass.localize(
|
||||
`ui.panel.config.devices.type.${
|
||||
device.entry_type || "device"
|
||||
}`
|
||||
)
|
||||
)}
|
||||
.path=${mdiPlusCircle}
|
||||
></ha-icon-button>
|
||||
</h1>
|
||||
${this._related?.automation?.length
|
||||
? html`
|
||||
<div class="items">
|
||||
${this._related.automation.map((automation) => {
|
||||
const entityState =
|
||||
this.hass.states[automation];
|
||||
return entityState
|
||||
? html`<div>
|
||||
<a
|
||||
href=${ifDefined(
|
||||
entityState.attributes.id
|
||||
? `/config/automation/edit/${entityState.attributes.id}`
|
||||
: undefined
|
||||
)}
|
||||
>
|
||||
<paper-item
|
||||
.automation=${entityState}
|
||||
.disabled=${!entityState.attributes
|
||||
.id}
|
||||
>
|
||||
<paper-item-body>
|
||||
${computeStateName(entityState)}
|
||||
</paper-item-body>
|
||||
<ha-icon-next></ha-icon-next>
|
||||
</paper-item>
|
||||
</a>
|
||||
${!entityState.attributes.id
|
||||
? html`
|
||||
<paper-tooltip animation-delay="0">
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.devices.cant_edit"
|
||||
)}
|
||||
</paper-tooltip>
|
||||
`
|
||||
: ""}
|
||||
</div> `
|
||||
: "";
|
||||
})}
|
||||
</div>
|
||||
`
|
||||
: html`
|
||||
<div class="card-content">
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.devices.add_prompt",
|
||||
"name",
|
||||
this.hass.localize(
|
||||
"ui.panel.config.devices.automation.automations"
|
||||
),
|
||||
"type",
|
||||
this.hass.localize(
|
||||
`ui.panel.config.devices.type.${
|
||||
device.entry_type || "device"
|
||||
}`
|
||||
)
|
||||
)}
|
||||
</div>
|
||||
`}
|
||||
</ha-card>
|
||||
`
|
||||
: ""
|
||||
}
|
||||
${
|
||||
isComponentLoaded(this.hass, "scene") && entities.length
|
||||
? html`
|
||||
<ha-card outlined>
|
||||
<h1 class="card-header">
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.devices.scene.scenes_heading"
|
||||
)}
|
||||
|
||||
<ha-icon-button
|
||||
@click=${this._createScene}
|
||||
.disabled=${device.disabled_by}
|
||||
.label=${device.disabled_by
|
||||
? this.hass.localize(
|
||||
"ui.panel.config.devices.scene.create_disabled",
|
||||
"type",
|
||||
this.hass.localize(
|
||||
`ui.panel.config.devices.type.${
|
||||
device.entry_type || "device"
|
||||
}`
|
||||
)
|
||||
)
|
||||
: this.hass.localize(
|
||||
"ui.panel.config.devices.scene.create",
|
||||
"type",
|
||||
this.hass.localize(
|
||||
`ui.panel.config.devices.type.${
|
||||
device.entry_type || "device"
|
||||
}`
|
||||
)
|
||||
)}
|
||||
.path=${mdiPlusCircle}
|
||||
></ha-icon-button>
|
||||
</h1>
|
||||
${this._related?.scene?.length
|
||||
? html`
|
||||
<div class="items">
|
||||
${this._related.scene.map((scene) => {
|
||||
const entityState = this.hass.states[scene];
|
||||
return entityState
|
||||
? html`
|
||||
<div>
|
||||
<a
|
||||
href=${ifDefined(
|
||||
entityState.attributes.id
|
||||
? `/config/scene/edit/${entityState.attributes.id}`
|
||||
: undefined
|
||||
)}
|
||||
>
|
||||
<paper-item
|
||||
.scene=${entityState}
|
||||
.disabled=${!entityState.attributes
|
||||
.id}
|
||||
>
|
||||
<paper-item-body>
|
||||
${computeStateName(entityState)}
|
||||
</paper-item-body>
|
||||
<ha-icon-next></ha-icon-next>
|
||||
</paper-item>
|
||||
</a>
|
||||
${!entityState.attributes.id
|
||||
? html`
|
||||
<paper-tooltip
|
||||
animation-delay="0"
|
||||
>
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.devices.cant_edit"
|
||||
)}
|
||||
</paper-tooltip>
|
||||
`
|
||||
: ""}
|
||||
</div>
|
||||
`
|
||||
: "";
|
||||
})}
|
||||
</div>
|
||||
`
|
||||
: html`
|
||||
<div class="card-content">
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.devices.add_prompt",
|
||||
"name",
|
||||
this.hass.localize(
|
||||
"ui.panel.config.devices.scene.scenes"
|
||||
),
|
||||
"type",
|
||||
this.hass.localize(
|
||||
`ui.panel.config.devices.type.${
|
||||
device.entry_type || "device"
|
||||
}`
|
||||
)
|
||||
)}
|
||||
</div>
|
||||
`}
|
||||
</ha-card>
|
||||
`
|
||||
: ""
|
||||
}
|
||||
${
|
||||
isComponentLoaded(this.hass, "script")
|
||||
? html`
|
||||
<ha-card outlined>
|
||||
<h1 class="card-header">
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.devices.script.scripts_heading"
|
||||
)}
|
||||
<ha-icon-button
|
||||
@click=${this._showScriptDialog}
|
||||
.disabled=${device.disabled_by}
|
||||
.label=${device.disabled_by
|
||||
? this.hass.localize(
|
||||
"ui.panel.config.devices.script.create_disabled",
|
||||
"type",
|
||||
this.hass.localize(
|
||||
`ui.panel.config.devices.type.${
|
||||
device.entry_type || "device"
|
||||
}`
|
||||
)
|
||||
)
|
||||
: this.hass.localize(
|
||||
"ui.panel.config.devices.script.create",
|
||||
"type",
|
||||
this.hass.localize(
|
||||
`ui.panel.config.devices.type.${
|
||||
device.entry_type || "device"
|
||||
}`
|
||||
)
|
||||
)}
|
||||
.path=${mdiPlusCircle}
|
||||
></ha-icon-button>
|
||||
</h1>
|
||||
${this._related?.script?.length
|
||||
? html`
|
||||
<div class="items">
|
||||
${this._related.script.map((script) => {
|
||||
const entityState = this.hass.states[script];
|
||||
return entityState
|
||||
? html`
|
||||
<a
|
||||
href=${`/config/script/edit/${entityState.entity_id}`}
|
||||
>
|
||||
<paper-item .script=${script}>
|
||||
<paper-item-body>
|
||||
${computeStateName(entityState)}
|
||||
</paper-item-body>
|
||||
<ha-icon-next></ha-icon-next>
|
||||
</paper-item>
|
||||
</a>
|
||||
`
|
||||
: "";
|
||||
})}
|
||||
</div>
|
||||
`
|
||||
: html`
|
||||
<div class="card-content">
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.devices.add_prompt",
|
||||
"name",
|
||||
this.hass.localize(
|
||||
"ui.panel.config.devices.script.scripts"
|
||||
),
|
||||
"type",
|
||||
this.hass.localize(
|
||||
`ui.panel.config.devices.type.${
|
||||
device.entry_type || "device"
|
||||
}`
|
||||
)
|
||||
)}
|
||||
</div>
|
||||
`}
|
||||
</ha-card>
|
||||
`
|
||||
: ""
|
||||
}
|
||||
${!this.narrow ? [automationCard, sceneCard, scriptCard] : ""}
|
||||
</div>
|
||||
<div class="column">
|
||||
${["control", "sensor", "config", "diagnostic"].map((category) =>
|
||||
@@ -777,6 +791,7 @@ export class HaConfigDevicePage extends LitElement {
|
||||
)}
|
||||
</div>
|
||||
<div class="column">
|
||||
${this.narrow ? [automationCard, sceneCard, scriptCard] : ""}
|
||||
${
|
||||
isComponentLoaded(this.hass, "logbook")
|
||||
? html`
|
||||
@@ -976,6 +991,33 @@ export class HaConfigDevicePage extends LitElement {
|
||||
this._deviceActions = deviceActions;
|
||||
}
|
||||
|
||||
private async _getDeviceAlerts() {
|
||||
const device = this._device(this.deviceId, this.devices);
|
||||
|
||||
if (!device) {
|
||||
return;
|
||||
}
|
||||
|
||||
const deviceAlerts: DeviceAlert[] = [];
|
||||
|
||||
const domains = this._integrations(device, this.entries).map(
|
||||
(int) => int.domain
|
||||
);
|
||||
|
||||
if (domains.includes("zwave_js")) {
|
||||
const zwave = await import(
|
||||
"./device-detail/integration-elements/zwave_js/device-alerts"
|
||||
);
|
||||
|
||||
const alerts = await zwave.getZwaveDeviceAlerts(this.hass, device);
|
||||
deviceAlerts.push(...alerts);
|
||||
}
|
||||
|
||||
if (deviceAlerts.length) {
|
||||
this._deviceAlerts = deviceAlerts;
|
||||
}
|
||||
}
|
||||
|
||||
private _computeEntityName(entity: EntityRegistryEntry) {
|
||||
if (entity.name) {
|
||||
return entity.name;
|
||||
@@ -1023,8 +1065,7 @@ export class HaConfigDevicePage extends LitElement {
|
||||
private _renderIntegrationInfo(
|
||||
device: DeviceRegistryEntry,
|
||||
integrations: ConfigEntry[],
|
||||
deviceInfo: TemplateResult[],
|
||||
deviceAlerts: TemplateResult[]
|
||||
deviceInfo: TemplateResult[]
|
||||
) {
|
||||
const domains = integrations.map((int) => int.domain);
|
||||
if (domains.includes("zha")) {
|
||||
@@ -1037,18 +1078,9 @@ export class HaConfigDevicePage extends LitElement {
|
||||
`);
|
||||
}
|
||||
if (domains.includes("zwave_js")) {
|
||||
import(
|
||||
"./device-detail/integration-elements/zwave_js/ha-device-alerts-zwave_js"
|
||||
);
|
||||
import(
|
||||
"./device-detail/integration-elements/zwave_js/ha-device-info-zwave_js"
|
||||
);
|
||||
deviceAlerts.push(html`
|
||||
<ha-device-alerts-zwave_js
|
||||
.hass=${this.hass}
|
||||
.device=${device}
|
||||
></ha-device-alerts-zwave_js>
|
||||
`);
|
||||
deviceInfo.push(html`
|
||||
<ha-device-info-zwave_js
|
||||
.hass=${this.hass}
|
||||
|
||||
@@ -378,8 +378,7 @@ export class EntityRegistrySettings extends SubscribeMixin(LitElement) {
|
||||
</mwc-list-item>
|
||||
<mwc-list-item
|
||||
value="outlet"
|
||||
.selected=${!this._deviceClass ||
|
||||
this._deviceClass === "outlet"}
|
||||
.selected=${this._deviceClass === "outlet"}
|
||||
>
|
||||
${this.hass.localize(
|
||||
"ui.dialogs.entity_registry.editor.device_classes.switch.outlet"
|
||||
|
||||
@@ -694,6 +694,11 @@ class ZWaveJSConfigDashboard extends SubscribeMixin(LitElement) {
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
span[slot="meta"] {
|
||||
font-size: 0.95em;
|
||||
color: var(--primary-text-color);
|
||||
}
|
||||
|
||||
.network-status div.heading {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
@@ -2,7 +2,6 @@ import "@material/mwc-button";
|
||||
import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit";
|
||||
import { property, state } from "lit/decorators";
|
||||
import memoizeOne from "memoize-one";
|
||||
import { computeRTLDirection } from "../../../common/util/compute_rtl";
|
||||
import "../../../components/entity/ha-entities-picker";
|
||||
import { createCloseHeading } from "../../../components/ha-dialog";
|
||||
import "../../../components/ha-formfield";
|
||||
@@ -159,7 +158,6 @@ class DialogPersonDetail extends LitElement {
|
||||
.label=${this.hass.localize(
|
||||
"ui.panel.config.person.detail.local_only"
|
||||
)}
|
||||
.dir=${computeRTLDirection(this.hass)}
|
||||
>
|
||||
<ha-switch
|
||||
.checked=${this._localOnly}
|
||||
@@ -171,7 +169,6 @@ class DialogPersonDetail extends LitElement {
|
||||
.label=${this.hass.localize(
|
||||
"ui.panel.config.person.detail.admin"
|
||||
)}
|
||||
.dir=${computeRTLDirection(this.hass)}
|
||||
>
|
||||
<ha-switch
|
||||
.disabled=${this._user.system_generated ||
|
||||
|
||||
@@ -6,7 +6,8 @@ import {
|
||||
PropertyValues,
|
||||
TemplateResult,
|
||||
} from "lit";
|
||||
import { customElement, state } from "lit/decorators";
|
||||
import { customElement, property, state } from "lit/decorators";
|
||||
import { classMap } from "lit/directives/class-map";
|
||||
import { DOMAINS_TOGGLE } from "../../../common/const";
|
||||
import { applyThemesOnElement } from "../../../common/dom/apply_themes_on_element";
|
||||
import { computeDomain } from "../../../common/entity/compute_domain";
|
||||
@@ -54,6 +55,8 @@ class HuiEntitiesCard extends LitElement implements LovelaceCard {
|
||||
return { type: "entities", entities: foundEntities };
|
||||
}
|
||||
|
||||
@property() public editMode?: boolean | any;
|
||||
|
||||
@state() private _config?: EntitiesCardConfig;
|
||||
|
||||
private _hass?: HomeAssistant;
|
||||
@@ -217,9 +220,15 @@ class HuiEntitiesCard extends LitElement implements LovelaceCard {
|
||||
`}
|
||||
</h1>
|
||||
`}
|
||||
<div id="states" class="card-content">
|
||||
${this._configEntities!.map((entityConf) =>
|
||||
this.renderEntity(entityConf)
|
||||
<div
|
||||
id="states"
|
||||
class=${classMap({
|
||||
"card-content": true,
|
||||
highlight: this.editMode?.selectedRow !== undefined,
|
||||
})}
|
||||
>
|
||||
${this._configEntities!.map((entityConf, idx) =>
|
||||
this.renderEntity(entityConf, idx)
|
||||
)}
|
||||
</div>
|
||||
|
||||
@@ -272,6 +281,12 @@ class HuiEntitiesCard extends LitElement implements LovelaceCard {
|
||||
#states > div {
|
||||
position: relative;
|
||||
}
|
||||
#states.highlight > div.selected {
|
||||
opacity: 1;
|
||||
}
|
||||
#states.highlight > div {
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
.icon {
|
||||
padding: 0px 18px 0px 8px;
|
||||
@@ -293,7 +308,10 @@ class HuiEntitiesCard extends LitElement implements LovelaceCard {
|
||||
`;
|
||||
}
|
||||
|
||||
private renderEntity(entityConf: LovelaceRowConfig): TemplateResult {
|
||||
private renderEntity(
|
||||
entityConf: LovelaceRowConfig,
|
||||
idx: number
|
||||
): TemplateResult {
|
||||
const element = createRowElement(
|
||||
(!("type" in entityConf) || entityConf.type === "conditional") &&
|
||||
this._config!.state_color
|
||||
@@ -307,7 +325,13 @@ class HuiEntitiesCard extends LitElement implements LovelaceCard {
|
||||
element.hass = this._hass;
|
||||
}
|
||||
|
||||
return html`<div>${element}</div>`;
|
||||
return html`<div
|
||||
class=${classMap({
|
||||
selected: this.editMode?.selectedRow === idx,
|
||||
})}
|
||||
>
|
||||
${element}
|
||||
</div>`;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@ import {
|
||||
TemplateResult,
|
||||
} from "lit";
|
||||
import { property, state } from "lit/decorators";
|
||||
import { classMap } from "lit/directives/class-map";
|
||||
import { LovelaceCardConfig } from "../../../data/lovelace";
|
||||
import { HomeAssistant } from "../../../types";
|
||||
import { createCardElement } from "../create-element/create-card-element";
|
||||
@@ -28,7 +29,7 @@ export abstract class HuiStackCard<T extends StackCardConfig = StackCardConfig>
|
||||
|
||||
@property({ attribute: false }) public hass?: HomeAssistant;
|
||||
|
||||
@property() public editMode?: boolean;
|
||||
@property() public editMode?: any;
|
||||
|
||||
@property() protected _cards?: LovelaceCard[];
|
||||
|
||||
@@ -43,8 +44,16 @@ export abstract class HuiStackCard<T extends StackCardConfig = StackCardConfig>
|
||||
throw new Error("Invalid configuration");
|
||||
}
|
||||
this._config = config;
|
||||
this._cards = config.cards.map((card) => {
|
||||
this._cards = config.cards.map((card, idx) => {
|
||||
const element = this._createCardElement(card) as LovelaceCard;
|
||||
if (this.editMode !== undefined) {
|
||||
if (this.editMode?.selected === idx) {
|
||||
element.classList.add("selected");
|
||||
element.editMode = this.editMode.data;
|
||||
} else {
|
||||
element.editMode = true;
|
||||
}
|
||||
}
|
||||
return element;
|
||||
});
|
||||
}
|
||||
@@ -58,12 +67,18 @@ export abstract class HuiStackCard<T extends StackCardConfig = StackCardConfig>
|
||||
return;
|
||||
}
|
||||
|
||||
for (const element of this._cards) {
|
||||
for (const [idx, element] of this._cards.entries()) {
|
||||
if (this.hass) {
|
||||
element.hass = this.hass;
|
||||
}
|
||||
if (this.editMode !== undefined) {
|
||||
element.editMode = this.editMode;
|
||||
if (this.editMode.selected === idx) {
|
||||
element.editMode = this.editMode.data ?? true;
|
||||
element.classList.add("selected");
|
||||
} else {
|
||||
element.editMode = true;
|
||||
element.classList.remove("selected");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -77,7 +92,12 @@ export abstract class HuiStackCard<T extends StackCardConfig = StackCardConfig>
|
||||
${this._config.title
|
||||
? html`<h1 class="card-header">${this._config.title}</h1>`
|
||||
: ""}
|
||||
<div id="root">${this._cards}</div>
|
||||
<div
|
||||
id="root"
|
||||
class=${classMap({ highlight: this.editMode?.selected !== undefined })}
|
||||
>
|
||||
${this._cards}
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
@@ -95,6 +115,12 @@ export abstract class HuiStackCard<T extends StackCardConfig = StackCardConfig>
|
||||
display: block;
|
||||
padding: 24px 16px 16px;
|
||||
}
|
||||
#root.highlight > *.selected {
|
||||
opacity: 1;
|
||||
}
|
||||
#root.highlight > * {
|
||||
opacity: 0.5;
|
||||
}
|
||||
`;
|
||||
}
|
||||
|
||||
|
||||
@@ -193,6 +193,9 @@ export class HuiEntityEditor extends LitElement {
|
||||
.add-entity {
|
||||
display: block;
|
||||
margin-left: 31px;
|
||||
margin-inline-start: 31px;
|
||||
margin-inline-end: initial;
|
||||
direction: var(--direction);
|
||||
}
|
||||
.entity {
|
||||
display: flex;
|
||||
|
||||
@@ -12,6 +12,8 @@ export class HuiCardPreview extends ReactiveElement {
|
||||
|
||||
@property() public config?: LovelaceCardConfig;
|
||||
|
||||
@property() public editMode = true;
|
||||
|
||||
private _element?: LovelaceCard;
|
||||
|
||||
private get _error() {
|
||||
@@ -81,6 +83,9 @@ export class HuiCardPreview extends ReactiveElement {
|
||||
this._element.hass = this.hass;
|
||||
}
|
||||
}
|
||||
if (changedProperties.has("editMode")) {
|
||||
this._element!.editMode = this.editMode;
|
||||
}
|
||||
}
|
||||
|
||||
private _createCard(configValue: LovelaceCardConfig): void {
|
||||
@@ -90,6 +95,7 @@ export class HuiCardPreview extends ReactiveElement {
|
||||
if (this.hass) {
|
||||
this._element!.hass = this.hass;
|
||||
}
|
||||
this._element!.editMode = this.editMode;
|
||||
|
||||
this.appendChild(this._element!);
|
||||
}
|
||||
|
||||
@@ -43,6 +43,13 @@ declare global {
|
||||
interface HTMLElementEventMap {
|
||||
"reload-lovelace": HASSDomEvent<undefined>;
|
||||
}
|
||||
|
||||
interface HASSDomEvents {
|
||||
"edit-mode-changed": any;
|
||||
}
|
||||
interface HTMLElementEventMap {
|
||||
"edit-mode-changed": HASSDomEvent<any>;
|
||||
}
|
||||
}
|
||||
|
||||
@customElement("hui-dialog-edit-card")
|
||||
@@ -77,10 +84,13 @@ export class HuiDialogEditCard
|
||||
|
||||
@state() private _isEscapeEnabled = true;
|
||||
|
||||
@state() private _editMode = true;
|
||||
|
||||
public async showDialog(params: EditCardDialogParams): Promise<void> {
|
||||
this._params = params;
|
||||
this._GUImode = true;
|
||||
this._guiModeAvailable = true;
|
||||
this._editMode = true;
|
||||
const [view, card] = params.path;
|
||||
this._viewConfig = params.lovelaceConfig.views[view];
|
||||
this._cardConfig =
|
||||
@@ -205,6 +215,7 @@ export class HuiDialogEditCard
|
||||
.lovelace=${this._params.lovelaceConfig}
|
||||
.value=${this._cardConfig}
|
||||
@config-changed=${this._handleConfigChanged}
|
||||
@edit-mode-changed=${this._handleEditModeChanged}
|
||||
@GUImode-changed=${this._handleGUIModeChanged}
|
||||
@editor-save=${this._save}
|
||||
dialogInitialFocus
|
||||
@@ -214,6 +225,7 @@ export class HuiDialogEditCard
|
||||
<hui-card-preview
|
||||
.hass=${this.hass}
|
||||
.config=${this._cardConfig}
|
||||
.editMode=${this._editMode}
|
||||
class=${this._error ? "blur" : ""}
|
||||
></hui-card-preview>
|
||||
${this._error
|
||||
@@ -284,6 +296,10 @@ export class HuiDialogEditCard
|
||||
this._dirty = true;
|
||||
}
|
||||
|
||||
private _handleEditModeChanged(ev: HASSDomEvent<any>) {
|
||||
this._editMode = ev.detail ?? true;
|
||||
}
|
||||
|
||||
private _handleGUIModeChanged(ev: HASSDomEvent<GUIModeChangedEvent>): void {
|
||||
ev.stopPropagation();
|
||||
this._GUImode = ev.detail.guiMode;
|
||||
|
||||
@@ -49,6 +49,7 @@ import {
|
||||
SubElementEditorConfig,
|
||||
} from "../types";
|
||||
import { configElementStyle } from "./config-elements-style";
|
||||
import { buttonEntityConfigStruct } from "../structs/button-entity-struct";
|
||||
|
||||
const buttonEntitiesRowConfigStruct = object({
|
||||
type: literal("button"),
|
||||
@@ -112,22 +113,7 @@ const webLinkEntitiesRowConfigStruct = object({
|
||||
|
||||
const buttonsEntitiesRowConfigStruct = object({
|
||||
type: literal("buttons"),
|
||||
entities: array(
|
||||
union([
|
||||
object({
|
||||
entity: string(),
|
||||
name: optional(string()),
|
||||
icon: optional(string()),
|
||||
image: optional(string()),
|
||||
show_name: optional(boolean()),
|
||||
show_icon: optional(boolean()),
|
||||
tap_action: optional(actionConfigStruct),
|
||||
hold_action: optional(actionConfigStruct),
|
||||
double_tap_action: optional(actionConfigStruct),
|
||||
}),
|
||||
string(),
|
||||
])
|
||||
),
|
||||
entities: array(buttonEntityConfigStruct),
|
||||
});
|
||||
|
||||
const attributeEntitiesRowConfigStruct = object({
|
||||
@@ -422,10 +408,15 @@ export class HuiEntitiesCardEditor
|
||||
|
||||
private _editDetailElement(ev: HASSDomEvent<EditSubElementEvent>): void {
|
||||
this._subElementEditorConfig = ev.detail.subElementConfig;
|
||||
|
||||
fireEvent(this, "edit-mode-changed", {
|
||||
selectedRow: ev.detail.subElementConfig?.index,
|
||||
});
|
||||
}
|
||||
|
||||
private _goBack(): void {
|
||||
this._subElementEditorConfig = undefined;
|
||||
fireEvent(this, "edit-mode-changed", true);
|
||||
}
|
||||
|
||||
static get styles(): CSSResultGroup {
|
||||
|
||||
@@ -144,6 +144,7 @@ export class HuiStackCardEditor
|
||||
.lovelace=${this.lovelace}
|
||||
@config-changed=${this._handleConfigChanged}
|
||||
@GUImode-changed=${this._handleGUIModeChanged}
|
||||
@edit-mode-changed=${this._handleEditModeChanged}
|
||||
></hui-card-element-editor>
|
||||
`
|
||||
: html`
|
||||
@@ -166,6 +167,9 @@ export class HuiStackCardEditor
|
||||
this._setMode(true);
|
||||
this._guiModeAvailable = true;
|
||||
this._selectedCard = parseInt(ev.detail.selected, 10);
|
||||
if (this._cardEditorEl) {
|
||||
this._cardEditorEl.forceRebuild = true;
|
||||
}
|
||||
}
|
||||
|
||||
protected _handleConfigChanged(ev: HASSDomEvent<ConfigChangedEvent>) {
|
||||
@@ -226,6 +230,14 @@ export class HuiStackCardEditor
|
||||
this._guiModeAvailable = ev.detail.guiModeAvailable;
|
||||
}
|
||||
|
||||
protected _handleEditModeChanged(ev: HASSDomEvent<any>) {
|
||||
ev.stopPropagation();
|
||||
fireEvent(this, "edit-mode-changed", {
|
||||
selected: this._selectedCard,
|
||||
data: ev.detail,
|
||||
});
|
||||
}
|
||||
|
||||
protected _toggleMode(): void {
|
||||
this._cardEditorEl?.toggleMode();
|
||||
}
|
||||
@@ -237,6 +249,13 @@ export class HuiStackCardEditor
|
||||
}
|
||||
}
|
||||
|
||||
protected updated(changedProperties) {
|
||||
if (changedProperties.has("_selectedCard"))
|
||||
fireEvent(this, "edit-mode-changed", {
|
||||
selected: this._selectedCard,
|
||||
});
|
||||
}
|
||||
|
||||
static get styles(): CSSResultGroup {
|
||||
return [
|
||||
configElementStyle,
|
||||
|
||||
@@ -53,6 +53,8 @@ export abstract class HuiElementEditor<T> extends LitElement {
|
||||
|
||||
@property({ attribute: false }) public lovelace?: LovelaceConfig;
|
||||
|
||||
public forceRebuild = false;
|
||||
|
||||
@state() private _yaml?: string;
|
||||
|
||||
@state() private _config?: T;
|
||||
@@ -292,7 +294,11 @@ export abstract class HuiElementEditor<T> extends LitElement {
|
||||
this._errors = undefined;
|
||||
this._warnings = undefined;
|
||||
|
||||
if (this._configElementType !== this.configElementType) {
|
||||
if (
|
||||
this._configElementType !== this.configElementType ||
|
||||
this.forceRebuild
|
||||
) {
|
||||
this.forceRebuild = false;
|
||||
// If the type has changed, we need to load a new GUI editor
|
||||
this._guiSupported = undefined;
|
||||
this._configElement = undefined;
|
||||
|
||||
@@ -261,6 +261,9 @@ export class HuiEntitiesCardRowEditor extends LitElement {
|
||||
display: block;
|
||||
margin-left: 31px;
|
||||
margin-right: 71px;
|
||||
margin-inline-start: 31px;
|
||||
margin-inline-end: 71px;
|
||||
direction: var(--direction);
|
||||
}
|
||||
.entity {
|
||||
display: flex;
|
||||
@@ -270,6 +273,9 @@ export class HuiEntitiesCardRowEditor extends LitElement {
|
||||
.entity .handle {
|
||||
padding-right: 8px;
|
||||
cursor: move;
|
||||
padding-inline-end: 8px;
|
||||
padding-inline-start: initial;
|
||||
direction: var(--direction);
|
||||
}
|
||||
|
||||
.entity ha-entity-picker {
|
||||
|
||||
@@ -1,14 +1,16 @@
|
||||
import {
|
||||
object,
|
||||
string,
|
||||
union,
|
||||
boolean,
|
||||
optional,
|
||||
array,
|
||||
literal,
|
||||
boolean,
|
||||
dynamic,
|
||||
enums,
|
||||
literal,
|
||||
object,
|
||||
optional,
|
||||
string,
|
||||
type,
|
||||
union,
|
||||
} from "superstruct";
|
||||
import { BaseActionConfig } from "../../../../data/lovelace";
|
||||
|
||||
const actionConfigStructUser = object({
|
||||
user: string(),
|
||||
@@ -65,10 +67,23 @@ export const actionConfigStructType = object({
|
||||
confirmation: optional(actionConfigStructConfirmation),
|
||||
});
|
||||
|
||||
export const actionConfigStruct = union([
|
||||
actionConfigStructType,
|
||||
actionConfigStructUrl,
|
||||
actionConfigStructNavigate,
|
||||
actionConfigStructService,
|
||||
actionConfigStructCustom,
|
||||
]);
|
||||
export const actionConfigStruct = dynamic<any>((value) => {
|
||||
if (value && typeof value === "object" && "action" in value) {
|
||||
switch ((value as BaseActionConfig).action!) {
|
||||
case "call-service": {
|
||||
return actionConfigStructService;
|
||||
}
|
||||
case "fire-dom-event": {
|
||||
return actionConfigStructCustom;
|
||||
}
|
||||
case "navigate": {
|
||||
return actionConfigStructNavigate;
|
||||
}
|
||||
case "url": {
|
||||
return actionConfigStructUrl;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return actionConfigStructType;
|
||||
});
|
||||
|
||||
14
src/panels/lovelace/editor/structs/button-entity-struct.ts
Normal file
14
src/panels/lovelace/editor/structs/button-entity-struct.ts
Normal file
@@ -0,0 +1,14 @@
|
||||
import { boolean, object, optional, string } from "superstruct";
|
||||
import { actionConfigStruct } from "./action-struct";
|
||||
|
||||
export const buttonEntityConfigStruct = object({
|
||||
entity: string(),
|
||||
name: optional(string()),
|
||||
icon: optional(string()),
|
||||
image: optional(string()),
|
||||
show_name: optional(boolean()),
|
||||
show_icon: optional(boolean()),
|
||||
tap_action: optional(actionConfigStruct),
|
||||
hold_action: optional(actionConfigStruct),
|
||||
double_tap_action: optional(actionConfigStruct),
|
||||
});
|
||||
@@ -1,6 +1,15 @@
|
||||
import { object, string, optional, array, number, union } from "superstruct";
|
||||
import {
|
||||
array,
|
||||
dynamic,
|
||||
number,
|
||||
object,
|
||||
optional,
|
||||
union,
|
||||
string,
|
||||
} from "superstruct";
|
||||
import { actionConfigStruct } from "../editor/structs/action-struct";
|
||||
import { entitiesConfigStruct } from "../editor/structs/entities-struct";
|
||||
import { buttonEntityConfigStruct } from "../editor/structs/button-entity-struct";
|
||||
import { LovelaceHeaderFooterConfig } from "./types";
|
||||
|
||||
export const pictureHeaderFooterConfigStruct = object({
|
||||
type: string(),
|
||||
@@ -12,7 +21,7 @@ export const pictureHeaderFooterConfigStruct = object({
|
||||
|
||||
export const buttonsHeaderFooterConfigStruct = object({
|
||||
type: string(),
|
||||
entities: array(entitiesConfigStruct),
|
||||
entities: array(buttonEntityConfigStruct),
|
||||
});
|
||||
|
||||
export const graphHeaderFooterConfigStruct = object({
|
||||
@@ -22,8 +31,25 @@ export const graphHeaderFooterConfigStruct = object({
|
||||
hours_to_show: optional(number()),
|
||||
});
|
||||
|
||||
export const headerFooterConfigStructs = union([
|
||||
pictureHeaderFooterConfigStruct,
|
||||
buttonsHeaderFooterConfigStruct,
|
||||
graphHeaderFooterConfigStruct,
|
||||
]);
|
||||
export const headerFooterConfigStructs = dynamic<any>((value) => {
|
||||
if (value && typeof value === "object" && "type" in value) {
|
||||
switch ((value as LovelaceHeaderFooterConfig).type!) {
|
||||
case "buttons": {
|
||||
return buttonsHeaderFooterConfigStruct;
|
||||
}
|
||||
case "graph": {
|
||||
return graphHeaderFooterConfigStruct;
|
||||
}
|
||||
case "picture": {
|
||||
return pictureHeaderFooterConfigStruct;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// No "type" property => we fallback to a union of all potential types
|
||||
return union([
|
||||
buttonsHeaderFooterConfigStruct,
|
||||
graphHeaderFooterConfigStruct,
|
||||
pictureHeaderFooterConfigStruct,
|
||||
]);
|
||||
});
|
||||
|
||||
@@ -38,7 +38,7 @@ export interface LovelaceBadge extends HTMLElement {
|
||||
export interface LovelaceCard extends HTMLElement {
|
||||
hass?: HomeAssistant;
|
||||
isPanel?: boolean;
|
||||
editMode?: boolean;
|
||||
editMode?: any;
|
||||
getCardSize(): number | Promise<number>;
|
||||
setConfig(config: LovelaceCardConfig): void;
|
||||
}
|
||||
|
||||
@@ -609,7 +609,8 @@
|
||||
"tv_show": "TV Show",
|
||||
"url": "URL",
|
||||
"video": "Video"
|
||||
}
|
||||
},
|
||||
"media_player_unavailable": "The selected media player is unavailable."
|
||||
},
|
||||
"calendar": {
|
||||
"my_calendars": "My Calendars",
|
||||
@@ -2372,8 +2373,8 @@
|
||||
"reconnecting": "Not connected. Trying to reconnect.",
|
||||
"access_is_being_prepared": "Remote control is being prepared. We will notify you when it's ready.",
|
||||
"info": "Home Assistant Cloud provides a secure remote connection to your instance while away from home.",
|
||||
"instance_is_available": "Your instance is available at",
|
||||
"instance_will_be_available": "Your instance will be available at",
|
||||
"instance_is_available": "Your instance is available at your",
|
||||
"instance_will_be_available": "Your instance will be available at your",
|
||||
"link_learn_how_it_works": "Learn how it works",
|
||||
"certificate_info": "Certificate Info"
|
||||
},
|
||||
|
||||
151
yarn.lock
151
yarn.lock
@@ -3246,7 +3246,7 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@polymer/iron-resizable-behavior@npm:^3.0.0, @polymer/iron-resizable-behavior@npm:^3.0.0-pre.26, @polymer/iron-resizable-behavior@npm:^3.0.1":
|
||||
"@polymer/iron-resizable-behavior@npm:^3.0.0-pre.26, @polymer/iron-resizable-behavior@npm:^3.0.1":
|
||||
version: 3.0.1
|
||||
resolution: "@polymer/iron-resizable-behavior@npm:3.0.1"
|
||||
dependencies:
|
||||
@@ -4196,87 +4196,86 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@vaadin/combo-box@npm:^22.0.4":
|
||||
version: 22.0.4
|
||||
resolution: "@vaadin/combo-box@npm:22.0.4"
|
||||
"@vaadin/combo-box@npm:^23.0.10":
|
||||
version: 23.0.10
|
||||
resolution: "@vaadin/combo-box@npm:23.0.10"
|
||||
dependencies:
|
||||
"@open-wc/dedupe-mixin": ^1.3.0
|
||||
"@polymer/iron-resizable-behavior": ^3.0.0
|
||||
"@polymer/polymer": ^3.0.0
|
||||
"@vaadin/component-base": ^22.0.4
|
||||
"@vaadin/field-base": ^22.0.4
|
||||
"@vaadin/input-container": ^22.0.4
|
||||
"@vaadin/item": ^22.0.4
|
||||
"@vaadin/vaadin-lumo-styles": ^22.0.4
|
||||
"@vaadin/vaadin-material-styles": ^22.0.4
|
||||
"@vaadin/vaadin-overlay": ^22.0.4
|
||||
"@vaadin/vaadin-themable-mixin": ^22.0.4
|
||||
checksum: a3cde710d1187bba8e9e7eeb7f6397e6e1158befa3412c3aa684b3b45a1425cdee28d408d5e4dc4f586e1f6881db8850fc51c38f4658c4eb65c51a26a9623c56
|
||||
"@vaadin/component-base": ^23.0.10
|
||||
"@vaadin/field-base": ^23.0.10
|
||||
"@vaadin/input-container": ^23.0.10
|
||||
"@vaadin/item": ^23.0.10
|
||||
"@vaadin/vaadin-lumo-styles": ^23.0.10
|
||||
"@vaadin/vaadin-material-styles": ^23.0.10
|
||||
"@vaadin/vaadin-overlay": ^23.0.10
|
||||
"@vaadin/vaadin-themable-mixin": ^23.0.10
|
||||
checksum: daaa0bd0cc0e8f1622417bd311e389f860c76d31fe8885f23fcdd486ff966a0945d6fe504f8d7251ec1ec54b95ef66b52d8a9e9e03ec21791bb6ca8b7f24efeb
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@vaadin/component-base@npm:^22.0.4":
|
||||
version: 22.0.4
|
||||
resolution: "@vaadin/component-base@npm:22.0.4"
|
||||
"@vaadin/component-base@npm:^23.0.10":
|
||||
version: 23.0.10
|
||||
resolution: "@vaadin/component-base@npm:23.0.10"
|
||||
dependencies:
|
||||
"@open-wc/dedupe-mixin": ^1.3.0
|
||||
"@polymer/polymer": ^3.0.0
|
||||
"@vaadin/vaadin-development-mode-detector": ^2.0.0
|
||||
"@vaadin/vaadin-usage-statistics": ^2.1.0
|
||||
lit: ^2.0.0
|
||||
checksum: d18e7cebdd2928e33641ee035927540239e8a65d23521aca2e35d9992a44060d951e877af09088de0ffa88daa11f86a02b86a087cb29b51d9ada574009159509
|
||||
checksum: 2b4d851999aad9dc8e1131d66924e26db64ce5a61d2c895bdf00c8daef774a651f5c2d5ade7274d3c7a1b8286170ee21a7ef873547895e0ceef4f7a7e07073a7
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@vaadin/field-base@npm:^22.0.4":
|
||||
version: 22.0.4
|
||||
resolution: "@vaadin/field-base@npm:22.0.4"
|
||||
"@vaadin/field-base@npm:^23.0.10":
|
||||
version: 23.0.10
|
||||
resolution: "@vaadin/field-base@npm:23.0.10"
|
||||
dependencies:
|
||||
"@open-wc/dedupe-mixin": ^1.3.0
|
||||
"@polymer/polymer": ^3.0.0
|
||||
"@vaadin/component-base": ^22.0.4
|
||||
"@vaadin/component-base": ^23.0.10
|
||||
lit: ^2.0.0
|
||||
checksum: 4ca54ea3efd1bad2cea6ada97484e24f77f7ebb2ab5da7de5b9b7949d624b049d357c7f6f69206f1f10023b1711dc7b8bde9f6dfad774578efec00e1907c4763
|
||||
checksum: 0f8d631af00a8268997beed8bde3f6080482eaf044577fd0df0b518fe06b90cbfa6f5c1b2b6e054171de652914d5596749484e4eaecff9754aef70760f25f493
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@vaadin/icon@npm:^22.0.4":
|
||||
version: 22.0.4
|
||||
resolution: "@vaadin/icon@npm:22.0.4"
|
||||
"@vaadin/icon@npm:^23.0.10":
|
||||
version: 23.0.10
|
||||
resolution: "@vaadin/icon@npm:23.0.10"
|
||||
dependencies:
|
||||
"@polymer/polymer": ^3.0.0
|
||||
"@vaadin/component-base": ^22.0.4
|
||||
"@vaadin/vaadin-lumo-styles": ^22.0.4
|
||||
"@vaadin/vaadin-themable-mixin": ^22.0.4
|
||||
"@vaadin/component-base": ^23.0.10
|
||||
"@vaadin/vaadin-lumo-styles": ^23.0.10
|
||||
"@vaadin/vaadin-themable-mixin": ^23.0.10
|
||||
lit: ^2.0.0
|
||||
checksum: 65e5195a8eb6f8ce24471c3f52ffdd7edc49249e39922e945eb8f02fc2b277d8d527a1538241b9660ca568a87663912b1be9c82fa8a841f286e713630d52f3db
|
||||
checksum: 1b7da9116ac649796e7852572280be67176fd609c46f37cb1f35fdd1daba0d44ac4c81642de07104c16580b9165f1f05af15c15c3828c95bc9d795b3050b31a1
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@vaadin/input-container@npm:^22.0.4":
|
||||
version: 22.0.4
|
||||
resolution: "@vaadin/input-container@npm:22.0.4"
|
||||
"@vaadin/input-container@npm:^23.0.10":
|
||||
version: 23.0.10
|
||||
resolution: "@vaadin/input-container@npm:23.0.10"
|
||||
dependencies:
|
||||
"@polymer/polymer": ^3.0.0
|
||||
"@vaadin/component-base": ^22.0.4
|
||||
"@vaadin/vaadin-lumo-styles": ^22.0.4
|
||||
"@vaadin/vaadin-material-styles": ^22.0.4
|
||||
"@vaadin/vaadin-themable-mixin": ^22.0.4
|
||||
checksum: 718cb7d8f715427d9085feee8a0df987440511059c5bbfcaa80d63ecd989a693f8f50af9da0f483555396aece21b75eff280921eda7cf0b6358e67518e53ba85
|
||||
"@vaadin/component-base": ^23.0.10
|
||||
"@vaadin/vaadin-lumo-styles": ^23.0.10
|
||||
"@vaadin/vaadin-material-styles": ^23.0.10
|
||||
"@vaadin/vaadin-themable-mixin": ^23.0.10
|
||||
checksum: 2a21486ef0d4618bf890823bae2471a4e476cf37d5b53059c80e0516acc34990dd0a627751b17ea3ab7eb3040dd343b222b9984d734bd07985a6b9f441015aa3
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@vaadin/item@npm:^22.0.4":
|
||||
version: 22.0.4
|
||||
resolution: "@vaadin/item@npm:22.0.4"
|
||||
"@vaadin/item@npm:^23.0.10":
|
||||
version: 23.0.10
|
||||
resolution: "@vaadin/item@npm:23.0.10"
|
||||
dependencies:
|
||||
"@open-wc/dedupe-mixin": ^1.3.0
|
||||
"@polymer/polymer": ^3.0.0
|
||||
"@vaadin/component-base": ^22.0.4
|
||||
"@vaadin/vaadin-lumo-styles": ^22.0.4
|
||||
"@vaadin/vaadin-material-styles": ^22.0.4
|
||||
"@vaadin/vaadin-themable-mixin": ^22.0.4
|
||||
checksum: ef8c253668852a129656e083149b3866327dfae8671e30bb1bf78b39f969bd1db74892f090c7632b64fd91c25334f0542ad9dc6848486609de4350da5e5ea44c
|
||||
"@vaadin/component-base": ^23.0.10
|
||||
"@vaadin/vaadin-lumo-styles": ^23.0.10
|
||||
"@vaadin/vaadin-material-styles": ^23.0.10
|
||||
"@vaadin/vaadin-themable-mixin": ^23.0.10
|
||||
checksum: 790fb48a12c37ad20fbb8f498601585006e27e2b78164336932c64071b1a7d34e88541d4f190c5357c32694dc76676d63c22b4c9cee64debecef90ea5f9ebbc5
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@@ -4287,49 +4286,49 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@vaadin/vaadin-lumo-styles@npm:^22.0.4":
|
||||
version: 22.0.4
|
||||
resolution: "@vaadin/vaadin-lumo-styles@npm:22.0.4"
|
||||
"@vaadin/vaadin-lumo-styles@npm:^23.0.10":
|
||||
version: 23.0.10
|
||||
resolution: "@vaadin/vaadin-lumo-styles@npm:23.0.10"
|
||||
dependencies:
|
||||
"@polymer/iron-icon": ^3.0.0
|
||||
"@polymer/iron-iconset-svg": ^3.0.0
|
||||
"@polymer/polymer": ^3.0.0
|
||||
"@vaadin/icon": ^22.0.4
|
||||
"@vaadin/vaadin-themable-mixin": ^22.0.4
|
||||
checksum: 15e9becd675e0d12024fbdfaecedd03f55841f685932ff5cf8a2143641f895309f21b84f378f1fca3af538c3aba26dad81421f05a28f31ad7bb5550ede8a3aea
|
||||
"@vaadin/icon": ^23.0.10
|
||||
"@vaadin/vaadin-themable-mixin": ^23.0.10
|
||||
checksum: c2a9c9f9d441bc55f326b267c4953361d64fed4bfe08727e7c3ea1d1598711c18c4e78faedb7ae192ba474b72a6f1521f366be1a9ed80132f83bc400869275c7
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@vaadin/vaadin-material-styles@npm:^22.0.4":
|
||||
version: 22.0.4
|
||||
resolution: "@vaadin/vaadin-material-styles@npm:22.0.4"
|
||||
"@vaadin/vaadin-material-styles@npm:^23.0.10":
|
||||
version: 23.0.10
|
||||
resolution: "@vaadin/vaadin-material-styles@npm:23.0.10"
|
||||
dependencies:
|
||||
"@polymer/polymer": ^3.0.0
|
||||
"@vaadin/vaadin-themable-mixin": ^22.0.4
|
||||
checksum: 0e341e03eab9641cc317a9cbf6d57e7d026539d7bc77159226625aad63a379f31cd70da5e02f10a3d79e9fe0cba1b058935beb2c5d98f146bfb9dd45d8634ee6
|
||||
"@vaadin/vaadin-themable-mixin": ^23.0.10
|
||||
checksum: d2f47272ac6ec3c099a6bebb0d6d861837f5d506b4c1c1ce2fe7d691b1aa8dd944afaaa9c3d4fc51cbee2cfb2efb677a89428fc124a1a4c4cc2b98058a6d2ef7
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@vaadin/vaadin-overlay@npm:^22.0.4":
|
||||
version: 22.0.4
|
||||
resolution: "@vaadin/vaadin-overlay@npm:22.0.4"
|
||||
"@vaadin/vaadin-overlay@npm:^23.0.10":
|
||||
version: 23.0.10
|
||||
resolution: "@vaadin/vaadin-overlay@npm:23.0.10"
|
||||
dependencies:
|
||||
"@polymer/polymer": ^3.0.0
|
||||
"@vaadin/component-base": ^22.0.4
|
||||
"@vaadin/vaadin-lumo-styles": ^22.0.4
|
||||
"@vaadin/vaadin-material-styles": ^22.0.4
|
||||
"@vaadin/vaadin-themable-mixin": ^22.0.4
|
||||
checksum: 1b012ff0beac7879da498cf50ee0974d4c3e5637ebea7f7834b9bfc45b9f02e80c61267794c0f3f4e1d4853aa2f35113e1d94bc187d9fe072f37a03eb99f3ab6
|
||||
"@vaadin/component-base": ^23.0.10
|
||||
"@vaadin/vaadin-lumo-styles": ^23.0.10
|
||||
"@vaadin/vaadin-material-styles": ^23.0.10
|
||||
"@vaadin/vaadin-themable-mixin": ^23.0.10
|
||||
checksum: 25bbca730426a87967ea0648db760b2669a257e46cd2e60cd9506bbfd8c0e7c353fc23063aa338b8feee9f6ed0a763c78a458b79c39d04c34591fdc8e476274c
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@vaadin/vaadin-themable-mixin@npm:^22.0.4":
|
||||
version: 22.0.4
|
||||
resolution: "@vaadin/vaadin-themable-mixin@npm:22.0.4"
|
||||
"@vaadin/vaadin-themable-mixin@npm:^23.0.10":
|
||||
version: 23.0.10
|
||||
resolution: "@vaadin/vaadin-themable-mixin@npm:23.0.10"
|
||||
dependencies:
|
||||
"@open-wc/dedupe-mixin": ^1.3.0
|
||||
lit: ^2.0.0
|
||||
checksum: 0b2dce09626c92b85ff2d2ad48c8130239bf41fd95147a5fd4490cab4767f074ba9d1008d732d9e90b9219cb1ac0509f4a5fc8637eb5847d6d33e14b20552186
|
||||
checksum: 056bff097ebc7fe1756c53018272b8b3b9006a53e77bf5ba964cff2f3b43ede52d980352a3bd38bc9eb6889ab85e897dcdc67493e9c0380993afd4fa0f2e7796
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@@ -9084,8 +9083,8 @@ fsevents@^1.2.7:
|
||||
"@types/webspeechapi": ^0.0.29
|
||||
"@typescript-eslint/eslint-plugin": ^4.32.0
|
||||
"@typescript-eslint/parser": ^4.32.0
|
||||
"@vaadin/combo-box": ^22.0.4
|
||||
"@vaadin/vaadin-themable-mixin": ^22.0.4
|
||||
"@vaadin/combo-box": ^23.0.10
|
||||
"@vaadin/vaadin-themable-mixin": ^23.0.10
|
||||
"@vibrant/color": ^3.2.1-alpha.1
|
||||
"@vibrant/core": ^3.2.1-alpha.1
|
||||
"@vibrant/quantizer-mmcq": ^3.2.1-alpha.1
|
||||
@@ -9128,7 +9127,7 @@ fsevents@^1.2.7:
|
||||
gulp-rename: ^2.0.0
|
||||
gulp-zopfli-green: ^3.0.1
|
||||
hls.js: ^1.1.5
|
||||
home-assistant-js-websocket: ^7.0.3
|
||||
home-assistant-js-websocket: ^7.1.0
|
||||
html-minifier: ^4.0.0
|
||||
husky: ^1.3.1
|
||||
idb-keyval: ^5.1.3
|
||||
@@ -9198,10 +9197,10 @@ fsevents@^1.2.7:
|
||||
languageName: unknown
|
||||
linkType: soft
|
||||
|
||||
"home-assistant-js-websocket@npm:^7.0.3":
|
||||
version: 7.0.3
|
||||
resolution: "home-assistant-js-websocket@npm:7.0.3"
|
||||
checksum: f2647fab4599069a6422b53661de0c8c5177408e297e89f35b442c5d8e65d31d7f607e6e6a813f4ec8af9d581b45a20b88b44bfedbe25b6c3f01fcc38d0e396e
|
||||
"home-assistant-js-websocket@npm:^7.1.0":
|
||||
version: 7.1.0
|
||||
resolution: "home-assistant-js-websocket@npm:7.1.0"
|
||||
checksum: 726f1e8ec0f900203a04ccf57723b448d2fec0a940fa1515f40814e5ae9cda982724d5c4658fd176bd3d8ca82edbe8ddfcef599fd513ca315e8d35cb61c6c142
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
|
||||
Reference in New Issue
Block a user