mirror of
https://github.com/home-assistant/frontend.git
synced 2026-02-28 04:17:48 +00:00
Compare commits
6 Commits
dev
...
copilot/cr
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f8d8bbf5f9 | ||
|
|
be810d1f09 | ||
|
|
8e6f693c55 | ||
|
|
c9d35c0500 | ||
|
|
3b2a1ed5be | ||
|
|
1c50432dd4 |
@@ -515,14 +515,6 @@ export class DemoHaAdaptiveDialog extends LitElement {
|
||||
<td><code>--ha-dialog-surface-background</code></td>
|
||||
<td>Dialog/sheet background color.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>--ha-dialog-surface-backdrop-filter</code></td>
|
||||
<td>Dialog/sheet surface backdrop filter.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>--dialog-box-shadow</code></td>
|
||||
<td>Dialog surface box shadow (dialog mode only).</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>--ha-dialog-border-radius</code></td>
|
||||
<td>Border radius of the dialog surface (dialog mode only).</td>
|
||||
@@ -535,34 +527,6 @@ export class DemoHaAdaptiveDialog extends LitElement {
|
||||
<td><code>--ha-dialog-hide-duration</code></td>
|
||||
<td>Hide animation duration (dialog mode only).</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>--ha-dialog-scrim-backdrop-filter</code></td>
|
||||
<td>Dialog/sheet scrim backdrop filter.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>--dialog-backdrop-filter</code></td>
|
||||
<td>Dialog/sheet scrim backdrop filter (legacy fallback).</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>--mdc-dialog-scrim-color</code></td>
|
||||
<td>Dialog/sheet scrim color (legacy compatibility).</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>--ha-bottom-sheet-surface-background</code></td>
|
||||
<td>Bottom sheet background color (sheet mode only).</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>--ha-bottom-sheet-surface-backdrop-filter</code></td>
|
||||
<td>Bottom sheet surface backdrop filter (sheet mode only).</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>--ha-bottom-sheet-scrim-backdrop-filter</code></td>
|
||||
<td>Bottom sheet scrim backdrop filter (sheet mode only).</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>--ha-bottom-sheet-scrim-color</code></td>
|
||||
<td>Bottom sheet scrim color (sheet mode only).</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
|
||||
@@ -380,29 +380,13 @@ export class DemoHaDialog extends LitElement {
|
||||
<td><code>--ha-dialog-surface-background</code></td>
|
||||
<td>Dialog background color.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>--ha-dialog-surface-backdrop-filter</code></td>
|
||||
<td>Backdrop filter applied to the dialog surface.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>--dialog-box-shadow</code></td>
|
||||
<td>Dialog surface box shadow.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>--ha-dialog-border-radius</code></td>
|
||||
<td>Border radius of the dialog surface.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>--ha-dialog-scrim-backdrop-filter</code></td>
|
||||
<td>Backdrop filter applied to the dialog scrim.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>--dialog-backdrop-filter</code></td>
|
||||
<td>Legacy fallback for the dialog scrim backdrop filter.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>--mdc-dialog-scrim-color</code></td>
|
||||
<td>Dialog scrim color (legacy compatibility).</td>
|
||||
<td><code>--dialog-z-index</code></td>
|
||||
<td>Z-index for the dialog.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>--dialog-surface-margin-top</code></td>
|
||||
|
||||
@@ -92,7 +92,7 @@
|
||||
"@webcomponents/scoped-custom-element-registry": "0.0.10",
|
||||
"@webcomponents/webcomponentsjs": "2.8.0",
|
||||
"app-datepicker": "5.1.1",
|
||||
"barcode-detector": "3.1.0",
|
||||
"barcode-detector": "3.0.8",
|
||||
"color-name": "2.1.0",
|
||||
"comlink": "4.4.2",
|
||||
"core-js": "3.48.0",
|
||||
@@ -149,7 +149,7 @@
|
||||
"@babel/plugin-transform-runtime": "7.29.0",
|
||||
"@babel/preset-env": "7.29.0",
|
||||
"@bundle-stats/plugin-webpack-filter": "4.21.10",
|
||||
"@html-eslint/eslint-plugin": "0.57.0",
|
||||
"@html-eslint/eslint-plugin": "0.56.0",
|
||||
"@lokalise/node-api": "15.6.1",
|
||||
"@octokit/auth-oauth-device": "8.0.3",
|
||||
"@octokit/plugin-retry": "8.1.0",
|
||||
@@ -214,7 +214,7 @@
|
||||
"terser-webpack-plugin": "5.3.16",
|
||||
"ts-lit-plugin": "2.0.2",
|
||||
"typescript": "5.9.3",
|
||||
"typescript-eslint": "8.56.1",
|
||||
"typescript-eslint": "8.56.0",
|
||||
"vite-tsconfig-paths": "6.1.1",
|
||||
"vitest": "4.0.18",
|
||||
"webpack-stats-plugin": "1.1.3",
|
||||
|
||||
@@ -133,34 +133,33 @@ const computeStateToPartsFromEntityAttributes = (
|
||||
),
|
||||
});
|
||||
} catch (_err) {
|
||||
// fallback to default numeric formatting below
|
||||
// fallback to default
|
||||
}
|
||||
|
||||
if (parts.length) {
|
||||
const TYPE_MAP: Record<string, ValuePart["type"]> = {
|
||||
integer: "value",
|
||||
group: "value",
|
||||
decimal: "value",
|
||||
fraction: "value",
|
||||
literal: "literal",
|
||||
currency: "unit",
|
||||
};
|
||||
const TYPE_MAP: Record<string, ValuePart["type"]> = {
|
||||
integer: "value",
|
||||
group: "value",
|
||||
decimal: "value",
|
||||
fraction: "value",
|
||||
literal: "literal",
|
||||
currency: "unit",
|
||||
};
|
||||
|
||||
const valueParts: ValuePart[] = [];
|
||||
const valueParts: ValuePart[] = [];
|
||||
|
||||
for (const part of parts) {
|
||||
const type = TYPE_MAP[part.type];
|
||||
if (!type) continue;
|
||||
const last = valueParts[valueParts.length - 1];
|
||||
// Merge consecutive numeric parts (e.g. "1" + "," + "234" + "." + "56" → "1,234.56")
|
||||
if (type === "value" && last?.type === "value") {
|
||||
last.value += part.value;
|
||||
} else {
|
||||
valueParts.push({ type, value: part.value });
|
||||
}
|
||||
for (const part of parts) {
|
||||
const type = TYPE_MAP[part.type];
|
||||
if (!type) continue;
|
||||
const last = valueParts[valueParts.length - 1];
|
||||
// Merge consecutive numeric parts (e.g. "1" + "," + "234" + "." + "56" → "1,234.56")
|
||||
if (type === "value" && last?.type === "value") {
|
||||
last.value += part.value;
|
||||
} else {
|
||||
valueParts.push({ type, value: part.value });
|
||||
}
|
||||
return valueParts;
|
||||
}
|
||||
|
||||
return valueParts;
|
||||
}
|
||||
|
||||
// default processing of numeric values
|
||||
|
||||
@@ -31,18 +31,9 @@ type DialogSheetMode = "dialog" | "bottom-sheet";
|
||||
* @slot footer - Dialog/sheet footer content.
|
||||
*
|
||||
* @cssprop --ha-dialog-surface-background - Dialog/sheet background color.
|
||||
* @cssprop --ha-dialog-surface-backdrop-filter - Dialog/sheet backdrop filter.
|
||||
* @cssprop --dialog-box-shadow - Dialog box shadow (dialog mode only).
|
||||
* @cssprop --ha-dialog-border-radius - Border radius of the dialog surface (dialog mode only).
|
||||
* @cssprop --ha-dialog-show-duration - Show animation duration (dialog mode only).
|
||||
* @cssprop --ha-dialog-hide-duration - Hide animation duration (dialog mode only).
|
||||
* @cssprop --ha-dialog-scrim-backdrop-filter - Dialog/sheet scrim backdrop filter.
|
||||
* @cssprop --dialog-backdrop-filter - Dialog/sheet scrim backdrop filter (legacy).
|
||||
* @cssprop --mdc-dialog-scrim-color - Dialog/sheet scrim color (legacy).
|
||||
* @cssprop --ha-bottom-sheet-surface-background - Bottom sheet background color (sheet mode only).
|
||||
* @cssprop --ha-bottom-sheet-surface-backdrop-filter - Bottom sheet backdrop filter (sheet mode only).
|
||||
* @cssprop --ha-bottom-sheet-scrim-backdrop-filter - Bottom sheet scrim backdrop filter (sheet mode only).
|
||||
* @cssprop --ha-bottom-sheet-scrim-color - Bottom sheet scrim color (sheet mode only).
|
||||
*
|
||||
* @attr {boolean} open - Controls the dialog/sheet open state.
|
||||
* @attr {("alert"|"standard")} type - Dialog type (dialog mode only). Defaults to "standard".
|
||||
|
||||
@@ -25,27 +25,6 @@ const SWIPE_LOCKED_COMPONENTS = new Set([
|
||||
|
||||
const SWIPE_LOCKED_CLASSES = new Set(["volume-slider-container", "forecast"]);
|
||||
|
||||
/**
|
||||
* Home Assistant bottom sheet component.
|
||||
*
|
||||
* @element ha-bottom-sheet
|
||||
* @extends {LitElement}
|
||||
*
|
||||
* @cssprop --ha-bottom-sheet-height - Preferred height of the bottom sheet.
|
||||
* @cssprop --ha-bottom-sheet-max-height - Maximum height of the bottom sheet.
|
||||
* @cssprop --ha-bottom-sheet-max-width - Maximum width of the bottom sheet.
|
||||
* @cssprop --ha-bottom-sheet-border-radius - Top border radius of the bottom sheet.
|
||||
* @cssprop --ha-bottom-sheet-surface-background - Bottom sheet background color.
|
||||
* @cssprop --ha-bottom-sheet-surface-backdrop-filter - Bottom sheet surface backdrop filter.
|
||||
* @cssprop --ha-bottom-sheet-scrim-backdrop-filter - Bottom sheet scrim backdrop filter.
|
||||
* @cssprop --ha-bottom-sheet-scrim-color - Bottom sheet scrim color.
|
||||
*
|
||||
* @cssprop --ha-dialog-surface-background - Bottom sheet background color fallback.
|
||||
* @cssprop --ha-dialog-surface-backdrop-filter - Bottom sheet surface backdrop filter fallback.
|
||||
* @cssprop --ha-dialog-scrim-backdrop-filter - Bottom sheet scrim backdrop filter fallback.
|
||||
* @cssprop --dialog-backdrop-filter - Bottom sheet scrim backdrop filter legacy fallback.
|
||||
* @cssprop --mdc-dialog-scrim-color - Bottom sheet scrim color legacy fallback.
|
||||
*/
|
||||
@customElement("ha-bottom-sheet")
|
||||
export class HaBottomSheet extends ScrollableFadeMixin(LitElement) {
|
||||
@property({ attribute: false }) public hass?: HomeAssistant;
|
||||
@@ -162,9 +141,6 @@ export class HaBottomSheet extends ScrollableFadeMixin(LitElement) {
|
||||
private _handleKeyDown = (ev: KeyboardEvent) => {
|
||||
if (ev.key === "Escape") {
|
||||
this._escapePressed = true;
|
||||
if (this.preventScrimClose) {
|
||||
ev.preventDefault();
|
||||
}
|
||||
ev.stopPropagation();
|
||||
(ev.currentTarget as WaDrawer).open = false;
|
||||
}
|
||||
@@ -406,26 +382,6 @@ export class HaBottomSheet extends ScrollableFadeMixin(LitElement) {
|
||||
transform: var(--dialog-transform);
|
||||
transition: var(--dialog-transition);
|
||||
}
|
||||
wa-drawer::part(dialog)::backdrop {
|
||||
-webkit-backdrop-filter: var(
|
||||
--ha-bottom-sheet-scrim-backdrop-filter,
|
||||
var(
|
||||
--ha-dialog-scrim-backdrop-filter,
|
||||
var(--dialog-backdrop-filter, none)
|
||||
)
|
||||
);
|
||||
backdrop-filter: var(
|
||||
--ha-bottom-sheet-scrim-backdrop-filter,
|
||||
var(
|
||||
--ha-dialog-scrim-backdrop-filter,
|
||||
var(--dialog-backdrop-filter, none)
|
||||
)
|
||||
);
|
||||
background-color: var(
|
||||
--ha-bottom-sheet-scrim-color,
|
||||
var(--mdc-dialog-scrim-color, none)
|
||||
);
|
||||
}
|
||||
wa-drawer::part(body) {
|
||||
max-width: var(--ha-bottom-sheet-max-width);
|
||||
width: 100%;
|
||||
@@ -440,18 +396,7 @@ export class HaBottomSheet extends ScrollableFadeMixin(LitElement) {
|
||||
);
|
||||
background-color: var(
|
||||
--ha-bottom-sheet-surface-background,
|
||||
var(
|
||||
--ha-dialog-surface-background,
|
||||
var(--card-background-color, var(--ha-color-surface-default))
|
||||
)
|
||||
);
|
||||
-webkit-backdrop-filter: var(
|
||||
--ha-bottom-sheet-surface-backdrop-filter,
|
||||
var(--ha-dialog-surface-backdrop-filter, none)
|
||||
);
|
||||
backdrop-filter: var(
|
||||
--ha-bottom-sheet-surface-backdrop-filter,
|
||||
var(--ha-dialog-surface-backdrop-filter, none)
|
||||
var(--ha-dialog-surface-background, var(--mdc-theme-surface, #fff)),
|
||||
);
|
||||
padding: var(
|
||||
--ha-bottom-sheet-padding,
|
||||
|
||||
@@ -245,7 +245,7 @@ export class HaButton extends Button {
|
||||
}
|
||||
|
||||
.label {
|
||||
overflow: var(--ha-button-label-overflow, hidden);
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
padding: var(--ha-space-1) 0;
|
||||
}
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
import { mdiMenuDown } from "@mdi/js";
|
||||
import type { TemplateResult } from "lit";
|
||||
import type { HassEntity } from "home-assistant-js-websocket";
|
||||
import { css, html, LitElement, nothing } from "lit";
|
||||
import { customElement, property, query } from "lit/decorators";
|
||||
import { classMap } from "lit/directives/class-map";
|
||||
import memoizeOne from "memoize-one";
|
||||
import type { HomeAssistant } from "../types";
|
||||
import "./ha-attribute-icon";
|
||||
import "./ha-dropdown";
|
||||
import "./ha-dropdown-item";
|
||||
import "./ha-icon";
|
||||
@@ -14,10 +16,17 @@ export interface SelectOption {
|
||||
value: string;
|
||||
iconPath?: string;
|
||||
icon?: string;
|
||||
attributeIcon?: {
|
||||
stateObj: HassEntity;
|
||||
attribute: string;
|
||||
attributeValue?: string;
|
||||
};
|
||||
}
|
||||
|
||||
@customElement("ha-control-select-menu")
|
||||
export class HaControlSelectMenu extends LitElement {
|
||||
@property({ attribute: false }) public hass!: HomeAssistant;
|
||||
|
||||
@property({ type: Boolean, attribute: "show-arrow" })
|
||||
public showArrow = false;
|
||||
|
||||
@@ -38,9 +47,6 @@ export class HaControlSelectMenu extends LitElement {
|
||||
|
||||
@property({ attribute: false }) public options: SelectOption[] = [];
|
||||
|
||||
@property({ attribute: false })
|
||||
public renderIcon?: (value: string) => TemplateResult<1> | typeof nothing;
|
||||
|
||||
@query("button") private _triggerButton!: HTMLButtonElement;
|
||||
|
||||
public override render() {
|
||||
@@ -88,8 +94,14 @@ export class HaControlSelectMenu extends LitElement {
|
||||
? html`<ha-svg-icon slot="icon" .path=${option.iconPath}></ha-svg-icon>`
|
||||
: option.icon
|
||||
? html`<ha-icon slot="icon" .icon=${option.icon}></ha-icon>`
|
||||
: this.renderIcon
|
||||
? html`<span slot="icon">${this.renderIcon(option.value)}</span>`
|
||||
: option.attributeIcon
|
||||
? html`<ha-attribute-icon
|
||||
slot="icon"
|
||||
.hass=${this.hass}
|
||||
.stateObj=${option.attributeIcon.stateObj}
|
||||
.attribute=${option.attributeIcon.attribute}
|
||||
.attributeValue=${option.attributeIcon.attributeValue}
|
||||
></ha-attribute-icon>`
|
||||
: nothing}
|
||||
${option.label}</ha-dropdown-item
|
||||
>`;
|
||||
@@ -107,20 +119,24 @@ export class HaControlSelectMenu extends LitElement {
|
||||
}
|
||||
|
||||
private _renderIcon() {
|
||||
const value = this.getValueObject(this.options, this.value);
|
||||
const { iconPath, icon, attributeIcon } =
|
||||
this.getValueObject(this.options, this.value) ?? {};
|
||||
const defaultIcon = this.querySelector("[slot='icon']");
|
||||
|
||||
return html`
|
||||
<div class="icon">
|
||||
${value?.iconPath
|
||||
? html`<ha-svg-icon
|
||||
slot="icon"
|
||||
.path=${value.iconPath}
|
||||
></ha-svg-icon>`
|
||||
: value?.icon
|
||||
? html`<ha-icon slot="icon" .icon=${value.icon}></ha-icon>`
|
||||
: this.renderIcon && this.value
|
||||
? this.renderIcon(this.value)
|
||||
${iconPath
|
||||
? html`<ha-svg-icon slot="icon" .path=${iconPath}></ha-svg-icon>`
|
||||
: icon
|
||||
? html`<ha-icon slot="icon" .icon=${icon}></ha-icon>`
|
||||
: attributeIcon
|
||||
? html`<ha-attribute-icon
|
||||
slot="icon"
|
||||
.hass=${this.hass}
|
||||
.stateObj=${attributeIcon.stateObj}
|
||||
.attribute=${attributeIcon.attribute}
|
||||
.attributeValue=${attributeIcon.attributeValue}
|
||||
></ha-attribute-icon>`
|
||||
: defaultIcon
|
||||
? html`<slot name="icon"></slot>`
|
||||
: nothing}
|
||||
@@ -156,12 +172,12 @@ export class HaControlSelectMenu extends LitElement {
|
||||
font-size: var(--ha-font-size-m);
|
||||
line-height: 1.4;
|
||||
width: auto;
|
||||
color: var(--primary-text-color);
|
||||
-webkit-tap-highlight-color: transparent;
|
||||
}
|
||||
.select-anchor {
|
||||
border: none;
|
||||
text-align: left;
|
||||
color: var(--primary-text-color);
|
||||
height: var(--control-select-menu-height);
|
||||
padding: var(--control-select-menu-padding);
|
||||
overflow: hidden;
|
||||
|
||||
@@ -93,8 +93,6 @@ export class HaDateRangePicker extends LitElement {
|
||||
| "center"
|
||||
| "inline";
|
||||
|
||||
@state() private _calcedVerticalOpeningDirection?: "up" | "down";
|
||||
|
||||
protected willUpdate(changedProps: PropertyValues) {
|
||||
if (
|
||||
(!this.hasUpdated && this.ranges === undefined) ||
|
||||
@@ -136,9 +134,7 @@ export class HaDateRangePicker extends LitElement {
|
||||
opening-direction=${ifDefined(
|
||||
this.openingDirection || this._calcedOpeningDirection
|
||||
)}
|
||||
opens-vertical=${ifDefined(
|
||||
this.verticalOpeningDirection || this._calcedVerticalOpeningDirection
|
||||
)}
|
||||
opens-vertical=${ifDefined(this.verticalOpeningDirection)}
|
||||
first-day=${firstWeekdayIndex(this.hass.locale)}
|
||||
language=${this.hass.locale.language}
|
||||
@change=${this._handleChange}
|
||||
@@ -332,24 +328,17 @@ export class HaDateRangePicker extends LitElement {
|
||||
|
||||
private _handleClick() {
|
||||
// calculate opening direction if not set
|
||||
if (!this._dateRangePicker.open) {
|
||||
if (!this.openingDirection) {
|
||||
const datePickerPosition = this.getBoundingClientRect().x;
|
||||
let opens: "right" | "left" | "center" | "inline";
|
||||
if (datePickerPosition > (2 * window.innerWidth) / 3) {
|
||||
opens = "left";
|
||||
} else if (datePickerPosition < window.innerWidth / 3) {
|
||||
opens = "right";
|
||||
} else {
|
||||
opens = "center";
|
||||
}
|
||||
this._calcedOpeningDirection = opens;
|
||||
}
|
||||
if (!this.verticalOpeningDirection) {
|
||||
const rect = this.getBoundingClientRect();
|
||||
this._calcedVerticalOpeningDirection =
|
||||
rect.top > window.innerHeight / 2 ? "up" : "down";
|
||||
if (!this._dateRangePicker.open && !this.openingDirection) {
|
||||
const datePickerPosition = this.getBoundingClientRect().x;
|
||||
let opens: "right" | "left" | "center" | "inline";
|
||||
if (datePickerPosition > (2 * window.innerWidth) / 3) {
|
||||
opens = "left";
|
||||
} else if (datePickerPosition < window.innerWidth / 3) {
|
||||
opens = "right";
|
||||
} else {
|
||||
opens = "center";
|
||||
}
|
||||
this._calcedOpeningDirection = opens;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -52,12 +52,7 @@ type DialogHideEvent = CustomEvent<{ source?: Element }>;
|
||||
* @cssprop --ha-dialog-show-duration - Show animation duration.
|
||||
* @cssprop --ha-dialog-hide-duration - Hide animation duration.
|
||||
* @cssprop --ha-dialog-surface-background - Dialog background color.
|
||||
* @cssprop --ha-dialog-surface-backdrop-filter - Dialog backdrop filter.
|
||||
* @cssprop --dialog-box-shadow - Dialog box shadow.
|
||||
* @cssprop --ha-dialog-border-radius - Border radius of the dialog surface.
|
||||
* @cssprop --ha-dialog-scrim-backdrop-filter - Dialog scrim backdrop filter.
|
||||
* @cssprop --dialog-backdrop-filter - Dialog scrim backdrop filter (legacy).
|
||||
* @cssprop --mdc-dialog-scrim-color - Dialog scrim color (legacy).
|
||||
* @cssprop --dialog-surface-margin-top - Top margin for the dialog surface.
|
||||
*
|
||||
* @attr {boolean} open - Controls the dialog open state.
|
||||
@@ -244,9 +239,6 @@ export class HaDialog extends ScrollableFadeMixin(LitElement) {
|
||||
private _handleKeyDown(ev: KeyboardEvent) {
|
||||
if (ev.key === "Escape") {
|
||||
this._escapePressed = true;
|
||||
if (this.preventScrimClose) {
|
||||
ev.preventDefault();
|
||||
}
|
||||
ev.stopPropagation();
|
||||
(ev.currentTarget as WaDialog).open = false;
|
||||
}
|
||||
@@ -276,6 +268,10 @@ export class HaDialog extends ScrollableFadeMixin(LitElement) {
|
||||
--spacing: var(--dialog-content-padding, var(--ha-space-6));
|
||||
--show-duration: var(--ha-dialog-show-duration, 200ms);
|
||||
--hide-duration: var(--ha-dialog-hide-duration, 200ms);
|
||||
--ha-dialog-surface-background: var(
|
||||
--card-background-color,
|
||||
var(--ha-color-surface-default)
|
||||
);
|
||||
--wa-color-surface-raised: var(
|
||||
--ha-dialog-surface-background,
|
||||
var(--card-background-color, var(--ha-color-surface-default))
|
||||
@@ -306,12 +302,6 @@ export class HaDialog extends ScrollableFadeMixin(LitElement) {
|
||||
}
|
||||
|
||||
wa-dialog::part(dialog) {
|
||||
-webkit-backdrop-filter: var(
|
||||
--ha-dialog-surface-backdrop-filter,
|
||||
none
|
||||
);
|
||||
backdrop-filter: var(--ha-dialog-surface-backdrop-filter, none);
|
||||
box-shadow: var(--dialog-box-shadow, var(--wa-shadow-l));
|
||||
color: var(--primary-text-color);
|
||||
min-width: var(--width, var(--full-width));
|
||||
max-width: var(--width, var(--full-width));
|
||||
@@ -341,18 +331,6 @@ export class HaDialog extends ScrollableFadeMixin(LitElement) {
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
wa-dialog::part(dialog)::backdrop {
|
||||
-webkit-backdrop-filter: var(
|
||||
--ha-dialog-scrim-backdrop-filter,
|
||||
var(--dialog-backdrop-filter, none)
|
||||
);
|
||||
backdrop-filter: var(
|
||||
--ha-dialog-scrim-backdrop-filter,
|
||||
var(--dialog-backdrop-filter, none)
|
||||
);
|
||||
background-color: var(--mdc-dialog-scrim-color, none);
|
||||
}
|
||||
|
||||
@media all and (max-width: 450px), all and (max-height: 500px) {
|
||||
:host([type="standard"]) {
|
||||
--ha-dialog-border-radius: 0;
|
||||
|
||||
@@ -37,9 +37,6 @@ export class HaIconButtonToggle extends HaIconButton {
|
||||
background-color: transparent;
|
||||
border: 2px solid var(--primary-text-color);
|
||||
}
|
||||
:host([selected]) ha-button::after {
|
||||
opacity: 0;
|
||||
}
|
||||
:host([selected]) ha-button::part(base) {
|
||||
color: var(--primary-background-color);
|
||||
background-color: unset;
|
||||
|
||||
@@ -74,7 +74,6 @@ export class HaIconButton extends LitElement {
|
||||
);
|
||||
--wa-color-on-normal: currentColor;
|
||||
--wa-color-fill-quiet: transparent;
|
||||
--ha-button-label-overflow: visible;
|
||||
}
|
||||
ha-button::after {
|
||||
content: "";
|
||||
|
||||
@@ -9,7 +9,6 @@ import type { CSSResultGroup, PropertyValues } from "lit";
|
||||
import { LitElement, css, html, nothing } from "lit";
|
||||
import { customElement, property, state } from "lit/decorators";
|
||||
import { supportsFeature } from "../../../common/entity/supports-feature";
|
||||
import "../../../components/ha-attribute-icon";
|
||||
import "../../../components/ha-control-select-menu";
|
||||
import "../../../components/ha-icon-button-group";
|
||||
import "../../../components/ha-icon-button-toggle";
|
||||
@@ -40,38 +39,6 @@ class MoreInfoClimate extends LitElement {
|
||||
|
||||
@state() private _mainControl: MainControl = "temperature";
|
||||
|
||||
private _renderPresetModeIcon = (value: string) =>
|
||||
html`<ha-attribute-icon
|
||||
.hass=${this.hass}
|
||||
.stateObj=${this.stateObj}
|
||||
attribute="preset_mode"
|
||||
.attributeValue=${value}
|
||||
></ha-attribute-icon>`;
|
||||
|
||||
private _renderFanModeIcon = (value: string) =>
|
||||
html`<ha-attribute-icon
|
||||
.hass=${this.hass}
|
||||
.stateObj=${this.stateObj}
|
||||
attribute="fan_mode"
|
||||
.attributeValue=${value}
|
||||
></ha-attribute-icon>`;
|
||||
|
||||
private _renderSwingModeIcon = (value: string) =>
|
||||
html`<ha-attribute-icon
|
||||
.hass=${this.hass}
|
||||
.stateObj=${this.stateObj}
|
||||
attribute="swing_mode"
|
||||
.attributeValue=${value}
|
||||
></ha-attribute-icon>`;
|
||||
|
||||
private _renderSwingHorizontalModeIcon = (value: string) =>
|
||||
html`<ha-attribute-icon
|
||||
.hass=${this.hass}
|
||||
.stateObj=${this.stateObj}
|
||||
attribute="swing_horizontal_mode"
|
||||
.attributeValue=${value}
|
||||
></ha-attribute-icon>`;
|
||||
|
||||
protected willUpdate(changedProps: PropertyValues): void {
|
||||
if (
|
||||
changedProps.has("stateObj") &&
|
||||
@@ -238,8 +205,12 @@ class MoreInfoClimate extends LitElement {
|
||||
"preset_mode",
|
||||
mode
|
||||
),
|
||||
attributeIcon: {
|
||||
stateObj,
|
||||
attribute: "preset_mode",
|
||||
attributeValue: mode,
|
||||
},
|
||||
}))}
|
||||
.renderIcon=${this._renderPresetModeIcon}
|
||||
>
|
||||
<ha-svg-icon slot="icon" .path=${mdiTuneVariant}></ha-svg-icon>
|
||||
</ha-control-select-menu>
|
||||
@@ -263,8 +234,12 @@ class MoreInfoClimate extends LitElement {
|
||||
"fan_mode",
|
||||
mode
|
||||
),
|
||||
attributeIcon: {
|
||||
stateObj,
|
||||
attribute: "fan_mode",
|
||||
attributeValue: mode,
|
||||
},
|
||||
}))}
|
||||
.renderIcon=${this._renderFanModeIcon}
|
||||
>
|
||||
<ha-svg-icon slot="icon" .path=${mdiFan}></ha-svg-icon>
|
||||
</ha-control-select-menu>
|
||||
@@ -288,8 +263,12 @@ class MoreInfoClimate extends LitElement {
|
||||
"swing_mode",
|
||||
mode
|
||||
),
|
||||
attributeIcon: {
|
||||
stateObj,
|
||||
attribute: "swing_mode",
|
||||
attributeValue: mode,
|
||||
},
|
||||
}))}
|
||||
.renderIcon=${this._renderSwingModeIcon}
|
||||
>
|
||||
<ha-svg-icon
|
||||
slot="icon"
|
||||
@@ -318,9 +297,13 @@ class MoreInfoClimate extends LitElement {
|
||||
"swing_horizontal_mode",
|
||||
mode
|
||||
),
|
||||
attributeIcon: {
|
||||
stateObj,
|
||||
attribute: "swing_horizontal_mode",
|
||||
attributeValue: mode,
|
||||
},
|
||||
})
|
||||
)}
|
||||
.renderIcon=${this._renderSwingHorizontalModeIcon}
|
||||
>
|
||||
<ha-svg-icon
|
||||
slot="icon"
|
||||
|
||||
@@ -40,22 +40,6 @@ class MoreInfoFan extends LitElement {
|
||||
|
||||
@state() public _presetMode?: string;
|
||||
|
||||
private _renderPresetModeIcon = (value: string) =>
|
||||
html`<ha-attribute-icon
|
||||
.hass=${this.hass}
|
||||
.stateObj=${this.stateObj}
|
||||
attribute="preset_mode"
|
||||
.attributeValue=${value}
|
||||
></ha-attribute-icon>`;
|
||||
|
||||
private _renderDirectionIcon = (value: string) =>
|
||||
html`<ha-attribute-icon
|
||||
.hass=${this.hass}
|
||||
.stateObj=${this.stateObj}
|
||||
attribute="direction"
|
||||
.attributeValue=${value}
|
||||
></ha-attribute-icon>`;
|
||||
|
||||
private _toggle = () => {
|
||||
const service = this.stateObj?.state === "on" ? "turn_off" : "turn_on";
|
||||
forwardHaptic(this, "light");
|
||||
@@ -208,9 +192,15 @@ class MoreInfoFan extends LitElement {
|
||||
"preset_mode",
|
||||
mode
|
||||
),
|
||||
attributeIcon: this.stateObj
|
||||
? {
|
||||
stateObj: this.stateObj,
|
||||
attribute: "preset_mode",
|
||||
attributeValue: mode,
|
||||
}
|
||||
: undefined,
|
||||
})
|
||||
)}
|
||||
.renderIcon=${this._renderPresetModeIcon}
|
||||
>
|
||||
<ha-svg-icon slot="icon" .path=${mdiTuneVariant}></ha-svg-icon>
|
||||
</ha-control-select-menu>
|
||||
@@ -236,8 +226,14 @@ class MoreInfoFan extends LitElement {
|
||||
direction
|
||||
)
|
||||
: direction,
|
||||
attributeIcon: this.stateObj
|
||||
? {
|
||||
stateObj: this.stateObj,
|
||||
attribute: "direction",
|
||||
attributeValue: direction,
|
||||
}
|
||||
: undefined,
|
||||
}))}
|
||||
.renderIcon=${this._renderDirectionIcon}
|
||||
>
|
||||
<ha-attribute-icon
|
||||
slot="icon"
|
||||
|
||||
@@ -23,14 +23,6 @@ class MoreInfoHumidifier extends LitElement {
|
||||
|
||||
@state() public _mode?: string;
|
||||
|
||||
private _renderModeIcon = (value: string) =>
|
||||
html`<ha-attribute-icon
|
||||
.hass=${this.hass}
|
||||
.stateObj=${this.stateObj}
|
||||
attribute="mode"
|
||||
.attributeValue=${value}
|
||||
></ha-attribute-icon>`;
|
||||
|
||||
protected willUpdate(changedProps: PropertyValues): void {
|
||||
super.willUpdate(changedProps);
|
||||
if (changedProps.has("stateObj")) {
|
||||
@@ -114,8 +106,14 @@ class MoreInfoHumidifier extends LitElement {
|
||||
mode
|
||||
)
|
||||
: mode,
|
||||
attributeIcon: stateObj
|
||||
? {
|
||||
stateObj,
|
||||
attribute: "mode",
|
||||
attributeValue: mode,
|
||||
}
|
||||
: undefined,
|
||||
})) || []}
|
||||
.renderIcon=${this._renderModeIcon}
|
||||
>
|
||||
<ha-svg-icon slot="icon" .path=${mdiTuneVariant}></ha-svg-icon>
|
||||
</ha-control-select-menu>
|
||||
|
||||
@@ -55,14 +55,6 @@ class MoreInfoLight extends LitElement {
|
||||
|
||||
@state() private _mainControl: MainControl = "brightness";
|
||||
|
||||
private _renderEffectIcon = (value: string) =>
|
||||
html`<ha-attribute-icon
|
||||
.hass=${this.hass}
|
||||
.stateObj=${this.stateObj}
|
||||
attribute="effect"
|
||||
.attributeValue=${value}
|
||||
></ha-attribute-icon>`;
|
||||
|
||||
protected updated(changedProps: PropertyValues<typeof this>): void {
|
||||
if (changedProps.has("stateObj")) {
|
||||
this._effect = this.stateObj?.attributes.effect;
|
||||
@@ -279,9 +271,15 @@ class MoreInfoLight extends LitElement {
|
||||
effect
|
||||
)
|
||||
: effect,
|
||||
attributeIcon: this.stateObj
|
||||
? {
|
||||
stateObj: this.stateObj,
|
||||
attribute: "effect",
|
||||
attributeValue: effect,
|
||||
}
|
||||
: undefined,
|
||||
})
|
||||
)}
|
||||
.renderIcon=${this._renderEffectIcon}
|
||||
>
|
||||
<ha-svg-icon slot="icon" .path=${mdiCreation}></ha-svg-icon>
|
||||
</ha-control-select-menu>
|
||||
|
||||
@@ -24,14 +24,6 @@ class MoreInfoWaterHeater extends LitElement {
|
||||
|
||||
@property({ attribute: false }) public stateObj?: WaterHeaterEntity;
|
||||
|
||||
private _renderOperationModeIcon = (value: string) =>
|
||||
html`<ha-attribute-icon
|
||||
.hass=${this.hass}
|
||||
.stateObj=${this.stateObj}
|
||||
attribute="operation_mode"
|
||||
.attributeValue=${value}
|
||||
></ha-attribute-icon>`;
|
||||
|
||||
protected render() {
|
||||
if (!this.stateObj) {
|
||||
return nothing;
|
||||
@@ -93,8 +85,12 @@ class MoreInfoWaterHeater extends LitElement {
|
||||
.map((mode) => ({
|
||||
value: mode,
|
||||
label: this.hass.formatEntityState(stateObj, mode),
|
||||
attributeIcon: {
|
||||
stateObj,
|
||||
attribute: "operation_mode",
|
||||
attributeValue: mode,
|
||||
},
|
||||
}))}
|
||||
.renderIcon=${this._renderOperationModeIcon}
|
||||
>
|
||||
<ha-svg-icon slot="icon" .path=${mdiWaterBoiler}></ha-svg-icon>
|
||||
</ha-control-select-menu>
|
||||
|
||||
@@ -2,27 +2,17 @@ import type { HassEntity } from "home-assistant-js-websocket";
|
||||
import type { CSSResultGroup, PropertyValues } from "lit";
|
||||
import { css, html, LitElement, nothing } from "lit";
|
||||
import { customElement, property, state } from "lit/decorators";
|
||||
import memoizeOne from "memoize-one";
|
||||
import { computeAttributeNameDisplay } from "../../common/entity/compute_attribute_display";
|
||||
import checkValidDate from "../../common/datetime/check_valid_date";
|
||||
import { formatDateTimeWithSeconds } from "../../common/datetime/format_date_time";
|
||||
import "../../components/ha-attribute-value";
|
||||
import "../../components/ha-card";
|
||||
import type { LocalizeKeys } from "../../common/translations/localize";
|
||||
import { computeShownAttributes } from "../../data/entity/entity_attributes";
|
||||
import type { ExtEntityRegistryEntry } from "../../data/entity/entity_registry";
|
||||
import type { HomeAssistant } from "../../types";
|
||||
import "../../components/ha-yaml-editor";
|
||||
|
||||
interface DetailsViewParams {
|
||||
entityId: string;
|
||||
}
|
||||
|
||||
interface DetailEntry {
|
||||
translationKey: LocalizeKeys;
|
||||
value: string;
|
||||
}
|
||||
|
||||
@customElement("ha-more-info-details")
|
||||
class HaMoreInfoDetails extends LitElement {
|
||||
@property({ attribute: false }) public hass!: HomeAssistant;
|
||||
@@ -31,8 +21,6 @@ class HaMoreInfoDetails extends LitElement {
|
||||
|
||||
@property({ attribute: false }) public params?: DetailsViewParams;
|
||||
|
||||
@property({ attribute: false }) public yamlMode = false;
|
||||
|
||||
@state() private _stateObj?: HassEntity;
|
||||
|
||||
protected willUpdate(changedProps: PropertyValues): void {
|
||||
@@ -49,127 +37,60 @@ class HaMoreInfoDetails extends LitElement {
|
||||
return nothing;
|
||||
}
|
||||
|
||||
const { stateEntries, attributes, yamlData } = this._getDetailData(
|
||||
this._stateObj
|
||||
const translatedState = this.hass.formatEntityState(this._stateObj);
|
||||
const detailsAttributes = computeShownAttributes(this._stateObj);
|
||||
const detailsAttributeSet = new Set(detailsAttributes);
|
||||
const builtInAttributes = Object.keys(this._stateObj.attributes).filter(
|
||||
(attribute) => !detailsAttributeSet.has(attribute)
|
||||
);
|
||||
const allAttributes = [...detailsAttributes, ...builtInAttributes];
|
||||
|
||||
return html`
|
||||
<div class="content">
|
||||
${this.yamlMode
|
||||
? html`<ha-yaml-editor
|
||||
.hass=${this.hass}
|
||||
.value=${yamlData}
|
||||
read-only
|
||||
auto-update
|
||||
></ha-yaml-editor>`
|
||||
: html`
|
||||
<section class="section">
|
||||
<h2 class="section-title">
|
||||
${this.hass.localize(
|
||||
"ui.components.entity.entity-state-picker.state"
|
||||
)}
|
||||
</h2>
|
||||
<ha-card>
|
||||
<div class="card-content">
|
||||
<div class="data-group">
|
||||
${stateEntries.map(
|
||||
(entry) =>
|
||||
html`<div class="data-entry">
|
||||
<div class="key">
|
||||
${this.hass.localize(entry.translationKey)}
|
||||
</div>
|
||||
<div class="value">${entry.value}</div>
|
||||
</div>`
|
||||
)}
|
||||
</div>
|
||||
<section class="section">
|
||||
<h2 class="section-title">
|
||||
${this.hass.localize(
|
||||
"ui.components.entity.entity-state-picker.state"
|
||||
)}
|
||||
</h2>
|
||||
<ha-card>
|
||||
<div class="card-content">
|
||||
<div class="attribute-group">
|
||||
<div class="data-entry">
|
||||
<div class="key">
|
||||
${this.hass.localize(
|
||||
"ui.dialogs.more_info_control.translated"
|
||||
)}
|
||||
</div>
|
||||
</ha-card>
|
||||
</section>
|
||||
<div class="value">${translatedState}</div>
|
||||
</div>
|
||||
<div class="data-entry">
|
||||
<div class="key">
|
||||
${this.hass.localize("ui.dialogs.more_info_control.raw")}
|
||||
</div>
|
||||
<div class="value">${this._stateObj.state}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</ha-card>
|
||||
</section>
|
||||
|
||||
<section class="section">
|
||||
<h2 class="section-title">
|
||||
${this.hass.localize(
|
||||
"ui.dialogs.more_info_control.attributes"
|
||||
)}
|
||||
</h2>
|
||||
<ha-card>
|
||||
<div class="card-content">
|
||||
<div class="data-group">
|
||||
${this._renderAttributes(attributes)}
|
||||
</div>
|
||||
</div>
|
||||
</ha-card>
|
||||
</section>
|
||||
`}
|
||||
<section class="section">
|
||||
<h2 class="section-title">
|
||||
${this.hass.localize("ui.dialogs.more_info_control.attributes")}
|
||||
</h2>
|
||||
<ha-card>
|
||||
<div class="card-content">
|
||||
<div class="attribute-group">
|
||||
${this._renderAttributes(allAttributes)}
|
||||
</div>
|
||||
</div>
|
||||
</ha-card>
|
||||
</section>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
private _getDetailData = memoizeOne(
|
||||
(
|
||||
stateObj: HassEntity
|
||||
): {
|
||||
stateEntries: DetailEntry[];
|
||||
attributes: string[];
|
||||
yamlData: {
|
||||
state: {
|
||||
translated: string;
|
||||
raw: string;
|
||||
last_changed: string;
|
||||
last_updated: string;
|
||||
};
|
||||
attributes: Record<string, string>;
|
||||
};
|
||||
} => {
|
||||
const translatedState = this.hass.formatEntityState(stateObj);
|
||||
|
||||
const detailsAttributes = computeShownAttributes(stateObj);
|
||||
const detailsAttributeSet = new Set(detailsAttributes);
|
||||
const builtInAttributes = Object.keys(stateObj.attributes).filter(
|
||||
(attribute) => !detailsAttributeSet.has(attribute)
|
||||
);
|
||||
|
||||
return {
|
||||
stateEntries: [
|
||||
{
|
||||
translationKey: "ui.dialogs.more_info_control.translated",
|
||||
value: translatedState,
|
||||
},
|
||||
{
|
||||
translationKey: "ui.dialogs.more_info_control.raw",
|
||||
value: stateObj.state,
|
||||
},
|
||||
{
|
||||
translationKey: "ui.dialogs.more_info_control.last_changed",
|
||||
value: this._formatTimestamp(stateObj.last_changed),
|
||||
},
|
||||
{
|
||||
translationKey: "ui.dialogs.more_info_control.last_updated",
|
||||
value: this._formatTimestamp(stateObj.last_updated),
|
||||
},
|
||||
],
|
||||
attributes: [...detailsAttributes, ...builtInAttributes],
|
||||
yamlData: {
|
||||
state: {
|
||||
translated: translatedState,
|
||||
raw: stateObj.state,
|
||||
last_changed: stateObj.last_changed,
|
||||
last_updated: stateObj.last_updated,
|
||||
},
|
||||
attributes: stateObj.attributes,
|
||||
},
|
||||
};
|
||||
}
|
||||
);
|
||||
|
||||
private _formatTimestamp(value: string): string {
|
||||
const date = new Date(value);
|
||||
|
||||
return checkValidDate(date)
|
||||
? formatDateTimeWithSeconds(date, this.hass.locale, this.hass.config)
|
||||
: value;
|
||||
}
|
||||
|
||||
private _renderAttributes(attributes: string[]) {
|
||||
if (attributes.length === 0) {
|
||||
return html`<div class="empty">
|
||||
@@ -238,7 +159,7 @@ class HaMoreInfoDetails extends LitElement {
|
||||
border-bottom: 1px solid var(--divider-color);
|
||||
}
|
||||
|
||||
.data-group .data-entry:last-of-type {
|
||||
.attribute-group .data-entry:last-of-type {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import {
|
||||
mdiChartBoxOutline,
|
||||
mdiClose,
|
||||
mdiCodeBraces,
|
||||
mdiCogOutline,
|
||||
mdiDevices,
|
||||
mdiDotsVertical,
|
||||
@@ -133,8 +132,6 @@ export class MoreInfoDialog extends ScrollableFadeMixin(LitElement) {
|
||||
|
||||
@state() private _infoEditMode = false;
|
||||
|
||||
@state() private _detailsYamlMode = false;
|
||||
|
||||
@state() private _isEscapeEnabled = true;
|
||||
|
||||
@state() private _sensorNumericDeviceClasses?: string[] = [];
|
||||
@@ -185,7 +182,6 @@ export class MoreInfoDialog extends ScrollableFadeMixin(LitElement) {
|
||||
this._parentEntityIds = [];
|
||||
this._entry = undefined;
|
||||
this._infoEditMode = false;
|
||||
this._detailsYamlMode = false;
|
||||
this._initialView = DEFAULT_VIEW;
|
||||
this._currView = DEFAULT_VIEW;
|
||||
this._childView = undefined;
|
||||
@@ -255,7 +251,6 @@ export class MoreInfoDialog extends ScrollableFadeMixin(LitElement) {
|
||||
private _goBack() {
|
||||
if (this._childView) {
|
||||
this._childView = undefined;
|
||||
this._detailsYamlMode = false;
|
||||
return;
|
||||
}
|
||||
if (this._initialView !== this._currView) {
|
||||
@@ -319,10 +314,6 @@ export class MoreInfoDialog extends ScrollableFadeMixin(LitElement) {
|
||||
this._infoEditMode = !this._infoEditMode;
|
||||
}
|
||||
|
||||
private _toggleDetailsYamlMode() {
|
||||
this._detailsYamlMode = !this._detailsYamlMode;
|
||||
}
|
||||
|
||||
private _handleToggleInfoEditModeEvent(ev) {
|
||||
this._infoEditMode = ev.detail;
|
||||
}
|
||||
@@ -646,18 +637,7 @@ export class MoreInfoDialog extends ScrollableFadeMixin(LitElement) {
|
||||
</ha-dropdown-item>
|
||||
</ha-dropdown>
|
||||
`
|
||||
: this._childView?.viewTag === "ha-more-info-details"
|
||||
? html`
|
||||
<ha-icon-button
|
||||
slot="headerActionItems"
|
||||
.label=${this.hass.localize(
|
||||
"ui.dialogs.more_info_control.toggle_yaml_mode"
|
||||
)}
|
||||
.path=${mdiCodeBraces}
|
||||
@click=${this._toggleDetailsYamlMode}
|
||||
></ha-icon-button>
|
||||
`
|
||||
: nothing}
|
||||
: nothing}
|
||||
<div
|
||||
class=${classMap({
|
||||
"content-wrapper": true,
|
||||
@@ -683,7 +663,6 @@ export class MoreInfoDialog extends ScrollableFadeMixin(LitElement) {
|
||||
hass: this.hass,
|
||||
entry: this._entry,
|
||||
params: this._childView.viewParams,
|
||||
yamlMode: this._detailsYamlMode,
|
||||
})}
|
||||
</div>
|
||||
`
|
||||
@@ -752,7 +731,6 @@ export class MoreInfoDialog extends ScrollableFadeMixin(LitElement) {
|
||||
if (changedProps.has("_currView")) {
|
||||
this._childView = undefined;
|
||||
this._infoEditMode = false;
|
||||
this._detailsYamlMode = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -288,7 +288,7 @@ export class QuickBar extends LitElement {
|
||||
<ha-combo-box-item
|
||||
tabindex="-1"
|
||||
type="button"
|
||||
style="--mdc-icon-size: 24px;"
|
||||
style="--mdc-icon-size: 32px;"
|
||||
>
|
||||
${"stateObj" in item && item.stateObj
|
||||
? html`
|
||||
@@ -302,7 +302,6 @@ export class QuickBar extends LitElement {
|
||||
? html`
|
||||
<ha-domain-icon
|
||||
slot="start"
|
||||
style="margin: var(--ha-space-1);"
|
||||
.hass=${this.hass}
|
||||
.domain=${item.domain}
|
||||
brand-fallback
|
||||
@@ -320,11 +319,7 @@ export class QuickBar extends LitElement {
|
||||
/>
|
||||
`
|
||||
: item.icon
|
||||
? html`<ha-icon
|
||||
style="margin: var(--ha-space-1);"
|
||||
slot="start"
|
||||
.icon=${item.icon}
|
||||
></ha-icon>`
|
||||
? html`<ha-icon slot="start" .icon=${item.icon}></ha-icon>`
|
||||
: "iconColor" in item && item.iconColor
|
||||
? html`
|
||||
<div
|
||||
@@ -338,11 +333,7 @@ export class QuickBar extends LitElement {
|
||||
</div>
|
||||
`
|
||||
: html`
|
||||
<ha-svg-icon
|
||||
style="margin: var(--ha-space-1);"
|
||||
slot="start"
|
||||
.path=${iconPath}
|
||||
></ha-svg-icon>
|
||||
<ha-svg-icon slot="start" .path=${iconPath}></ha-svg-icon>
|
||||
`}
|
||||
<span slot="headline">${item.primary}</span>
|
||||
${item.secondary
|
||||
|
||||
@@ -27,19 +27,15 @@ import { css, html, LitElement, nothing } from "lit";
|
||||
import { customElement, property, query, state } from "lit/decorators";
|
||||
import { classMap } from "lit/directives/class-map";
|
||||
import { UndoRedoController } from "../../../common/controllers/undo-redo-controller";
|
||||
import { transform } from "../../../common/decorators/transform";
|
||||
import { fireEvent } from "../../../common/dom/fire_event";
|
||||
import { goBack, navigate } from "../../../common/navigate";
|
||||
import { promiseTimeout } from "../../../common/util/promise-timeout";
|
||||
import { afterNextRender } from "../../../common/util/render-status";
|
||||
import "../../../components/ha-button";
|
||||
import "../../../components/ha-dropdown";
|
||||
import "../../../components/ha-dropdown-item";
|
||||
import "../../../components/ha-fab";
|
||||
import "../../../components/ha-fade-in";
|
||||
import "../../../components/ha-icon";
|
||||
import "../../../components/ha-icon-button";
|
||||
import "../../../components/ha-spinner";
|
||||
import "../../../components/ha-svg-icon";
|
||||
import "../../../components/ha-yaml-editor";
|
||||
import type {
|
||||
@@ -72,27 +68,22 @@ import {
|
||||
showAlertDialog,
|
||||
showConfirmationDialog,
|
||||
} from "../../../dialogs/generic/show-dialog-box";
|
||||
import { showMoreInfoDialog } from "../../../dialogs/more-info/show-ha-more-info-dialog";
|
||||
import "../../../layouts/hass-subpage";
|
||||
import { KeyboardShortcutMixin } from "../../../mixins/keyboard-shortcut-mixin";
|
||||
import { PreventUnsavedMixin } from "../../../mixins/prevent-unsaved-mixin";
|
||||
import { haStyle } from "../../../resources/styles";
|
||||
import type {
|
||||
Entries,
|
||||
HomeAssistant,
|
||||
Route,
|
||||
ValueChangedEvent,
|
||||
} from "../../../types";
|
||||
import type { Entries, ValueChangedEvent } from "../../../types";
|
||||
import { isMac } from "../../../util/is_mac";
|
||||
import { showToast } from "../../../util/toast";
|
||||
import { showAssignCategoryDialog } from "../category/show-dialog-assign-category";
|
||||
import { showAutomationModeDialog } from "./automation-mode-dialog/show-dialog-automation-mode";
|
||||
import {
|
||||
type EntityRegistryUpdate,
|
||||
showAutomationSaveDialog,
|
||||
} from "./automation-save-dialog/show-dialog-automation-save";
|
||||
import { showAutomationSaveDialog } from "./automation-save-dialog/show-dialog-automation-save";
|
||||
import { showAutomationSaveTimeoutDialog } from "./automation-save-timeout-dialog/show-dialog-automation-save-timeout";
|
||||
import "./blueprint-automation-editor";
|
||||
import {
|
||||
AutomationScriptEditorMixin,
|
||||
automationScriptEditorStyles,
|
||||
} from "./ha-automation-script-editor-mixin";
|
||||
import "./manual-automation-editor";
|
||||
import type { HaManualAutomationEditor } from "./manual-automation-editor";
|
||||
import type { HaDropdownSelectEvent } from "../../../components/ha-dropdown";
|
||||
@@ -119,53 +110,13 @@ declare global {
|
||||
}
|
||||
|
||||
@customElement("ha-automation-editor")
|
||||
export class HaAutomationEditor extends PreventUnsavedMixin(
|
||||
KeyboardShortcutMixin(LitElement)
|
||||
export class HaAutomationEditor extends AutomationScriptEditorMixin<AutomationConfig>(
|
||||
PreventUnsavedMixin(KeyboardShortcutMixin(LitElement))
|
||||
) {
|
||||
@property({ attribute: false }) public hass!: HomeAssistant;
|
||||
|
||||
@property({ attribute: false }) public automationId: string | null = null;
|
||||
|
||||
@property({ attribute: false }) public entityId: string | null = null;
|
||||
|
||||
@property({ attribute: false }) public automations!: AutomationEntity[];
|
||||
|
||||
@property({ attribute: "is-wide", type: Boolean }) public isWide = false;
|
||||
|
||||
@property({ type: Boolean }) public narrow = false;
|
||||
|
||||
@property({ attribute: false }) public route!: Route;
|
||||
|
||||
@state() private _config?: AutomationConfig;
|
||||
|
||||
@state() private _dirty = false;
|
||||
|
||||
@state() private _errors?: string;
|
||||
|
||||
@state() private _yamlErrors?: string;
|
||||
|
||||
@state() private _entityId?: string;
|
||||
|
||||
@state() private _mode: "gui" | "yaml" = "gui";
|
||||
|
||||
@state() private _readOnly = false;
|
||||
|
||||
@state() private _validationErrors?: (string | TemplateResult)[];
|
||||
|
||||
@state() private _blueprintConfig?: BlueprintAutomationConfig;
|
||||
|
||||
@state()
|
||||
@consume({ context: fullEntitiesContext, subscribe: true })
|
||||
@transform<EntityRegistryEntry[], EntityRegistryEntry>({
|
||||
transformer: function (this: HaAutomationEditor, value) {
|
||||
return value.find(({ entity_id }) => entity_id === this._entityId);
|
||||
},
|
||||
watch: ["_entityId"],
|
||||
})
|
||||
private _registryEntry?: EntityRegistryEntry;
|
||||
|
||||
@state() private _saving = false;
|
||||
|
||||
@state()
|
||||
@consume({ context: fullEntitiesContext, subscribe: true })
|
||||
_entityRegistry!: EntityRegistryEntry[];
|
||||
@@ -180,24 +131,18 @@ export class HaAutomationEditor extends PreventUnsavedMixin(
|
||||
|
||||
private _configSubscriptionsId = 1;
|
||||
|
||||
private _entityRegistryUpdate?: EntityRegistryUpdate;
|
||||
|
||||
private _newAutomationId?: string;
|
||||
|
||||
private _entityRegCreated?: (
|
||||
value: PromiseLike<EntityRegistryEntry> | EntityRegistryEntry
|
||||
) => void;
|
||||
|
||||
private _undoRedoController = new UndoRedoController<AutomationConfig>(this, {
|
||||
apply: (config) => this._applyUndoRedo(config),
|
||||
currentConfig: () => this._config!,
|
||||
currentConfig: () => this.config!,
|
||||
});
|
||||
|
||||
protected willUpdate(changedProps) {
|
||||
super.willUpdate(changedProps);
|
||||
|
||||
if (
|
||||
this._entityRegCreated &&
|
||||
this.entityRegCreated &&
|
||||
this._newAutomationId &&
|
||||
changedProps.has("_entityRegistry")
|
||||
) {
|
||||
@@ -207,26 +152,22 @@ export class HaAutomationEditor extends PreventUnsavedMixin(
|
||||
entity.unique_id === this._newAutomationId
|
||||
);
|
||||
if (automation) {
|
||||
this._entityRegCreated(automation);
|
||||
this._entityRegCreated = undefined;
|
||||
this.entityRegCreated(automation);
|
||||
this.entityRegCreated = undefined;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected render(): TemplateResult | typeof nothing {
|
||||
if (!this._config) {
|
||||
return html`
|
||||
<ha-fade-in .delay=${500}>
|
||||
<ha-spinner size="large"></ha-spinner>
|
||||
</ha-fade-in>
|
||||
`;
|
||||
if (!this.config) {
|
||||
return this.renderLoading();
|
||||
}
|
||||
|
||||
const stateObj = this._entityId
|
||||
? this.hass.states[this._entityId]
|
||||
const stateObj = this.currentEntityId
|
||||
? this.hass.states[this.currentEntityId]
|
||||
: undefined;
|
||||
|
||||
const useBlueprint = "use_blueprint" in this._config;
|
||||
const useBlueprint = "use_blueprint" in this.config;
|
||||
const shortcutIcon = isMac
|
||||
? html`<ha-svg-icon .path=${mdiAppleKeyboardCommand}></ha-svg-icon>`
|
||||
: this.hass.localize("ui.panel.config.automation.editor.ctrl");
|
||||
@@ -236,11 +177,11 @@ export class HaAutomationEditor extends PreventUnsavedMixin(
|
||||
.hass=${this.hass}
|
||||
.narrow=${this.narrow}
|
||||
.route=${this.route}
|
||||
.backCallback=${this._backTapped}
|
||||
.header=${this._config.alias ||
|
||||
.backCallback=${this.backTapped}
|
||||
.header=${this.config.alias ||
|
||||
this.hass.localize("ui.panel.config.automation.editor.default_name")}
|
||||
>
|
||||
${this._mode === "gui" && !this.narrow
|
||||
${this.mode === "gui" && !this.narrow
|
||||
? html`<ha-icon-button
|
||||
slot="toolbar-icon"
|
||||
.label=${this.hass.localize("ui.common.undo")}
|
||||
@@ -284,7 +225,7 @@ export class HaAutomationEditor extends PreventUnsavedMixin(
|
||||
</span>
|
||||
</ha-tooltip>`
|
||||
: nothing}
|
||||
${this._config?.id && !this.narrow
|
||||
${this.config?.id && !this.narrow
|
||||
? html`
|
||||
<ha-button
|
||||
appearance="plain"
|
||||
@@ -308,7 +249,7 @@ export class HaAutomationEditor extends PreventUnsavedMixin(
|
||||
.path=${mdiDotsVertical}
|
||||
></ha-icon-button>
|
||||
|
||||
${this._mode === "gui" && this.narrow
|
||||
${this.mode === "gui" && this.narrow
|
||||
? html`<ha-dropdown-item
|
||||
value="undo"
|
||||
.disabled=${!this._undoRedoController.canUndo}
|
||||
@@ -342,7 +283,7 @@ export class HaAutomationEditor extends PreventUnsavedMixin(
|
||||
|
||||
<ha-dropdown-item .disabled=${!stateObj} value="category">
|
||||
${this.hass.localize(
|
||||
`ui.panel.config.scene.picker.${this._registryEntry?.categories?.automation ? "edit_category" : "assign_category"}`
|
||||
`ui.panel.config.scene.picker.${this.registryEntry?.categories?.automation ? "edit_category" : "assign_category"}`
|
||||
)}
|
||||
<ha-svg-icon slot="icon" .path=${mdiTag}></ha-svg-icon>
|
||||
</ha-dropdown-item>
|
||||
@@ -366,9 +307,9 @@ export class HaAutomationEditor extends PreventUnsavedMixin(
|
||||
|
||||
<ha-dropdown-item
|
||||
value="rename"
|
||||
.disabled=${this._readOnly ||
|
||||
.disabled=${this.readOnly ||
|
||||
!this.automationId ||
|
||||
this._mode === "yaml"}
|
||||
this.mode === "yaml"}
|
||||
>
|
||||
${this.hass.localize("ui.panel.config.automation.editor.rename")}
|
||||
<ha-svg-icon slot="icon" .path=${mdiRenameBox}></ha-svg-icon>
|
||||
@@ -377,7 +318,7 @@ export class HaAutomationEditor extends PreventUnsavedMixin(
|
||||
? html`
|
||||
<ha-dropdown-item
|
||||
@click=${this._promptAutomationMode}
|
||||
.disabled=${this._readOnly || this._mode === "yaml"}
|
||||
.disabled=${this.readOnly || this.mode === "yaml"}
|
||||
>
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.automation.editor.change_mode"
|
||||
@@ -391,12 +332,12 @@ export class HaAutomationEditor extends PreventUnsavedMixin(
|
||||
: nothing}
|
||||
|
||||
<ha-dropdown-item
|
||||
.disabled=${!!this._blueprintConfig ||
|
||||
(!this._readOnly && !this.automationId)}
|
||||
.disabled=${!!this.blueprintConfig ||
|
||||
(!this.readOnly && !this.automationId)}
|
||||
value="duplicate"
|
||||
>
|
||||
${this.hass.localize(
|
||||
this._readOnly
|
||||
this.readOnly
|
||||
? "ui.panel.config.automation.editor.migrate"
|
||||
: "ui.panel.config.automation.editor.duplicate"
|
||||
)}
|
||||
@@ -410,7 +351,7 @@ export class HaAutomationEditor extends PreventUnsavedMixin(
|
||||
? html`
|
||||
<ha-dropdown-item
|
||||
value="take_control"
|
||||
.disabled=${this._readOnly}
|
||||
.disabled=${this.readOnly}
|
||||
>
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.automation.editor.take_control"
|
||||
@@ -422,7 +363,7 @@ export class HaAutomationEditor extends PreventUnsavedMixin(
|
||||
|
||||
<ha-dropdown-item value="toggle_yaml_mode">
|
||||
${this.hass.localize(
|
||||
`ui.panel.config.automation.editor.edit_${this._mode === "gui" ? "yaml" : "ui"}`
|
||||
`ui.panel.config.automation.editor.edit_${this.mode === "gui" ? "yaml" : "ui"}`
|
||||
)}
|
||||
<ha-svg-icon slot="icon" .path=${mdiPlaylistEdit}></ha-svg-icon>
|
||||
</ha-dropdown-item>
|
||||
@@ -456,10 +397,10 @@ export class HaAutomationEditor extends PreventUnsavedMixin(
|
||||
</ha-dropdown-item>
|
||||
</ha-dropdown>
|
||||
<div
|
||||
class=${this._mode === "yaml" ? "yaml-mode" : ""}
|
||||
class=${this.mode === "yaml" ? "yaml-mode" : ""}
|
||||
@subscribe-automation-config=${this._subscribeAutomationConfig}
|
||||
>
|
||||
${this._mode === "gui"
|
||||
${this.mode === "gui"
|
||||
? html`
|
||||
<div>
|
||||
${useBlueprint
|
||||
@@ -469,10 +410,10 @@ export class HaAutomationEditor extends PreventUnsavedMixin(
|
||||
.narrow=${this.narrow}
|
||||
.isWide=${this.isWide}
|
||||
.stateObj=${stateObj}
|
||||
.config=${this._config}
|
||||
.disabled=${this._readOnly}
|
||||
.saving=${this._saving}
|
||||
.dirty=${this._dirty}
|
||||
.config=${this.config}
|
||||
.disabled=${this.readOnly}
|
||||
.saving=${this.saving}
|
||||
.dirty=${this.dirty}
|
||||
@value-changed=${this._valueChanged}
|
||||
@save-automation=${this._handleSaveAutomation}
|
||||
></blueprint-automation-editor>
|
||||
@@ -483,16 +424,16 @@ export class HaAutomationEditor extends PreventUnsavedMixin(
|
||||
.narrow=${this.narrow}
|
||||
.isWide=${this.isWide}
|
||||
.stateObj=${stateObj}
|
||||
.config=${this._config}
|
||||
.disabled=${this._readOnly}
|
||||
.dirty=${this._dirty}
|
||||
.saving=${this._saving}
|
||||
.config=${this.config}
|
||||
.disabled=${this.readOnly}
|
||||
.dirty=${this.dirty}
|
||||
.saving=${this.saving}
|
||||
@value-changed=${this._valueChanged}
|
||||
@save-automation=${this._handleSaveAutomation}
|
||||
@editor-save=${this._handleSaveAutomation}
|
||||
>
|
||||
<div class="alert-wrapper" slot="alerts">
|
||||
${this._errors || stateObj?.state === UNAVAILABLE
|
||||
${this.errors || stateObj?.state === UNAVAILABLE
|
||||
? html`<ha-alert
|
||||
alert-type="error"
|
||||
.title=${stateObj?.state === UNAVAILABLE
|
||||
@@ -501,7 +442,7 @@ export class HaAutomationEditor extends PreventUnsavedMixin(
|
||||
)
|
||||
: undefined}
|
||||
>
|
||||
${this._errors || this._validationErrors}
|
||||
${this.errors || this.validationErrors}
|
||||
${stateObj?.state === UNAVAILABLE
|
||||
? html`<ha-svg-icon
|
||||
slot="icon"
|
||||
@@ -510,7 +451,7 @@ export class HaAutomationEditor extends PreventUnsavedMixin(
|
||||
: nothing}
|
||||
</ha-alert>`
|
||||
: nothing}
|
||||
${this._blueprintConfig
|
||||
${this.blueprintConfig
|
||||
? html`<ha-alert alert-type="info">
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.automation.editor.confirm_take_control"
|
||||
@@ -518,21 +459,21 @@ export class HaAutomationEditor extends PreventUnsavedMixin(
|
||||
<div slot="action" style="display: flex;">
|
||||
<ha-button
|
||||
appearance="plain"
|
||||
@click=${this._takeControlSave}
|
||||
@click=${this.takeControlSave}
|
||||
>${this.hass.localize(
|
||||
"ui.common.yes"
|
||||
)}</ha-button
|
||||
>
|
||||
<ha-button
|
||||
appearance="plain"
|
||||
@click=${this._revertBlueprint}
|
||||
@click=${this.revertBlueprint}
|
||||
>${this.hass.localize(
|
||||
"ui.common.no"
|
||||
)}</ha-button
|
||||
>
|
||||
</div>
|
||||
</ha-alert>`
|
||||
: this._readOnly
|
||||
: this.readOnly
|
||||
? html`<ha-alert
|
||||
alert-type="warning"
|
||||
dismissable
|
||||
@@ -575,7 +516,7 @@ export class HaAutomationEditor extends PreventUnsavedMixin(
|
||||
`}
|
||||
</div>
|
||||
`
|
||||
: this._mode === "yaml"
|
||||
: this.mode === "yaml"
|
||||
? html`${stateObj?.state === "off"
|
||||
? html`
|
||||
<ha-alert alert-type="info">
|
||||
@@ -598,7 +539,7 @@ export class HaAutomationEditor extends PreventUnsavedMixin(
|
||||
<ha-yaml-editor
|
||||
.hass=${this.hass}
|
||||
.defaultValue=${this._preprocessYaml()}
|
||||
.readOnly=${this._readOnly}
|
||||
.readOnly=${this.readOnly}
|
||||
@value-changed=${this._yamlChanged}
|
||||
@editor-save=${this._handleSaveAutomation}
|
||||
.showErrors=${false}
|
||||
@@ -606,9 +547,9 @@ export class HaAutomationEditor extends PreventUnsavedMixin(
|
||||
></ha-yaml-editor>
|
||||
<ha-fab
|
||||
slot="fab"
|
||||
class=${this._dirty ? "dirty" : ""}
|
||||
class=${this.dirty ? "dirty" : ""}
|
||||
.label=${this.hass.localize("ui.common.save")}
|
||||
.disabled=${this._saving}
|
||||
.disabled=${this.saving}
|
||||
extended
|
||||
@click=${this._handleSaveAutomation}
|
||||
>
|
||||
@@ -645,7 +586,7 @@ export class HaAutomationEditor extends PreventUnsavedMixin(
|
||||
this.hass
|
||||
) {
|
||||
const initData = getAutomationEditorInitData();
|
||||
this._dirty = !!initData;
|
||||
this.dirty = !!initData;
|
||||
let baseConfig: Partial<AutomationConfig> = { description: "" };
|
||||
if (!initData || !("use_blueprint" in initData)) {
|
||||
baseConfig = {
|
||||
@@ -656,35 +597,35 @@ export class HaAutomationEditor extends PreventUnsavedMixin(
|
||||
actions: [],
|
||||
};
|
||||
}
|
||||
this._config = {
|
||||
this.config = {
|
||||
...baseConfig,
|
||||
...(initData ? normalizeAutomationConfig(initData) : initData),
|
||||
} as AutomationConfig;
|
||||
this._entityId = undefined;
|
||||
this._readOnly = false;
|
||||
this.currentEntityId = undefined;
|
||||
this.readOnly = false;
|
||||
}
|
||||
|
||||
if (changedProps.has("entityId") && this.entityId) {
|
||||
getAutomationStateConfig(this.hass, this.entityId).then((c) => {
|
||||
this._config = normalizeAutomationConfig(c.config);
|
||||
this.config = normalizeAutomationConfig(c.config);
|
||||
this._checkValidation();
|
||||
});
|
||||
this._entityId = this.entityId;
|
||||
this._dirty = false;
|
||||
this._readOnly = true;
|
||||
this.currentEntityId = this.entityId;
|
||||
this.dirty = false;
|
||||
this.readOnly = true;
|
||||
}
|
||||
|
||||
if (
|
||||
changedProps.has("automations") &&
|
||||
this.automationId &&
|
||||
!this._entityId
|
||||
!this.currentEntityId
|
||||
) {
|
||||
this._setEntityId();
|
||||
}
|
||||
|
||||
if (changedProps.has("_config")) {
|
||||
if (changedProps.has("config")) {
|
||||
Object.values(this._configSubscriptions).forEach((sub) =>
|
||||
sub(this._config)
|
||||
sub(this.config)
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -693,24 +634,24 @@ export class HaAutomationEditor extends PreventUnsavedMixin(
|
||||
const automation = this.automations.find(
|
||||
(entity: AutomationEntity) => entity.attributes.id === this.automationId
|
||||
);
|
||||
this._entityId = automation?.entity_id;
|
||||
this.currentEntityId = automation?.entity_id;
|
||||
}
|
||||
|
||||
private async _checkValidation() {
|
||||
this._validationErrors = undefined;
|
||||
if (!this._entityId || !this._config) {
|
||||
this.validationErrors = undefined;
|
||||
if (!this.currentEntityId || !this.config) {
|
||||
return;
|
||||
}
|
||||
const stateObj = this.hass.states[this._entityId];
|
||||
const stateObj = this.hass.states[this.currentEntityId];
|
||||
if (stateObj?.state !== UNAVAILABLE) {
|
||||
return;
|
||||
}
|
||||
const validation = await validateConfig(this.hass, {
|
||||
triggers: this._config.triggers,
|
||||
conditions: this._config.conditions,
|
||||
actions: this._config.actions,
|
||||
triggers: this.config.triggers,
|
||||
conditions: this.config.conditions,
|
||||
actions: this.config.actions,
|
||||
});
|
||||
this._validationErrors = (
|
||||
this.validationErrors = (
|
||||
Object.entries(validation) as Entries<typeof validation>
|
||||
).map(([key, value]) =>
|
||||
value.valid
|
||||
@@ -728,9 +669,9 @@ export class HaAutomationEditor extends PreventUnsavedMixin(
|
||||
this.hass,
|
||||
this.automationId as string
|
||||
);
|
||||
this._dirty = false;
|
||||
this._readOnly = false;
|
||||
this._config = normalizeAutomationConfig(config);
|
||||
this.dirty = false;
|
||||
this.readOnly = false;
|
||||
this.config = normalizeAutomationConfig(config);
|
||||
this._checkValidation();
|
||||
} catch (err: any) {
|
||||
const entity = this._entityRegistry.find(
|
||||
@@ -761,34 +702,27 @@ export class HaAutomationEditor extends PreventUnsavedMixin(
|
||||
private _valueChanged(ev: ValueChangedEvent<AutomationConfig>) {
|
||||
ev.stopPropagation();
|
||||
|
||||
if (this._config) {
|
||||
this._undoRedoController.commit(this._config);
|
||||
if (this.config) {
|
||||
this._undoRedoController.commit(this.config);
|
||||
}
|
||||
|
||||
this._config = ev.detail.value;
|
||||
if (this._readOnly) {
|
||||
this.config = ev.detail.value;
|
||||
if (this.readOnly) {
|
||||
return;
|
||||
}
|
||||
this._dirty = true;
|
||||
this._errors = undefined;
|
||||
this.dirty = true;
|
||||
this.errors = undefined;
|
||||
}
|
||||
|
||||
private _showInfo() {
|
||||
if (!this.hass || !this._entityId) {
|
||||
if (!this.hass || !this.currentEntityId) {
|
||||
return;
|
||||
}
|
||||
fireEvent(this, "hass-more-info", { entityId: this._entityId });
|
||||
}
|
||||
|
||||
private _showSettings() {
|
||||
showMoreInfoDialog(this, {
|
||||
entityId: this._entityId!,
|
||||
view: "settings",
|
||||
});
|
||||
fireEvent(this, "hass-more-info", { entityId: this.currentEntityId });
|
||||
}
|
||||
|
||||
private _editCategory() {
|
||||
if (!this._registryEntry) {
|
||||
if (!this.registryEntry) {
|
||||
showAlertDialog(this, {
|
||||
title: this.hass.localize(
|
||||
"ui.panel.config.scene.picker.no_category_support"
|
||||
@@ -801,36 +735,36 @@ export class HaAutomationEditor extends PreventUnsavedMixin(
|
||||
}
|
||||
showAssignCategoryDialog(this, {
|
||||
scope: "automation",
|
||||
entityReg: this._registryEntry,
|
||||
entityReg: this.registryEntry,
|
||||
});
|
||||
}
|
||||
|
||||
private async _showTrace() {
|
||||
if (this._config?.id) {
|
||||
const result = await this._confirmUnsavedChanged();
|
||||
if (this.config?.id) {
|
||||
const result = await this.confirmUnsavedChanged();
|
||||
if (result) {
|
||||
navigate(
|
||||
`/config/automation/trace/${encodeURIComponent(this._config.id)}`
|
||||
`/config/automation/trace/${encodeURIComponent(this.config.id)}`
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private _runActions() {
|
||||
if (!this.hass || !this._entityId) {
|
||||
if (!this.hass || !this.currentEntityId) {
|
||||
return;
|
||||
}
|
||||
triggerAutomationActions(
|
||||
this.hass,
|
||||
this.hass.states[this._entityId].entity_id
|
||||
this.hass.states[this.currentEntityId].entity_id
|
||||
);
|
||||
}
|
||||
|
||||
private async _toggle(): Promise<void> {
|
||||
if (!this.hass || !this._entityId) {
|
||||
if (!this.hass || !this.currentEntityId) {
|
||||
return;
|
||||
}
|
||||
const stateObj = this.hass.states[this._entityId];
|
||||
const stateObj = this.hass.states[this.currentEntityId];
|
||||
const service = stateObj.state === "off" ? "turn_on" : "turn_off";
|
||||
await this.hass.callService("automation", service, {
|
||||
entity_id: stateObj.entity_id,
|
||||
@@ -838,42 +772,42 @@ export class HaAutomationEditor extends PreventUnsavedMixin(
|
||||
}
|
||||
|
||||
private _preprocessYaml() {
|
||||
if (!this._config) {
|
||||
if (!this.config) {
|
||||
return {};
|
||||
}
|
||||
const cleanConfig: AutomationConfig = { ...this._config };
|
||||
const cleanConfig: AutomationConfig = { ...this.config };
|
||||
delete cleanConfig.id;
|
||||
return cleanConfig;
|
||||
}
|
||||
|
||||
private _yamlChanged(ev: CustomEvent) {
|
||||
ev.stopPropagation();
|
||||
this._dirty = true;
|
||||
this.dirty = true;
|
||||
if (!ev.detail.isValid) {
|
||||
this._yamlErrors = ev.detail.errorMsg;
|
||||
this.yamlErrors = ev.detail.errorMsg;
|
||||
return;
|
||||
}
|
||||
this._yamlErrors = undefined;
|
||||
this._config = {
|
||||
id: this._config?.id,
|
||||
this.yamlErrors = undefined;
|
||||
this.config = {
|
||||
id: this.config?.id,
|
||||
...normalizeAutomationConfig(ev.detail.value),
|
||||
};
|
||||
this._errors = undefined;
|
||||
this.errors = undefined;
|
||||
}
|
||||
|
||||
private async _confirmUnsavedChanged(): Promise<boolean> {
|
||||
if (!this._dirty) {
|
||||
protected async confirmUnsavedChanged(): Promise<boolean> {
|
||||
if (!this.dirty) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return new Promise<boolean>((resolve) => {
|
||||
showAutomationSaveDialog(this, {
|
||||
config: this._config!,
|
||||
config: this.config!,
|
||||
domain: "automation",
|
||||
updateConfig: async (config, entityRegistryUpdate) => {
|
||||
this._config = config;
|
||||
this._entityRegistryUpdate = entityRegistryUpdate;
|
||||
this._dirty = true;
|
||||
this.config = config;
|
||||
this.entityRegistryUpdate = entityRegistryUpdate;
|
||||
this.dirty = true;
|
||||
this.requestUpdate();
|
||||
|
||||
const id = this.automationId || String(Date.now());
|
||||
@@ -889,8 +823,8 @@ export class HaAutomationEditor extends PreventUnsavedMixin(
|
||||
},
|
||||
onClose: () => resolve(false),
|
||||
onDiscard: () => resolve(true),
|
||||
entityRegistryUpdate: this._entityRegistryUpdate,
|
||||
entityRegistryEntry: this._registryEntry,
|
||||
entityRegistryUpdate: this.entityRegistryUpdate,
|
||||
entityRegistryEntry: this.registryEntry,
|
||||
title: this.hass.localize(
|
||||
this.automationId
|
||||
? "ui.panel.config.automation.editor.leave.unsaved_confirm_title"
|
||||
@@ -906,15 +840,8 @@ export class HaAutomationEditor extends PreventUnsavedMixin(
|
||||
});
|
||||
}
|
||||
|
||||
private _backTapped = async () => {
|
||||
const result = await this._confirmUnsavedChanged();
|
||||
if (result) {
|
||||
afterNextRender(() => goBack("/config"));
|
||||
}
|
||||
};
|
||||
|
||||
private async _takeControl() {
|
||||
const config = this._config as BlueprintAutomationConfig;
|
||||
const config = this.config as BlueprintAutomationConfig;
|
||||
|
||||
try {
|
||||
const result = await substituteBlueprint(
|
||||
@@ -931,35 +858,20 @@ export class HaAutomationEditor extends PreventUnsavedMixin(
|
||||
description: config.description,
|
||||
};
|
||||
|
||||
this._blueprintConfig = config;
|
||||
this._config = newConfig;
|
||||
if (this._mode === "yaml") {
|
||||
this.renderRoot.querySelector("ha-yaml-editor")?.setValue(this._config);
|
||||
this.blueprintConfig = config;
|
||||
this.config = newConfig;
|
||||
if (this.mode === "yaml") {
|
||||
this.renderRoot.querySelector("ha-yaml-editor")?.setValue(this.config);
|
||||
}
|
||||
this._readOnly = true;
|
||||
this._errors = undefined;
|
||||
this.readOnly = true;
|
||||
this.errors = undefined;
|
||||
} catch (err: any) {
|
||||
this._errors = err.message;
|
||||
this.errors = err.message;
|
||||
}
|
||||
}
|
||||
|
||||
private _revertBlueprint() {
|
||||
this._config = this._blueprintConfig;
|
||||
if (this._mode === "yaml") {
|
||||
this.renderRoot.querySelector("ha-yaml-editor")?.setValue(this._config);
|
||||
}
|
||||
this._blueprintConfig = undefined;
|
||||
this._readOnly = false;
|
||||
}
|
||||
|
||||
private _takeControlSave() {
|
||||
this._readOnly = false;
|
||||
this._dirty = true;
|
||||
this._blueprintConfig = undefined;
|
||||
}
|
||||
|
||||
private async _duplicate() {
|
||||
const result = this._readOnly
|
||||
const result = this.readOnly
|
||||
? await showConfirmationDialog(this, {
|
||||
title: this.hass.localize(
|
||||
"ui.panel.config.automation.picker.migrate_automation"
|
||||
@@ -968,12 +880,12 @@ export class HaAutomationEditor extends PreventUnsavedMixin(
|
||||
"ui.panel.config.automation.picker.migrate_automation_description"
|
||||
),
|
||||
})
|
||||
: await this._confirmUnsavedChanged();
|
||||
: await this.confirmUnsavedChanged();
|
||||
if (result) {
|
||||
showAutomationEditor({
|
||||
...this._config,
|
||||
...this.config,
|
||||
id: undefined,
|
||||
alias: this._readOnly ? this._config?.alias : undefined,
|
||||
alias: this.readOnly ? this.config?.alias : undefined,
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -985,7 +897,7 @@ export class HaAutomationEditor extends PreventUnsavedMixin(
|
||||
),
|
||||
text: this.hass.localize(
|
||||
"ui.panel.config.automation.picker.delete_confirm_text",
|
||||
{ name: this._config?.alias }
|
||||
{ name: this.config?.alias }
|
||||
),
|
||||
confirmText: this.hass!.localize("ui.common.delete"),
|
||||
destructive: true,
|
||||
@@ -1001,43 +913,21 @@ export class HaAutomationEditor extends PreventUnsavedMixin(
|
||||
}
|
||||
}
|
||||
|
||||
private async _switchUiMode() {
|
||||
if (this._yamlErrors) {
|
||||
const result = await showConfirmationDialog(this, {
|
||||
text: html`${this.hass.localize(
|
||||
"ui.panel.config.automation.editor.switch_ui_yaml_error"
|
||||
)}<br /><br />${this._yamlErrors}`,
|
||||
confirmText: this.hass!.localize("ui.common.continue"),
|
||||
destructive: true,
|
||||
dismissText: this.hass!.localize("ui.common.cancel"),
|
||||
});
|
||||
if (!result) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
this._yamlErrors = undefined;
|
||||
this._mode = "gui";
|
||||
}
|
||||
|
||||
private _switchYamlMode() {
|
||||
this._mode = "yaml";
|
||||
}
|
||||
|
||||
private async _promptAutomationAlias(): Promise<boolean> {
|
||||
return new Promise((resolve) => {
|
||||
showAutomationSaveDialog(this, {
|
||||
config: this._config!,
|
||||
config: this.config!,
|
||||
domain: "automation",
|
||||
updateConfig: async (config, entityRegistryUpdate) => {
|
||||
this._config = config;
|
||||
this._entityRegistryUpdate = entityRegistryUpdate;
|
||||
this._dirty = true;
|
||||
this.config = config;
|
||||
this.entityRegistryUpdate = entityRegistryUpdate;
|
||||
this.dirty = true;
|
||||
this.requestUpdate();
|
||||
resolve(true);
|
||||
},
|
||||
onClose: () => resolve(false),
|
||||
entityRegistryUpdate: this._entityRegistryUpdate,
|
||||
entityRegistryEntry: this._registryEntry,
|
||||
entityRegistryUpdate: this.entityRegistryUpdate,
|
||||
entityRegistryEntry: this.registryEntry,
|
||||
});
|
||||
});
|
||||
}
|
||||
@@ -1045,10 +935,10 @@ export class HaAutomationEditor extends PreventUnsavedMixin(
|
||||
private async _promptAutomationMode(): Promise<void> {
|
||||
return new Promise((resolve) => {
|
||||
showAutomationModeDialog(this, {
|
||||
config: this._config!,
|
||||
config: this.config!,
|
||||
updateConfig: (config) => {
|
||||
this._config = config;
|
||||
this._dirty = true;
|
||||
this.config = config;
|
||||
this.dirty = true;
|
||||
this.requestUpdate();
|
||||
resolve();
|
||||
},
|
||||
@@ -1058,9 +948,9 @@ export class HaAutomationEditor extends PreventUnsavedMixin(
|
||||
}
|
||||
|
||||
private async _handleSaveAutomation(): Promise<void> {
|
||||
if (this._yamlErrors) {
|
||||
if (this.yamlErrors) {
|
||||
showToast(this, {
|
||||
message: this._yamlErrors,
|
||||
message: this.yamlErrors,
|
||||
});
|
||||
return;
|
||||
}
|
||||
@@ -1082,22 +972,22 @@ export class HaAutomationEditor extends PreventUnsavedMixin(
|
||||
}
|
||||
|
||||
private async _saveAutomation(id): Promise<void> {
|
||||
this._saving = true;
|
||||
this._validationErrors = undefined;
|
||||
this.saving = true;
|
||||
this.validationErrors = undefined;
|
||||
|
||||
let entityRegPromise: Promise<EntityRegistryEntry> | undefined;
|
||||
if (this._entityRegistryUpdate !== undefined && !this._entityId) {
|
||||
if (this.entityRegistryUpdate !== undefined && !this.currentEntityId) {
|
||||
this._newAutomationId = id;
|
||||
entityRegPromise = new Promise<EntityRegistryEntry>((resolve) => {
|
||||
this._entityRegCreated = resolve;
|
||||
this.entityRegCreated = resolve;
|
||||
});
|
||||
}
|
||||
|
||||
try {
|
||||
await saveAutomationConfig(this.hass, id, this._config!);
|
||||
await saveAutomationConfig(this.hass, id, this.config!);
|
||||
|
||||
if (this._entityRegistryUpdate !== undefined) {
|
||||
let entityId = this._entityId;
|
||||
if (this.entityRegistryUpdate !== undefined) {
|
||||
let entityId = this.currentEntityId;
|
||||
|
||||
// wait for automation to appear in entity registry when creating a new automation
|
||||
if (entityRegPromise) {
|
||||
@@ -1131,23 +1021,23 @@ export class HaAutomationEditor extends PreventUnsavedMixin(
|
||||
if (entityId) {
|
||||
await updateEntityRegistryEntry(this.hass, entityId, {
|
||||
categories: {
|
||||
automation: this._entityRegistryUpdate.category || null,
|
||||
automation: this.entityRegistryUpdate.category || null,
|
||||
},
|
||||
labels: this._entityRegistryUpdate.labels || [],
|
||||
area_id: this._entityRegistryUpdate.area || null,
|
||||
labels: this.entityRegistryUpdate.labels || [],
|
||||
area_id: this.entityRegistryUpdate.area || null,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
this._dirty = false;
|
||||
this.dirty = false;
|
||||
} catch (errors: any) {
|
||||
this._errors = errors.body?.message || errors.error || errors.body;
|
||||
this.errors = errors.body?.message || errors.error || errors.body;
|
||||
showToast(this, {
|
||||
message: errors.body?.message || errors.error || errors.body,
|
||||
});
|
||||
throw errors;
|
||||
} finally {
|
||||
this._saving = false;
|
||||
this.saving = false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1157,7 +1047,7 @@ export class HaAutomationEditor extends PreventUnsavedMixin(
|
||||
ev.detail.unsub = () => {
|
||||
delete this._configSubscriptions[id];
|
||||
};
|
||||
ev.detail.callback(this._config);
|
||||
ev.detail.callback(this.config);
|
||||
}
|
||||
|
||||
protected supportedShortcuts(): SupportedShortcuts {
|
||||
@@ -1173,14 +1063,6 @@ export class HaAutomationEditor extends PreventUnsavedMixin(
|
||||
};
|
||||
}
|
||||
|
||||
protected get isDirty() {
|
||||
return this._dirty;
|
||||
}
|
||||
|
||||
protected async promptDiscardChanges() {
|
||||
return this._confirmUnsavedChanged();
|
||||
}
|
||||
|
||||
// @ts-ignore
|
||||
private _collapseAll() {
|
||||
this._manualEditor?.collapseAll();
|
||||
@@ -1205,8 +1087,8 @@ export class HaAutomationEditor extends PreventUnsavedMixin(
|
||||
|
||||
private _applyUndoRedo(config: AutomationConfig) {
|
||||
this._manualEditor?.triggerCloseSidebar();
|
||||
this._config = config;
|
||||
this._dirty = true;
|
||||
this.config = config;
|
||||
this.dirty = true;
|
||||
}
|
||||
|
||||
private _undo() {
|
||||
@@ -1235,7 +1117,7 @@ export class HaAutomationEditor extends PreventUnsavedMixin(
|
||||
this._showInfo();
|
||||
break;
|
||||
case "settings":
|
||||
this._showSettings();
|
||||
this.showSettings();
|
||||
break;
|
||||
case "category":
|
||||
this._editCategory();
|
||||
@@ -1256,11 +1138,11 @@ export class HaAutomationEditor extends PreventUnsavedMixin(
|
||||
this._takeControl();
|
||||
break;
|
||||
case "toggle_yaml_mode":
|
||||
if (this._mode === "gui") {
|
||||
this._switchYamlMode();
|
||||
if (this.mode === "gui") {
|
||||
this.switchYamlMode();
|
||||
break;
|
||||
}
|
||||
this._switchUiMode();
|
||||
this.switchUiMode();
|
||||
break;
|
||||
case "disable":
|
||||
this._toggle();
|
||||
@@ -1277,25 +1159,8 @@ export class HaAutomationEditor extends PreventUnsavedMixin(
|
||||
static get styles(): CSSResultGroup {
|
||||
return [
|
||||
haStyle,
|
||||
automationScriptEditorStyles,
|
||||
css`
|
||||
:host {
|
||||
--ha-automation-editor-max-width: var(
|
||||
--ha-automation-editor-width,
|
||||
1540px
|
||||
);
|
||||
}
|
||||
ha-fade-in {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
height: 100%;
|
||||
}
|
||||
.yaml-mode {
|
||||
height: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
padding-bottom: 0;
|
||||
}
|
||||
manual-automation-editor,
|
||||
blueprint-automation-editor {
|
||||
margin: 0 auto;
|
||||
@@ -1309,17 +1174,6 @@ export class HaAutomationEditor extends PreventUnsavedMixin(
|
||||
padding: 0 12px;
|
||||
}
|
||||
|
||||
ha-yaml-editor {
|
||||
flex-grow: 1;
|
||||
--actions-border-radius: var(--ha-border-radius-square);
|
||||
--code-mirror-height: 100%;
|
||||
min-height: 0;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
p {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
ha-entity-toggle {
|
||||
margin-right: 8px;
|
||||
margin-inline-end: 8px;
|
||||
@@ -1335,24 +1189,6 @@ export class HaAutomationEditor extends PreventUnsavedMixin(
|
||||
max-width: 1040px;
|
||||
padding: 28px 20px 0;
|
||||
}
|
||||
ha-fab {
|
||||
position: fixed;
|
||||
right: calc(16px + var(--safe-area-inset-right, 0px));
|
||||
bottom: calc(-80px - var(--safe-area-inset-bottom));
|
||||
transition: bottom 0.3s;
|
||||
}
|
||||
ha-fab.dirty {
|
||||
bottom: calc(16px + var(--safe-area-inset-bottom, 0px));
|
||||
}
|
||||
ha-tooltip ha-svg-icon {
|
||||
width: 12px;
|
||||
}
|
||||
ha-tooltip .shortcut {
|
||||
display: inline-flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
gap: 2px;
|
||||
}
|
||||
`,
|
||||
];
|
||||
}
|
||||
|
||||
@@ -0,0 +1,199 @@
|
||||
import { consume } from "@lit/context";
|
||||
import type { CSSResult, TemplateResult, LitElement } from "lit";
|
||||
import { css, html } from "lit";
|
||||
import { property, state } from "lit/decorators";
|
||||
import { transform } from "../../../common/decorators/transform";
|
||||
import { goBack } from "../../../common/navigate";
|
||||
import { afterNextRender } from "../../../common/util/render-status";
|
||||
import { fullEntitiesContext } from "../../../data/context";
|
||||
import type { EntityRegistryEntry } from "../../../data/entity/entity_registry";
|
||||
import { showConfirmationDialog } from "../../../dialogs/generic/show-dialog-box";
|
||||
import { showMoreInfoDialog } from "../../../dialogs/more-info/show-ha-more-info-dialog";
|
||||
import type { Constructor, HomeAssistant, Route } from "../../../types";
|
||||
import type { EntityRegistryUpdate } from "./automation-save-dialog/show-dialog-automation-save";
|
||||
import "../../../components/ha-fade-in";
|
||||
import "../../../components/ha-spinner"; // used by renderLoading() provided to both editors
|
||||
|
||||
/** Minimum config shape shared by both AutomationConfig and ScriptConfig. */
|
||||
interface BaseEditorConfig {
|
||||
alias?: string;
|
||||
}
|
||||
|
||||
/** Shared CSS styles for both automation and script editors. */
|
||||
export const automationScriptEditorStyles: CSSResult = css`
|
||||
:host {
|
||||
--ha-automation-editor-max-width: var(--ha-automation-editor-width, 1540px);
|
||||
}
|
||||
ha-fade-in {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
height: 100%;
|
||||
}
|
||||
.yaml-mode {
|
||||
height: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
padding-bottom: 0;
|
||||
}
|
||||
ha-yaml-editor {
|
||||
flex-grow: 1;
|
||||
--actions-border-radius: var(--ha-border-radius-square);
|
||||
--code-mirror-height: 100%;
|
||||
min-height: 0;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
p {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
ha-fab {
|
||||
position: fixed;
|
||||
right: calc(16px + var(--safe-area-inset-right, 0px));
|
||||
bottom: calc(-80px - var(--safe-area-inset-bottom));
|
||||
transition: bottom 0.3s;
|
||||
}
|
||||
ha-fab.dirty {
|
||||
bottom: calc(16px + var(--safe-area-inset-bottom, 0px));
|
||||
}
|
||||
ha-tooltip ha-svg-icon {
|
||||
width: 12px;
|
||||
}
|
||||
ha-tooltip .shortcut {
|
||||
display: inline-flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
gap: 2px;
|
||||
}
|
||||
`;
|
||||
|
||||
export const AutomationScriptEditorMixin = <TConfig extends BaseEditorConfig>(
|
||||
superClass: Constructor<LitElement>
|
||||
) => {
|
||||
class AutomationScriptEditorClass extends superClass {
|
||||
@property({ attribute: false }) public hass!: HomeAssistant;
|
||||
|
||||
@property({ attribute: "is-wide", type: Boolean }) public isWide = false;
|
||||
|
||||
@property({ type: Boolean }) public narrow = false;
|
||||
|
||||
@property({ attribute: false }) public route!: Route;
|
||||
|
||||
@property({ attribute: false }) public entityId: string | null = null;
|
||||
|
||||
@state() protected dirty = false;
|
||||
|
||||
@state() protected errors?: string;
|
||||
|
||||
@state() protected yamlErrors?: string;
|
||||
|
||||
@state() protected currentEntityId?: string;
|
||||
|
||||
@state() protected mode: "gui" | "yaml" = "gui";
|
||||
|
||||
@state() protected readOnly = false;
|
||||
|
||||
@state() protected saving = false;
|
||||
|
||||
@state() protected validationErrors?: (string | TemplateResult)[];
|
||||
|
||||
@state() protected config?: TConfig;
|
||||
|
||||
@state() protected blueprintConfig?: TConfig;
|
||||
|
||||
@state()
|
||||
@consume({ context: fullEntitiesContext, subscribe: true })
|
||||
@transform<EntityRegistryEntry[], EntityRegistryEntry>({
|
||||
transformer: function (this: { currentEntityId?: string }, value) {
|
||||
return value.find(
|
||||
({ entity_id }) => entity_id === this.currentEntityId
|
||||
);
|
||||
},
|
||||
watch: ["currentEntityId"],
|
||||
})
|
||||
protected registryEntry?: EntityRegistryEntry;
|
||||
|
||||
protected entityRegistryUpdate?: EntityRegistryUpdate;
|
||||
|
||||
protected entityRegCreated?: (
|
||||
value: PromiseLike<EntityRegistryEntry> | EntityRegistryEntry
|
||||
) => void;
|
||||
|
||||
protected renderLoading(): TemplateResult {
|
||||
return html`
|
||||
<ha-fade-in .delay=${500}>
|
||||
<ha-spinner size="large"></ha-spinner>
|
||||
</ha-fade-in>
|
||||
`;
|
||||
}
|
||||
|
||||
protected showSettings() {
|
||||
showMoreInfoDialog(this, {
|
||||
entityId: this.currentEntityId!,
|
||||
view: "settings",
|
||||
});
|
||||
}
|
||||
|
||||
protected async switchUiMode() {
|
||||
if (this.yamlErrors) {
|
||||
const result = await showConfirmationDialog(this, {
|
||||
text: html`${this.hass.localize(
|
||||
"ui.panel.config.automation.editor.switch_ui_yaml_error"
|
||||
)}<br /><br />${this.yamlErrors}`,
|
||||
confirmText: this.hass!.localize("ui.common.continue"),
|
||||
destructive: true,
|
||||
dismissText: this.hass!.localize("ui.common.cancel"),
|
||||
});
|
||||
if (!result) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
this.yamlErrors = undefined;
|
||||
this.mode = "gui";
|
||||
}
|
||||
|
||||
protected switchYamlMode() {
|
||||
this.mode = "yaml";
|
||||
}
|
||||
|
||||
protected takeControlSave() {
|
||||
this.readOnly = false;
|
||||
this.dirty = true;
|
||||
this.blueprintConfig = undefined;
|
||||
}
|
||||
|
||||
protected revertBlueprint() {
|
||||
this.config = this.blueprintConfig;
|
||||
if (this.mode === "yaml") {
|
||||
this.renderRoot.querySelector("ha-yaml-editor")?.setValue(this.config);
|
||||
}
|
||||
this.blueprintConfig = undefined;
|
||||
this.readOnly = false;
|
||||
}
|
||||
|
||||
protected backTapped = async () => {
|
||||
const result = await this.confirmUnsavedChanged();
|
||||
if (result) {
|
||||
afterNextRender(() => goBack("/config"));
|
||||
}
|
||||
};
|
||||
|
||||
protected get isDirty() {
|
||||
return this.dirty;
|
||||
}
|
||||
|
||||
protected async promptDiscardChanges() {
|
||||
return this.confirmUnsavedChanged();
|
||||
}
|
||||
|
||||
/**
|
||||
* Asks whether unsaved changes should be discarded.
|
||||
* Subclasses must override this to show a confirmation dialog.
|
||||
* @returns true to proceed (discard/save changes), false to cancel.
|
||||
*/
|
||||
protected confirmUnsavedChanged(): Promise<boolean> {
|
||||
return Promise.resolve(true);
|
||||
}
|
||||
}
|
||||
return AutomationScriptEditorClass;
|
||||
};
|
||||
@@ -36,7 +36,7 @@ import { showQuickBar } from "../../../dialogs/quick-bar/show-dialog-quick-bar";
|
||||
import { showRestartDialog } from "../../../dialogs/restart/show-dialog-restart";
|
||||
import { showShortcutsDialog } from "../../../dialogs/shortcuts/show-shortcuts-dialog";
|
||||
import { SubscribeMixin } from "../../../mixins/subscribe-mixin";
|
||||
import { haStyle } from "../../../resources/styles";
|
||||
import { haStyle, haStyleScrollbar } from "../../../resources/styles";
|
||||
import type { HomeAssistant } from "../../../types";
|
||||
import { documentationUrl } from "../../../util/documentation-url";
|
||||
import { isMac } from "../../../util/is_mac";
|
||||
@@ -255,88 +255,90 @@ class HaConfigDashboard extends SubscribeMixin(LitElement) {
|
||||
</ha-dropdown-item>
|
||||
</ha-dropdown>
|
||||
|
||||
<ha-config-section
|
||||
.narrow=${this.narrow}
|
||||
.isWide=${this.isWide}
|
||||
full-width
|
||||
>
|
||||
${repairsIssues.length || canInstallUpdates.length
|
||||
? html`<ha-card outlined>
|
||||
${repairsIssues.length
|
||||
? html`
|
||||
<ha-config-repairs
|
||||
<div class="content ha-scrollbar">
|
||||
<ha-config-section
|
||||
.narrow=${this.narrow}
|
||||
.isWide=${this.isWide}
|
||||
full-width
|
||||
>
|
||||
${repairsIssues.length || canInstallUpdates.length
|
||||
? html`<ha-card outlined>
|
||||
${repairsIssues.length
|
||||
? html`
|
||||
<ha-config-repairs
|
||||
.hass=${this.hass}
|
||||
.narrow=${this.narrow}
|
||||
.total=${totalRepairIssues}
|
||||
.repairsIssues=${repairsIssues}
|
||||
></ha-config-repairs>
|
||||
${totalRepairIssues > repairsIssues.length
|
||||
? html`
|
||||
<ha-assist-chip
|
||||
href="/config/repairs"
|
||||
.label=${this.hass.localize(
|
||||
"ui.panel.config.repairs.more_repairs",
|
||||
{
|
||||
count:
|
||||
totalRepairIssues - repairsIssues.length,
|
||||
}
|
||||
)}
|
||||
>
|
||||
</ha-assist-chip>
|
||||
`
|
||||
: ""}
|
||||
`
|
||||
: ""}
|
||||
${repairsIssues.length && canInstallUpdates.length
|
||||
? html`<hr />`
|
||||
: ""}
|
||||
${canInstallUpdates.length
|
||||
? html`
|
||||
<ha-config-updates
|
||||
.hass=${this.hass}
|
||||
.narrow=${this.narrow}
|
||||
.total=${totalUpdates}
|
||||
.updateEntities=${canInstallUpdates}
|
||||
.isInstallable=${true}
|
||||
></ha-config-updates>
|
||||
${totalUpdates > canInstallUpdates.length
|
||||
? html`
|
||||
<ha-assist-chip
|
||||
href="/config/updates"
|
||||
label=${this.hass.localize(
|
||||
"ui.panel.config.updates.more_updates",
|
||||
{
|
||||
count:
|
||||
totalUpdates - canInstallUpdates.length,
|
||||
}
|
||||
)}
|
||||
>
|
||||
</ha-assist-chip>
|
||||
`
|
||||
: ""}
|
||||
`
|
||||
: ""}
|
||||
</ha-card>`
|
||||
: ""}
|
||||
${this._pages(
|
||||
this.cloudStatus,
|
||||
isComponentLoaded(this.hass, "cloud"),
|
||||
this.hass.auth.external?.config.hasSettingsScreen
|
||||
).map((categoryPages) =>
|
||||
categoryPages.length === 0
|
||||
? nothing
|
||||
: html`
|
||||
<ha-card outlined>
|
||||
<ha-config-navigation
|
||||
.hass=${this.hass}
|
||||
.narrow=${this.narrow}
|
||||
.total=${totalRepairIssues}
|
||||
.repairsIssues=${repairsIssues}
|
||||
></ha-config-repairs>
|
||||
${totalRepairIssues > repairsIssues.length
|
||||
? html`
|
||||
<ha-assist-chip
|
||||
href="/config/repairs"
|
||||
.label=${this.hass.localize(
|
||||
"ui.panel.config.repairs.more_repairs",
|
||||
{
|
||||
count:
|
||||
totalRepairIssues - repairsIssues.length,
|
||||
}
|
||||
)}
|
||||
>
|
||||
</ha-assist-chip>
|
||||
`
|
||||
: ""}
|
||||
`
|
||||
: ""}
|
||||
${repairsIssues.length && canInstallUpdates.length
|
||||
? html`<hr />`
|
||||
: ""}
|
||||
${canInstallUpdates.length
|
||||
? html`
|
||||
<ha-config-updates
|
||||
.hass=${this.hass}
|
||||
.narrow=${this.narrow}
|
||||
.total=${totalUpdates}
|
||||
.updateEntities=${canInstallUpdates}
|
||||
.isInstallable=${true}
|
||||
></ha-config-updates>
|
||||
${totalUpdates > canInstallUpdates.length
|
||||
? html`
|
||||
<ha-assist-chip
|
||||
href="/config/updates"
|
||||
label=${this.hass.localize(
|
||||
"ui.panel.config.updates.more_updates",
|
||||
{
|
||||
count:
|
||||
totalUpdates - canInstallUpdates.length,
|
||||
}
|
||||
)}
|
||||
>
|
||||
</ha-assist-chip>
|
||||
`
|
||||
: ""}
|
||||
`
|
||||
: ""}
|
||||
</ha-card>`
|
||||
: ""}
|
||||
${this._pages(
|
||||
this.cloudStatus,
|
||||
isComponentLoaded(this.hass, "cloud"),
|
||||
this.hass.auth.external?.config.hasSettingsScreen
|
||||
).map((categoryPages) =>
|
||||
categoryPages.length === 0
|
||||
? nothing
|
||||
: html`
|
||||
<ha-card outlined>
|
||||
<ha-config-navigation
|
||||
.hass=${this.hass}
|
||||
.narrow=${this.narrow}
|
||||
.pages=${categoryPages}
|
||||
></ha-config-navigation>
|
||||
</ha-card>
|
||||
`
|
||||
)}
|
||||
<ha-tip .hass=${this.hass}>${this._tip}</ha-tip>
|
||||
</ha-config-section>
|
||||
.pages=${categoryPages}
|
||||
></ha-config-navigation>
|
||||
</ha-card>
|
||||
`
|
||||
)}
|
||||
<ha-tip .hass=${this.hass}>${this._tip}</ha-tip>
|
||||
</ha-config-section>
|
||||
</div>
|
||||
</ha-top-app-bar-fixed>
|
||||
`;
|
||||
}
|
||||
@@ -392,7 +394,36 @@ class HaConfigDashboard extends SubscribeMixin(LitElement) {
|
||||
static get styles(): CSSResultGroup {
|
||||
return [
|
||||
haStyle,
|
||||
haStyleScrollbar,
|
||||
css`
|
||||
:host {
|
||||
display: block;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
ha-top-app-bar-fixed {
|
||||
height: 100%;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.content {
|
||||
height: calc(
|
||||
100vh - var(--header-height, 0px) - var(
|
||||
--safe-area-inset-top,
|
||||
0px
|
||||
) - var(--safe-area-inset-bottom, 0px)
|
||||
);
|
||||
height: calc(
|
||||
100dvh - var(--header-height, 0px) - var(
|
||||
--safe-area-inset-top,
|
||||
0px
|
||||
) - var(--safe-area-inset-bottom, 0px)
|
||||
);
|
||||
padding-bottom: var(--ha-space-5);
|
||||
box-sizing: border-box;
|
||||
overflow-x: hidden;
|
||||
}
|
||||
|
||||
:host(:not([narrow])) ha-card:last-child {
|
||||
margin-bottom: 24px;
|
||||
}
|
||||
|
||||
@@ -20,9 +20,9 @@ import "../../../../../components/ha-md-list-item";
|
||||
import "../../../../../components/ha-svg-icon";
|
||||
import type { ConfigEntry } from "../../../../../data/config_entries";
|
||||
import { getConfigEntries } from "../../../../../data/config_entries";
|
||||
import type { HomeAssistant } from "../../../../../types";
|
||||
import "../../../../../layouts/hass-subpage";
|
||||
import { haStyle } from "../../../../../resources/styles";
|
||||
import type { HomeAssistant } from "../../../../../types";
|
||||
|
||||
const THREAD_ICON =
|
||||
"m 17.126982,8.0730792 c 0,-0.7297242 -0.593746,-1.32357 -1.323637,-1.32357 -0.729454,0 -1.323199,0.5938458 -1.323199,1.32357 v 1.3234242 l 1.323199,1.458e-4 c 0.729891,0 1.323637,-0.5937006 1.323637,-1.32357 z M 11.999709,0 C 5.3829818,0 0,5.3838955 0,12.001455 0,18.574352 5.3105455,23.927406 11.865164,24 V 12.012075 l -3.9275642,-2.91e-4 c -1.1669814,0 -2.1169453,0.949979 -2.1169453,2.118323 0,1.16718 0.9499639,2.116868 2.1169453,2.116868 v 2.615717 c -2.6093089,0 -4.732218,-2.12327 -4.732218,-4.732585 0,-2.61048 2.1229091,-4.7343308 4.732218,-4.7343308 l 3.9275642,5.82e-4 v -1.323279 c 0,-2.172296 1.766691,-3.9395777 3.938181,-3.9395777 2.171928,0 3.9392,1.7672817 3.9392,3.9395777 0,2.1721498 -1.767272,3.9395768 -3.9392,3.9395768 l -1.323199,-1.45e-4 V 23.744102 C 19.911127,22.597726 24,17.768833 24,12.001455 24,5.3838955 18.616727,0 11.999709,0 Z";
|
||||
@@ -312,8 +312,7 @@ export class MatterConfigDashboard extends LitElement {
|
||||
}
|
||||
|
||||
.container {
|
||||
padding: var(--ha-space-2) var(--ha-space-4)
|
||||
calc(var(--ha-space-16) + var(--safe-area-inset-bottom, 0px));
|
||||
padding: var(--ha-space-2) var(--ha-space-4) var(--ha-space-4);
|
||||
}
|
||||
|
||||
a[slot="fab"] {
|
||||
|
||||
@@ -37,10 +37,10 @@ import {
|
||||
} from "../../../../../data/zha";
|
||||
import { showOptionsFlowDialog } from "../../../../../dialogs/config-flow/show-dialog-options-flow";
|
||||
import { showAlertDialog } from "../../../../../dialogs/generic/show-dialog-box";
|
||||
import { fileDownload } from "../../../../../util/file_download";
|
||||
import "../../../../../layouts/hass-subpage";
|
||||
import { haStyle } from "../../../../../resources/styles";
|
||||
import type { HomeAssistant, Route } from "../../../../../types";
|
||||
import { fileDownload } from "../../../../../util/file_download";
|
||||
|
||||
@customElement("zha-config-dashboard")
|
||||
class ZHAConfigDashboard extends LitElement {
|
||||
@@ -520,8 +520,7 @@ class ZHAConfigDashboard extends LitElement {
|
||||
}
|
||||
|
||||
.container {
|
||||
padding: var(--ha-space-2) var(--ha-space-4)
|
||||
calc(var(--ha-space-20) + var(--safe-area-inset-bottom, 0px));
|
||||
padding: var(--ha-space-2) var(--ha-space-4) var(--ha-space-4);
|
||||
}
|
||||
`,
|
||||
];
|
||||
|
||||
@@ -18,7 +18,6 @@ import type { UnsubscribeFunc } from "home-assistant-js-websocket";
|
||||
import type { CSSResultGroup, TemplateResult } from "lit";
|
||||
import { css, html, LitElement, nothing } from "lit";
|
||||
import { customElement, property, state } from "lit/decorators";
|
||||
import { goBack } from "../../../../../common/navigate";
|
||||
import "../../../../../components/ha-button";
|
||||
import "../../../../../components/ha-card";
|
||||
import "../../../../../components/ha-fab";
|
||||
@@ -29,6 +28,7 @@ import "../../../../../components/ha-md-list-item";
|
||||
import "../../../../../components/ha-progress-ring";
|
||||
import "../../../../../components/ha-spinner";
|
||||
import "../../../../../components/ha-svg-icon";
|
||||
import { goBack } from "../../../../../common/navigate";
|
||||
import type { ConfigEntry } from "../../../../../data/config_entries";
|
||||
import {
|
||||
ERROR_STATES,
|
||||
@@ -968,8 +968,7 @@ class ZWaveJSConfigDashboard extends SubscribeMixin(LitElement) {
|
||||
}
|
||||
|
||||
.container {
|
||||
padding: var(--ha-space-2) var(--ha-space-4)
|
||||
calc(var(--ha-space-16) + var(--safe-area-inset-bottom, 0px));
|
||||
padding: var(--ha-space-2) var(--ha-space-4) var(--ha-space-4);
|
||||
}
|
||||
`,
|
||||
];
|
||||
|
||||
@@ -86,7 +86,6 @@ class DialogSystemLogDetail extends LitElement {
|
||||
<ha-dialog
|
||||
.hass=${this.hass}
|
||||
.open=${this._open}
|
||||
width="large"
|
||||
@closed=${this._dialogClosed}
|
||||
>
|
||||
<span slot="headerTitle">${title}</span>
|
||||
|
||||
@@ -143,7 +143,8 @@ class HaConfigRepairs extends LitElement {
|
||||
}
|
||||
} else if (
|
||||
issue.domain === "vacuum" &&
|
||||
issue.translation_key === "segments_changed"
|
||||
(issue.translation_key === "segments_changed" ||
|
||||
issue.translation_key === "segments_mapping_not_configured")
|
||||
) {
|
||||
const data = await fetchRepairsIssueData(
|
||||
this.hass.connection,
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import "@home-assistant/webawesome/dist/components/divider/divider";
|
||||
import { consume } from "@lit/context";
|
||||
import {
|
||||
mdiAppleKeyboardCommand,
|
||||
mdiCog,
|
||||
@@ -22,15 +21,13 @@ import {
|
||||
} from "@mdi/js";
|
||||
import type { CSSResultGroup, PropertyValues, TemplateResult } from "lit";
|
||||
import { LitElement, css, html, nothing } from "lit";
|
||||
import { customElement, property, query, state } from "lit/decorators";
|
||||
import { customElement, property, query } from "lit/decorators";
|
||||
import { classMap } from "lit/directives/class-map";
|
||||
import { UndoRedoController } from "../../../common/controllers/undo-redo-controller";
|
||||
import { transform } from "../../../common/decorators/transform";
|
||||
import { fireEvent } from "../../../common/dom/fire_event";
|
||||
import { goBack, navigate } from "../../../common/navigate";
|
||||
import { slugify } from "../../../common/string/slugify";
|
||||
import { promiseTimeout } from "../../../common/util/promise-timeout";
|
||||
import { afterNextRender } from "../../../common/util/render-status";
|
||||
import "../../../components/ha-button";
|
||||
import "../../../components/ha-dropdown";
|
||||
import "../../../components/ha-dropdown-item";
|
||||
@@ -40,7 +37,6 @@ import "../../../components/ha-svg-icon";
|
||||
import "../../../components/ha-yaml-editor";
|
||||
import { substituteBlueprint } from "../../../data/blueprint";
|
||||
import { validateConfig } from "../../../data/config";
|
||||
import { fullEntitiesContext } from "../../../data/context";
|
||||
import { UNAVAILABLE } from "../../../data/entity/entity";
|
||||
import {
|
||||
type EntityRegistryEntry,
|
||||
@@ -67,88 +63,47 @@ import { KeyboardShortcutMixin } from "../../../mixins/keyboard-shortcut-mixin";
|
||||
import { PreventUnsavedMixin } from "../../../mixins/prevent-unsaved-mixin";
|
||||
import { SubscribeMixin } from "../../../mixins/subscribe-mixin";
|
||||
import { haStyle } from "../../../resources/styles";
|
||||
import type { Entries, HomeAssistant, Route } from "../../../types";
|
||||
import type { Entries } from "../../../types";
|
||||
import { isMac } from "../../../util/is_mac";
|
||||
import { showToast } from "../../../util/toast";
|
||||
import { showAutomationModeDialog } from "../automation/automation-mode-dialog/show-dialog-automation-mode";
|
||||
import type { EntityRegistryUpdate } from "../automation/automation-save-dialog/show-dialog-automation-save";
|
||||
import { showAutomationSaveDialog } from "../automation/automation-save-dialog/show-dialog-automation-save";
|
||||
import { showAutomationSaveTimeoutDialog } from "../automation/automation-save-timeout-dialog/show-dialog-automation-save-timeout";
|
||||
import { showAssignCategoryDialog } from "../category/show-dialog-assign-category";
|
||||
import "./blueprint-script-editor";
|
||||
import {
|
||||
AutomationScriptEditorMixin,
|
||||
automationScriptEditorStyles,
|
||||
} from "../automation/ha-automation-script-editor-mixin";
|
||||
import "./manual-script-editor";
|
||||
import type { HaManualScriptEditor } from "./manual-script-editor";
|
||||
import type { HaDropdownSelectEvent } from "../../../components/ha-dropdown";
|
||||
|
||||
@customElement("ha-script-editor")
|
||||
export class HaScriptEditor extends SubscribeMixin(
|
||||
PreventUnsavedMixin(KeyboardShortcutMixin(LitElement))
|
||||
AutomationScriptEditorMixin<ScriptConfig>(
|
||||
PreventUnsavedMixin(KeyboardShortcutMixin(LitElement))
|
||||
)
|
||||
) {
|
||||
@property({ attribute: false }) public hass!: HomeAssistant;
|
||||
|
||||
@property({ attribute: false }) public scriptId: string | null = null;
|
||||
|
||||
@property({ attribute: false }) public entityId: string | null = null;
|
||||
|
||||
@property({ attribute: false }) public entityRegistry!: EntityRegistryEntry[];
|
||||
|
||||
@property({ attribute: "is-wide", type: Boolean }) public isWide = false;
|
||||
|
||||
@property({ type: Boolean }) public narrow = false;
|
||||
|
||||
@property({ attribute: false }) public route!: Route;
|
||||
|
||||
@state() private _config?: ScriptConfig;
|
||||
|
||||
@state() private _dirty = false;
|
||||
|
||||
@state() private _errors?: string;
|
||||
|
||||
@state() private _yamlErrors?: string;
|
||||
|
||||
@state() private _entityId?: string;
|
||||
|
||||
@state() private _mode: "gui" | "yaml" = "gui";
|
||||
|
||||
@state() private _readOnly = false;
|
||||
|
||||
@state()
|
||||
@consume({ context: fullEntitiesContext, subscribe: true })
|
||||
@transform<EntityRegistryEntry[], EntityRegistryEntry>({
|
||||
transformer: function (this: HaScriptEditor, value) {
|
||||
return value.find(({ entity_id }) => entity_id === this._entityId);
|
||||
},
|
||||
watch: ["_entityId"],
|
||||
})
|
||||
private _registryEntry?: EntityRegistryEntry;
|
||||
|
||||
@query("manual-script-editor")
|
||||
private _manualEditor?: HaManualScriptEditor;
|
||||
|
||||
@state() private _validationErrors?: (string | TemplateResult)[];
|
||||
|
||||
@state() private _blueprintConfig?: BlueprintScriptConfig;
|
||||
|
||||
@state() private _saving = false;
|
||||
|
||||
private _entityRegistryUpdate?: EntityRegistryUpdate;
|
||||
|
||||
private _newScriptId?: string;
|
||||
|
||||
private _entityRegCreated?: (
|
||||
value: PromiseLike<EntityRegistryEntry> | EntityRegistryEntry
|
||||
) => void;
|
||||
|
||||
private _undoRedoController = new UndoRedoController<ScriptConfig>(this, {
|
||||
apply: (config) => this._applyUndoRedo(config),
|
||||
currentConfig: () => this._config!,
|
||||
currentConfig: () => this.config!,
|
||||
});
|
||||
|
||||
protected willUpdate(changedProps) {
|
||||
super.willUpdate(changedProps);
|
||||
|
||||
if (
|
||||
this._entityRegCreated &&
|
||||
this.entityRegCreated &&
|
||||
this._newScriptId &&
|
||||
changedProps.has("entityRegistry")
|
||||
) {
|
||||
@@ -157,22 +112,22 @@ export class HaScriptEditor extends SubscribeMixin(
|
||||
entity.platform === "script" && entity.unique_id === this._newScriptId
|
||||
);
|
||||
if (script) {
|
||||
this._entityRegCreated(script);
|
||||
this._entityRegCreated = undefined;
|
||||
this.entityRegCreated(script);
|
||||
this.entityRegCreated = undefined;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected render(): TemplateResult | typeof nothing {
|
||||
if (!this._config) {
|
||||
return nothing;
|
||||
if (!this.config) {
|
||||
return this.renderLoading();
|
||||
}
|
||||
|
||||
const stateObj = this._entityId
|
||||
? this.hass.states[this._entityId]
|
||||
const stateObj = this.currentEntityId
|
||||
? this.hass.states[this.currentEntityId]
|
||||
: undefined;
|
||||
|
||||
const useBlueprint = "use_blueprint" in this._config;
|
||||
const useBlueprint = "use_blueprint" in this.config;
|
||||
const shortcutIcon = isMac
|
||||
? html`<ha-svg-icon .path=${mdiAppleKeyboardCommand}></ha-svg-icon>`
|
||||
: this.hass.localize("ui.panel.config.automation.editor.ctrl");
|
||||
@@ -182,11 +137,11 @@ export class HaScriptEditor extends SubscribeMixin(
|
||||
.hass=${this.hass}
|
||||
.narrow=${this.narrow}
|
||||
.route=${this.route}
|
||||
.backCallback=${this._backTapped}
|
||||
.header=${this._config.alias ||
|
||||
.backCallback=${this.backTapped}
|
||||
.header=${this.config.alias ||
|
||||
this.hass.localize("ui.panel.config.script.editor.default_name")}
|
||||
>
|
||||
${this._mode === "gui" && !this.narrow
|
||||
${this.mode === "gui" && !this.narrow
|
||||
? html`<ha-icon-button
|
||||
slot="toolbar-icon"
|
||||
.label=${this.hass.localize("ui.common.undo")}
|
||||
@@ -252,7 +207,7 @@ export class HaScriptEditor extends SubscribeMixin(
|
||||
.path=${mdiDotsVertical}
|
||||
></ha-icon-button>
|
||||
|
||||
${this._mode === "gui" && this.narrow
|
||||
${this.mode === "gui" && this.narrow
|
||||
? html`<ha-dropdown-item
|
||||
value="undo"
|
||||
.disabled=${!this._undoRedoController.canUndo}
|
||||
@@ -286,7 +241,7 @@ export class HaScriptEditor extends SubscribeMixin(
|
||||
|
||||
<ha-dropdown-item .disabled=${!stateObj} value="category">
|
||||
${this.hass.localize(
|
||||
`ui.panel.config.scene.picker.${this._registryEntry?.categories?.script ? "edit_category" : "assign_category"}`
|
||||
`ui.panel.config.scene.picker.${this.registryEntry?.categories?.script ? "edit_category" : "assign_category"}`
|
||||
)}
|
||||
<ha-svg-icon slot="icon" .path=${mdiTag}></ha-svg-icon>
|
||||
</ha-dropdown-item>
|
||||
@@ -307,10 +262,10 @@ export class HaScriptEditor extends SubscribeMixin(
|
||||
></ha-svg-icon>
|
||||
</ha-dropdown-item>`
|
||||
: nothing}
|
||||
${!useBlueprint && !("fields" in this._config)
|
||||
${!useBlueprint && !("fields" in this.config)
|
||||
? html`
|
||||
<ha-dropdown-item
|
||||
.disabled=${this._readOnly || this._mode === "yaml"}
|
||||
.disabled=${this.readOnly || this.mode === "yaml"}
|
||||
value="add_fields"
|
||||
>
|
||||
${this.hass.localize(
|
||||
@@ -326,9 +281,7 @@ export class HaScriptEditor extends SubscribeMixin(
|
||||
|
||||
<ha-dropdown-item
|
||||
value="rename"
|
||||
.disabled=${!this.scriptId ||
|
||||
this._readOnly ||
|
||||
this._mode === "yaml"}
|
||||
.disabled=${!this.scriptId || this.readOnly || this.mode === "yaml"}
|
||||
>
|
||||
${this.hass.localize("ui.panel.config.script.editor.rename")}
|
||||
<ha-svg-icon slot="icon" .path=${mdiRenameBox}></ha-svg-icon>
|
||||
@@ -337,7 +290,7 @@ export class HaScriptEditor extends SubscribeMixin(
|
||||
? html`
|
||||
<ha-dropdown-item
|
||||
value="change_mode"
|
||||
.disabled=${this._readOnly || this._mode === "yaml"}
|
||||
.disabled=${this.readOnly || this.mode === "yaml"}
|
||||
>
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.script.editor.change_mode"
|
||||
@@ -351,12 +304,12 @@ export class HaScriptEditor extends SubscribeMixin(
|
||||
: nothing}
|
||||
|
||||
<ha-dropdown-item
|
||||
.disabled=${!!this._blueprintConfig ||
|
||||
(!this._readOnly && !this.scriptId)}
|
||||
.disabled=${!!this.blueprintConfig ||
|
||||
(!this.readOnly && !this.scriptId)}
|
||||
value="duplicate"
|
||||
>
|
||||
${this.hass.localize(
|
||||
this._readOnly
|
||||
this.readOnly
|
||||
? "ui.panel.config.script.editor.migrate"
|
||||
: "ui.panel.config.script.editor.duplicate"
|
||||
)}
|
||||
@@ -370,7 +323,7 @@ export class HaScriptEditor extends SubscribeMixin(
|
||||
? html`
|
||||
<ha-dropdown-item
|
||||
value="take_control"
|
||||
.disabled=${this._readOnly}
|
||||
.disabled=${this.readOnly}
|
||||
>
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.script.editor.take_control"
|
||||
@@ -382,7 +335,7 @@ export class HaScriptEditor extends SubscribeMixin(
|
||||
|
||||
<ha-dropdown-item value="toggle_yaml_mode">
|
||||
${this.hass.localize(
|
||||
`ui.panel.config.automation.editor.edit_${this._mode === "gui" ? "yaml" : "ui"}`
|
||||
`ui.panel.config.automation.editor.edit_${this.mode === "gui" ? "yaml" : "ui"}`
|
||||
)}
|
||||
<ha-svg-icon slot="icon" .path=${mdiPlaylistEdit}></ha-svg-icon>
|
||||
</ha-dropdown-item>
|
||||
@@ -390,7 +343,7 @@ export class HaScriptEditor extends SubscribeMixin(
|
||||
<wa-divider></wa-divider>
|
||||
|
||||
<ha-dropdown-item
|
||||
.disabled=${this._readOnly || !this.scriptId}
|
||||
.disabled=${this.readOnly || !this.scriptId}
|
||||
value="delete"
|
||||
.variant=${this.scriptId ? "danger" : "default"}
|
||||
>
|
||||
@@ -403,8 +356,8 @@ export class HaScriptEditor extends SubscribeMixin(
|
||||
</ha-svg-icon>
|
||||
</ha-dropdown-item>
|
||||
</ha-dropdown>
|
||||
<div class=${this._mode === "yaml" ? "yaml-mode" : ""}>
|
||||
${this._mode === "gui"
|
||||
<div class=${this.mode === "yaml" ? "yaml-mode" : ""}>
|
||||
${this.mode === "gui"
|
||||
? html`
|
||||
<div>
|
||||
${useBlueprint
|
||||
@@ -413,10 +366,10 @@ export class HaScriptEditor extends SubscribeMixin(
|
||||
.hass=${this.hass}
|
||||
.narrow=${this.narrow}
|
||||
.isWide=${this.isWide}
|
||||
.config=${this._config}
|
||||
.disabled=${this._readOnly}
|
||||
.saving=${this._saving}
|
||||
.dirty=${this._dirty}
|
||||
.config=${this.config}
|
||||
.disabled=${this.readOnly}
|
||||
.saving=${this.saving}
|
||||
.dirty=${this.dirty}
|
||||
@value-changed=${this._valueChanged}
|
||||
@save-script=${this._handleSaveScript}
|
||||
></blueprint-script-editor>
|
||||
@@ -426,16 +379,16 @@ export class HaScriptEditor extends SubscribeMixin(
|
||||
.hass=${this.hass}
|
||||
.narrow=${this.narrow}
|
||||
.isWide=${this.isWide}
|
||||
.config=${this._config}
|
||||
.disabled=${this._readOnly}
|
||||
.dirty=${this._dirty}
|
||||
.saving=${this._saving}
|
||||
.config=${this.config}
|
||||
.disabled=${this.readOnly}
|
||||
.dirty=${this.dirty}
|
||||
.saving=${this.saving}
|
||||
@value-changed=${this._valueChanged}
|
||||
@editor-save=${this._handleSaveScript}
|
||||
@save-script=${this._handleSaveScript}
|
||||
>
|
||||
<div class="alert-wrapper" slot="alerts">
|
||||
${this._errors || stateObj?.state === UNAVAILABLE
|
||||
${this.errors || stateObj?.state === UNAVAILABLE
|
||||
? html`<ha-alert
|
||||
alert-type="error"
|
||||
.title=${stateObj?.state === UNAVAILABLE
|
||||
@@ -444,7 +397,7 @@ export class HaScriptEditor extends SubscribeMixin(
|
||||
)
|
||||
: undefined}
|
||||
>
|
||||
${this._errors || this._validationErrors}
|
||||
${this.errors || this.validationErrors}
|
||||
${stateObj?.state === UNAVAILABLE
|
||||
? html`<ha-svg-icon
|
||||
slot="icon"
|
||||
@@ -453,7 +406,7 @@ export class HaScriptEditor extends SubscribeMixin(
|
||||
: nothing}
|
||||
</ha-alert>`
|
||||
: nothing}
|
||||
${this._blueprintConfig
|
||||
${this.blueprintConfig
|
||||
? html`<ha-alert alert-type="info">
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.script.editor.confirm_take_control"
|
||||
@@ -461,21 +414,21 @@ export class HaScriptEditor extends SubscribeMixin(
|
||||
<div slot="action" style="display: flex;">
|
||||
<ha-button
|
||||
appearance="plain"
|
||||
@click=${this._takeControlSave}
|
||||
@click=${this.takeControlSave}
|
||||
>${this.hass.localize(
|
||||
"ui.common.yes"
|
||||
)}</ha-button
|
||||
>
|
||||
<ha-button
|
||||
appearance="plain"
|
||||
@click=${this._revertBlueprint}
|
||||
@click=${this.revertBlueprint}
|
||||
>${this.hass.localize(
|
||||
"ui.common.no"
|
||||
)}</ha-button
|
||||
>
|
||||
</div>
|
||||
</ha-alert>`
|
||||
: this._readOnly
|
||||
: this.readOnly
|
||||
? html`<ha-alert
|
||||
alert-type="warning"
|
||||
dismissable
|
||||
@@ -498,11 +451,11 @@ export class HaScriptEditor extends SubscribeMixin(
|
||||
`}
|
||||
</div>
|
||||
`
|
||||
: this._mode === "yaml"
|
||||
: this.mode === "yaml"
|
||||
? html`<ha-yaml-editor
|
||||
.hass=${this.hass}
|
||||
.defaultValue=${this._preprocessYaml()}
|
||||
.readOnly=${this._readOnly}
|
||||
.readOnly=${this.readOnly}
|
||||
disable-fullscreen
|
||||
@value-changed=${this._yamlChanged}
|
||||
@editor-save=${this._handleSaveScript}
|
||||
@@ -510,9 +463,9 @@ export class HaScriptEditor extends SubscribeMixin(
|
||||
></ha-yaml-editor>
|
||||
<ha-fab
|
||||
slot="fab"
|
||||
class=${!this._readOnly && this._dirty ? "dirty" : ""}
|
||||
class=${!this.readOnly && this.dirty ? "dirty" : ""}
|
||||
.label=${this.hass.localize("ui.common.save")}
|
||||
.disabled=${this._saving}
|
||||
.disabled=${this.saving}
|
||||
extended
|
||||
@click=${this._handleSaveScript}
|
||||
>
|
||||
@@ -551,26 +504,26 @@ export class HaScriptEditor extends SubscribeMixin(
|
||||
const entity = this.entityRegistry.find(
|
||||
(ent) => ent.platform === "script" && ent.unique_id === this.scriptId
|
||||
);
|
||||
this._entityId = entity?.entity_id;
|
||||
this.currentEntityId = entity?.entity_id;
|
||||
}
|
||||
|
||||
if (changedProps.has("scriptId") && !this.scriptId && this.hass) {
|
||||
const initData = getScriptEditorInitData();
|
||||
this._dirty = !!initData;
|
||||
this.dirty = !!initData;
|
||||
const baseConfig: Partial<ScriptConfig> = {};
|
||||
if (!initData || !("use_blueprint" in initData)) {
|
||||
baseConfig.sequence = [];
|
||||
}
|
||||
this._config = {
|
||||
this.config = {
|
||||
...baseConfig,
|
||||
...initData,
|
||||
} as ScriptConfig;
|
||||
this._readOnly = false;
|
||||
this.readOnly = false;
|
||||
}
|
||||
|
||||
if (changedProps.has("entityId") && this.entityId) {
|
||||
getScriptStateConfig(this.hass, this.entityId).then((c) => {
|
||||
this._config = normalizeScriptConfig(c.config);
|
||||
this.config = normalizeScriptConfig(c.config);
|
||||
this._checkValidation();
|
||||
});
|
||||
const regEntry = this.entityRegistry.find(
|
||||
@@ -579,25 +532,25 @@ export class HaScriptEditor extends SubscribeMixin(
|
||||
if (regEntry?.unique_id) {
|
||||
this.scriptId = regEntry.unique_id;
|
||||
}
|
||||
this._entityId = this.entityId;
|
||||
this._dirty = false;
|
||||
this._readOnly = true;
|
||||
this.currentEntityId = this.entityId;
|
||||
this.dirty = false;
|
||||
this.readOnly = true;
|
||||
}
|
||||
}
|
||||
|
||||
private async _checkValidation() {
|
||||
this._validationErrors = undefined;
|
||||
if (!this._entityId || !this._config) {
|
||||
this.validationErrors = undefined;
|
||||
if (!this.currentEntityId || !this.config) {
|
||||
return;
|
||||
}
|
||||
const stateObj = this.hass.states[this._entityId];
|
||||
const stateObj = this.hass.states[this.currentEntityId];
|
||||
if (stateObj?.state !== UNAVAILABLE) {
|
||||
return;
|
||||
}
|
||||
const validation = await validateConfig(this.hass, {
|
||||
actions: this._config.sequence,
|
||||
actions: this.config.sequence,
|
||||
});
|
||||
this._validationErrors = (
|
||||
this.validationErrors = (
|
||||
Object.entries(validation) as Entries<typeof validation>
|
||||
).map(([key, value]) =>
|
||||
value.valid
|
||||
@@ -612,13 +565,13 @@ export class HaScriptEditor extends SubscribeMixin(
|
||||
private async _loadConfig() {
|
||||
fetchScriptFileConfig(this.hass, this.scriptId!).then(
|
||||
(config) => {
|
||||
this._dirty = false;
|
||||
this._readOnly = false;
|
||||
this._config = normalizeScriptConfig(config);
|
||||
this.dirty = false;
|
||||
this.readOnly = false;
|
||||
this.config = normalizeScriptConfig(config);
|
||||
const entity = this.entityRegistry.find(
|
||||
(ent) => ent.platform === "script" && ent.unique_id === this.scriptId
|
||||
);
|
||||
this._entityId = entity?.entity_id;
|
||||
this.currentEntityId = entity?.entity_id;
|
||||
this._checkValidation();
|
||||
},
|
||||
(resp) => {
|
||||
@@ -647,19 +600,19 @@ export class HaScriptEditor extends SubscribeMixin(
|
||||
}
|
||||
|
||||
private _valueChanged(ev) {
|
||||
if (this._config) {
|
||||
this._undoRedoController.commit(this._config);
|
||||
if (this.config) {
|
||||
this._undoRedoController.commit(this.config);
|
||||
}
|
||||
|
||||
this._config = ev.detail.value;
|
||||
this._errors = undefined;
|
||||
this._dirty = true;
|
||||
this.config = ev.detail.value;
|
||||
this.errors = undefined;
|
||||
this.dirty = true;
|
||||
}
|
||||
|
||||
private async _runScript() {
|
||||
if (hasScriptFields(this.hass, this._entityId!)) {
|
||||
if (hasScriptFields(this.hass, this.currentEntityId!)) {
|
||||
showMoreInfoDialog(this, {
|
||||
entityId: this._entityId!,
|
||||
entityId: this.currentEntityId!,
|
||||
});
|
||||
return;
|
||||
}
|
||||
@@ -667,20 +620,13 @@ export class HaScriptEditor extends SubscribeMixin(
|
||||
await triggerScript(this.hass, this.scriptId!);
|
||||
showToast(this, {
|
||||
message: this.hass.localize("ui.notification_toast.triggered", {
|
||||
name: this._config!.alias,
|
||||
name: this.config!.alias,
|
||||
}),
|
||||
});
|
||||
}
|
||||
|
||||
private _showSettings() {
|
||||
showMoreInfoDialog(this, {
|
||||
entityId: this._entityId!,
|
||||
view: "settings",
|
||||
});
|
||||
}
|
||||
|
||||
private _editCategory() {
|
||||
if (!this._registryEntry) {
|
||||
if (!this.registryEntry) {
|
||||
showAlertDialog(this, {
|
||||
title: this.hass.localize(
|
||||
"ui.panel.config.scene.picker.no_category_support"
|
||||
@@ -693,7 +639,7 @@ export class HaScriptEditor extends SubscribeMixin(
|
||||
}
|
||||
showAssignCategoryDialog(this, {
|
||||
scope: "script",
|
||||
entityReg: this._registryEntry,
|
||||
entityReg: this.registryEntry,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -730,7 +676,7 @@ export class HaScriptEditor extends SubscribeMixin(
|
||||
|
||||
private async _showTrace() {
|
||||
if (this.scriptId) {
|
||||
const result = await this._confirmUnsavedChanged();
|
||||
const result = await this.confirmUnsavedChanged();
|
||||
if (result) {
|
||||
navigate(`/config/script/trace/${this.scriptId}`);
|
||||
}
|
||||
@@ -738,47 +684,47 @@ export class HaScriptEditor extends SubscribeMixin(
|
||||
}
|
||||
|
||||
private _addFields() {
|
||||
if ("fields" in this._config!) {
|
||||
if ("fields" in this.config!) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (this._config) {
|
||||
this._undoRedoController.commit(this._config);
|
||||
if (this.config) {
|
||||
this._undoRedoController.commit(this.config);
|
||||
}
|
||||
|
||||
this._manualEditor?.addFields();
|
||||
this._dirty = true;
|
||||
this.dirty = true;
|
||||
}
|
||||
|
||||
private _preprocessYaml() {
|
||||
return this._config;
|
||||
return this.config;
|
||||
}
|
||||
|
||||
private _yamlChanged(ev: CustomEvent) {
|
||||
ev.stopPropagation();
|
||||
this._dirty = true;
|
||||
this.dirty = true;
|
||||
if (!ev.detail.isValid) {
|
||||
this._yamlErrors = ev.detail.errorMsg;
|
||||
this.yamlErrors = ev.detail.errorMsg;
|
||||
return;
|
||||
}
|
||||
this._yamlErrors = undefined;
|
||||
this._config = ev.detail.value;
|
||||
this._errors = undefined;
|
||||
this.yamlErrors = undefined;
|
||||
this.config = ev.detail.value;
|
||||
this.errors = undefined;
|
||||
}
|
||||
|
||||
private async _confirmUnsavedChanged(): Promise<boolean> {
|
||||
if (!this._dirty) {
|
||||
protected async confirmUnsavedChanged(): Promise<boolean> {
|
||||
if (!this.dirty) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return new Promise<boolean>((resolve) => {
|
||||
showAutomationSaveDialog(this, {
|
||||
config: this._config!,
|
||||
config: this.config!,
|
||||
domain: "script",
|
||||
updateConfig: async (config, entityRegistryUpdate) => {
|
||||
this._config = config;
|
||||
this._entityRegistryUpdate = entityRegistryUpdate;
|
||||
this._dirty = true;
|
||||
this.config = config;
|
||||
this.entityRegistryUpdate = entityRegistryUpdate;
|
||||
this.dirty = true;
|
||||
this.requestUpdate();
|
||||
|
||||
const id = this.scriptId || String(Date.now());
|
||||
@@ -794,8 +740,8 @@ export class HaScriptEditor extends SubscribeMixin(
|
||||
},
|
||||
onClose: () => resolve(false),
|
||||
onDiscard: () => resolve(true),
|
||||
entityRegistryUpdate: this._entityRegistryUpdate,
|
||||
entityRegistryEntry: this._registryEntry,
|
||||
entityRegistryUpdate: this.entityRegistryUpdate,
|
||||
entityRegistryEntry: this.registryEntry,
|
||||
title: this.hass.localize(
|
||||
this.scriptId
|
||||
? "ui.panel.config.script.editor.leave.unsaved_confirm_title"
|
||||
@@ -811,15 +757,8 @@ export class HaScriptEditor extends SubscribeMixin(
|
||||
});
|
||||
}
|
||||
|
||||
private _backTapped = async () => {
|
||||
const result = await this._confirmUnsavedChanged();
|
||||
if (result) {
|
||||
afterNextRender(() => goBack("/config"));
|
||||
}
|
||||
};
|
||||
|
||||
private async _takeControl() {
|
||||
const config = this._config as BlueprintScriptConfig;
|
||||
const config = this.config as BlueprintScriptConfig;
|
||||
|
||||
try {
|
||||
const result = await substituteBlueprint(
|
||||
@@ -835,35 +774,20 @@ export class HaScriptEditor extends SubscribeMixin(
|
||||
description: config.description,
|
||||
};
|
||||
|
||||
this._blueprintConfig = config;
|
||||
this._config = newConfig;
|
||||
if (this._mode === "yaml") {
|
||||
this.renderRoot.querySelector("ha-yaml-editor")?.setValue(this._config);
|
||||
this.blueprintConfig = config;
|
||||
this.config = newConfig;
|
||||
if (this.mode === "yaml") {
|
||||
this.renderRoot.querySelector("ha-yaml-editor")?.setValue(this.config);
|
||||
}
|
||||
this._readOnly = true;
|
||||
this._errors = undefined;
|
||||
this.readOnly = true;
|
||||
this.errors = undefined;
|
||||
} catch (err: any) {
|
||||
this._errors = err.message;
|
||||
this.errors = err.message;
|
||||
}
|
||||
}
|
||||
|
||||
private _revertBlueprint() {
|
||||
this._config = this._blueprintConfig;
|
||||
if (this._mode === "yaml") {
|
||||
this.renderRoot.querySelector("ha-yaml-editor")?.setValue(this._config);
|
||||
}
|
||||
this._blueprintConfig = undefined;
|
||||
this._readOnly = false;
|
||||
}
|
||||
|
||||
private _takeControlSave() {
|
||||
this._readOnly = false;
|
||||
this._dirty = true;
|
||||
this._blueprintConfig = undefined;
|
||||
}
|
||||
|
||||
private async _duplicate() {
|
||||
const result = this._readOnly
|
||||
const result = this.readOnly
|
||||
? await showConfirmationDialog(this, {
|
||||
title: this.hass.localize(
|
||||
"ui.panel.config.script.picker.migrate_script"
|
||||
@@ -872,14 +796,14 @@ export class HaScriptEditor extends SubscribeMixin(
|
||||
"ui.panel.config.script.picker.migrate_script_description"
|
||||
),
|
||||
})
|
||||
: await this._confirmUnsavedChanged();
|
||||
: await this.confirmUnsavedChanged();
|
||||
if (result) {
|
||||
this._entityId = undefined;
|
||||
this.currentEntityId = undefined;
|
||||
showScriptEditor({
|
||||
...this._config,
|
||||
alias: this._readOnly
|
||||
? this._config?.alias
|
||||
: `${this._config?.alias} (${this.hass.localize(
|
||||
...this.config,
|
||||
alias: this.readOnly
|
||||
? this.config?.alias
|
||||
: `${this.config?.alias} (${this.hass.localize(
|
||||
"ui.panel.config.script.picker.duplicate"
|
||||
)})`,
|
||||
});
|
||||
@@ -893,7 +817,7 @@ export class HaScriptEditor extends SubscribeMixin(
|
||||
),
|
||||
text: this.hass.localize(
|
||||
"ui.panel.config.script.editor.delete_confirm_text",
|
||||
{ name: this._config?.alias }
|
||||
{ name: this.config?.alias }
|
||||
),
|
||||
confirmText: this.hass!.localize("ui.common.delete"),
|
||||
destructive: true,
|
||||
@@ -907,42 +831,20 @@ export class HaScriptEditor extends SubscribeMixin(
|
||||
goBack("/config");
|
||||
}
|
||||
|
||||
private async _switchUiMode() {
|
||||
if (this._yamlErrors) {
|
||||
const result = await showConfirmationDialog(this, {
|
||||
text: html`${this.hass.localize(
|
||||
"ui.panel.config.automation.editor.switch_ui_yaml_error"
|
||||
)}<br /><br />${this._yamlErrors}`,
|
||||
confirmText: this.hass!.localize("ui.common.continue"),
|
||||
destructive: true,
|
||||
dismissText: this.hass!.localize("ui.common.cancel"),
|
||||
});
|
||||
if (!result) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
this._yamlErrors = undefined;
|
||||
this._mode = "gui";
|
||||
}
|
||||
|
||||
private _switchYamlMode() {
|
||||
this._mode = "yaml";
|
||||
}
|
||||
|
||||
private async _promptScriptAlias(): Promise<boolean> {
|
||||
return new Promise((resolve) => {
|
||||
showAutomationSaveDialog(this, {
|
||||
config: this._config!,
|
||||
config: this.config!,
|
||||
domain: "script",
|
||||
updateConfig: async (config, entityRegistryUpdate) => {
|
||||
this._config = config;
|
||||
this._entityRegistryUpdate = entityRegistryUpdate;
|
||||
this._dirty = true;
|
||||
this.config = config;
|
||||
this.entityRegistryUpdate = entityRegistryUpdate;
|
||||
this.dirty = true;
|
||||
this.requestUpdate();
|
||||
resolve(true);
|
||||
},
|
||||
onClose: () => resolve(false),
|
||||
entityRegistryUpdate: this._entityRegistryUpdate,
|
||||
entityRegistryUpdate: this.entityRegistryUpdate,
|
||||
entityRegistryEntry: this.entityRegistry.find(
|
||||
(entry) => entry.unique_id === this.scriptId
|
||||
),
|
||||
@@ -953,10 +855,10 @@ export class HaScriptEditor extends SubscribeMixin(
|
||||
private async _promptScriptMode(): Promise<void> {
|
||||
return new Promise((resolve) => {
|
||||
showAutomationModeDialog(this, {
|
||||
config: this._config!,
|
||||
config: this.config!,
|
||||
updateConfig: (config) => {
|
||||
this._config = config;
|
||||
this._dirty = true;
|
||||
this.config = config;
|
||||
this.dirty = true;
|
||||
this.requestUpdate();
|
||||
resolve();
|
||||
},
|
||||
@@ -966,9 +868,9 @@ export class HaScriptEditor extends SubscribeMixin(
|
||||
}
|
||||
|
||||
private async _handleSaveScript() {
|
||||
if (this._yamlErrors) {
|
||||
if (this.yamlErrors) {
|
||||
showToast(this, {
|
||||
message: this._yamlErrors,
|
||||
message: this.yamlErrors,
|
||||
});
|
||||
return;
|
||||
}
|
||||
@@ -980,9 +882,9 @@ export class HaScriptEditor extends SubscribeMixin(
|
||||
if (!saved) {
|
||||
return;
|
||||
}
|
||||
this._entityId = this._computeEntityIdFromAlias(this._config!.alias);
|
||||
this.currentEntityId = this._computeEntityIdFromAlias(this.config!.alias);
|
||||
}
|
||||
const id = this.scriptId || this._entityId || Date.now();
|
||||
const id = this.scriptId || this.currentEntityId || Date.now();
|
||||
|
||||
await this._saveScript(id);
|
||||
if (!this.scriptId) {
|
||||
@@ -991,13 +893,13 @@ export class HaScriptEditor extends SubscribeMixin(
|
||||
}
|
||||
|
||||
private async _saveScript(id): Promise<void> {
|
||||
this._saving = true;
|
||||
this.saving = true;
|
||||
|
||||
let entityRegPromise: Promise<EntityRegistryEntry> | undefined;
|
||||
if (this._entityRegistryUpdate !== undefined && !this.scriptId) {
|
||||
if (this.entityRegistryUpdate !== undefined && !this.scriptId) {
|
||||
this._newScriptId = id.toString();
|
||||
entityRegPromise = new Promise<EntityRegistryEntry>((resolve) => {
|
||||
this._entityRegCreated = resolve;
|
||||
this.entityRegCreated = resolve;
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1005,11 +907,11 @@ export class HaScriptEditor extends SubscribeMixin(
|
||||
await this.hass!.callApi(
|
||||
"POST",
|
||||
"config/script/config/" + id,
|
||||
this._config
|
||||
this.config
|
||||
);
|
||||
|
||||
if (this._entityRegistryUpdate !== undefined) {
|
||||
let entityId = this._entityId;
|
||||
if (this.entityRegistryUpdate !== undefined) {
|
||||
let entityId = this.currentEntityId;
|
||||
|
||||
// wait for new script to appear in entity registry
|
||||
if (entityRegPromise) {
|
||||
@@ -1044,23 +946,23 @@ export class HaScriptEditor extends SubscribeMixin(
|
||||
if (entityId) {
|
||||
await updateEntityRegistryEntry(this.hass, entityId, {
|
||||
categories: {
|
||||
script: this._entityRegistryUpdate.category || null,
|
||||
script: this.entityRegistryUpdate.category || null,
|
||||
},
|
||||
labels: this._entityRegistryUpdate.labels || [],
|
||||
area_id: this._entityRegistryUpdate.area || null,
|
||||
labels: this.entityRegistryUpdate.labels || [],
|
||||
area_id: this.entityRegistryUpdate.area || null,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
this._dirty = false;
|
||||
this.dirty = false;
|
||||
} catch (errors: any) {
|
||||
this._errors = errors.body?.message || errors.error || errors.body;
|
||||
this.errors = errors.body?.message || errors.error || errors.body;
|
||||
showToast(this, {
|
||||
message: errors.body?.message || errors.error || errors.body,
|
||||
});
|
||||
throw errors;
|
||||
} finally {
|
||||
this._saving = false;
|
||||
this.saving = false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1077,14 +979,6 @@ export class HaScriptEditor extends SubscribeMixin(
|
||||
};
|
||||
}
|
||||
|
||||
protected get isDirty() {
|
||||
return this._dirty;
|
||||
}
|
||||
|
||||
protected async promptDiscardChanges() {
|
||||
return this._confirmUnsavedChanged();
|
||||
}
|
||||
|
||||
// @ts-ignore
|
||||
private _collapseAll() {
|
||||
this._manualEditor?.collapseAll();
|
||||
@@ -1109,8 +1003,8 @@ export class HaScriptEditor extends SubscribeMixin(
|
||||
|
||||
private _applyUndoRedo(config: ScriptConfig) {
|
||||
this._manualEditor?.triggerCloseSidebar();
|
||||
this._config = config;
|
||||
this._dirty = true;
|
||||
this.config = config;
|
||||
this.dirty = true;
|
||||
}
|
||||
|
||||
private _undo() {
|
||||
@@ -1139,7 +1033,7 @@ export class HaScriptEditor extends SubscribeMixin(
|
||||
this._showInfo();
|
||||
break;
|
||||
case "settings":
|
||||
this._showSettings();
|
||||
this.showSettings();
|
||||
break;
|
||||
case "category":
|
||||
this._editCategory();
|
||||
@@ -1163,11 +1057,11 @@ export class HaScriptEditor extends SubscribeMixin(
|
||||
this._takeControl();
|
||||
break;
|
||||
case "toggle_yaml_mode":
|
||||
if (this._mode === "gui") {
|
||||
this._switchYamlMode();
|
||||
if (this.mode === "gui") {
|
||||
this.switchYamlMode();
|
||||
break;
|
||||
}
|
||||
this._switchUiMode();
|
||||
this.switchUiMode();
|
||||
break;
|
||||
case "delete":
|
||||
this._deleteConfirm();
|
||||
@@ -1181,19 +1075,8 @@ export class HaScriptEditor extends SubscribeMixin(
|
||||
static get styles(): CSSResultGroup {
|
||||
return [
|
||||
haStyle,
|
||||
automationScriptEditorStyles,
|
||||
css`
|
||||
:host {
|
||||
--ha-automation-editor-max-width: var(
|
||||
--ha-automation-editor-width,
|
||||
1540px
|
||||
);
|
||||
}
|
||||
.yaml-mode {
|
||||
height: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
padding-bottom: 0;
|
||||
}
|
||||
manual-script-editor,
|
||||
blueprint-script-editor {
|
||||
margin: 0 auto;
|
||||
@@ -1244,29 +1127,9 @@ export class HaScriptEditor extends SubscribeMixin(
|
||||
padding: 0 12px;
|
||||
}
|
||||
|
||||
ha-yaml-editor {
|
||||
flex-grow: 1;
|
||||
--actions-border-radius: var(--ha-border-radius-square);
|
||||
--code-mirror-height: 100%;
|
||||
min-height: 0;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
p {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
span[slot="introduction"] a {
|
||||
color: var(--primary-color);
|
||||
}
|
||||
ha-fab {
|
||||
position: fixed;
|
||||
right: 16px;
|
||||
bottom: calc(-80px - var(--safe-area-inset-bottom));
|
||||
transition: bottom 0.3s;
|
||||
}
|
||||
ha-fab.dirty {
|
||||
bottom: calc(16px + var(--safe-area-inset-bottom, 0px));
|
||||
}
|
||||
.header {
|
||||
display: flex;
|
||||
margin: 16px 0;
|
||||
@@ -1280,15 +1143,6 @@ export class HaScriptEditor extends SubscribeMixin(
|
||||
.header a {
|
||||
color: var(--secondary-text-color);
|
||||
}
|
||||
ha-tooltip ha-svg-icon {
|
||||
width: 12px;
|
||||
}
|
||||
ha-tooltip .shortcut {
|
||||
display: inline-flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
gap: 2px;
|
||||
}
|
||||
`,
|
||||
];
|
||||
}
|
||||
|
||||
@@ -670,10 +670,10 @@ export class AssistPipelineDebug extends LitElement {
|
||||
background-color: var(--light-primary-color);
|
||||
color: var(--text-light-primary-color, var(--primary-text-color));
|
||||
direction: var(--direction);
|
||||
}
|
||||
|
||||
.tool_result [slot="header"] {
|
||||
color: var(--text-light-primary-color, var(--primary-text-color));
|
||||
--primary-text-color: var(
|
||||
--text-light-primary-color,
|
||||
var(--primary-text-color)
|
||||
);
|
||||
}
|
||||
|
||||
.message.user,
|
||||
|
||||
@@ -7,7 +7,11 @@ import type { HomeAssistant } from "../../../types";
|
||||
import { DEFAULT_ENERGY_COLLECTION_KEY } from "../ha-panel-energy";
|
||||
import { shouldShowFloorsAndAreas } from "./show-floors-and-areas";
|
||||
import type { LovelaceSectionConfig } from "../../../data/lovelace/config/section";
|
||||
import type { LovelaceBadgeConfig } from "../../../data/lovelace/config/badge";
|
||||
import {
|
||||
LARGE_SCREEN_CONDITION,
|
||||
SMALL_SCREEN_CONDITION,
|
||||
} from "../../lovelace/strategies/helpers/screen-conditions";
|
||||
import type { LovelaceCardConfig } from "../../../data/lovelace/config/card";
|
||||
|
||||
@customElement("power-view-strategy")
|
||||
export class PowerViewStrategy extends ReactiveElement {
|
||||
@@ -45,15 +49,22 @@ export class PowerViewStrategy extends ReactiveElement {
|
||||
(source) => source.type === "gas" && source.stat_rate
|
||||
);
|
||||
|
||||
const tileSection: LovelaceSectionConfig = {
|
||||
type: "grid",
|
||||
cards: [],
|
||||
column_span: 2,
|
||||
};
|
||||
const chartsSection: LovelaceSectionConfig = {
|
||||
type: "grid",
|
||||
cards: [],
|
||||
column_span: 2,
|
||||
};
|
||||
const badges: LovelaceBadgeConfig[] = [];
|
||||
const tiles: LovelaceCardConfig[] = [];
|
||||
|
||||
const view: LovelaceViewConfig = {
|
||||
type: "sections",
|
||||
sections: [chartsSection],
|
||||
sections: [tileSection, chartsSection],
|
||||
max_columns: 2,
|
||||
};
|
||||
|
||||
// No sources configured
|
||||
@@ -69,10 +80,11 @@ export class PowerViewStrategy extends ReactiveElement {
|
||||
}
|
||||
|
||||
if (hasPowerSources) {
|
||||
badges.push({
|
||||
const card = {
|
||||
type: "power-total",
|
||||
collection_key: collectionKey,
|
||||
});
|
||||
};
|
||||
tiles.push(card);
|
||||
|
||||
chartsSection.cards!.push({
|
||||
title: hass.localize("ui.panel.energy.cards.power_sources_graph_title"),
|
||||
@@ -85,17 +97,19 @@ export class PowerViewStrategy extends ReactiveElement {
|
||||
}
|
||||
|
||||
if (hasGasSources) {
|
||||
badges.push({
|
||||
const card = {
|
||||
type: "gas-total",
|
||||
collection_key: collectionKey,
|
||||
});
|
||||
};
|
||||
tiles.push({ ...card });
|
||||
}
|
||||
|
||||
if (hasWaterSources) {
|
||||
badges.push({
|
||||
const card = {
|
||||
type: "water-total",
|
||||
collection_key: collectionKey,
|
||||
});
|
||||
};
|
||||
tiles.push({ ...card });
|
||||
}
|
||||
|
||||
if (hasPowerDevices) {
|
||||
@@ -134,8 +148,21 @@ export class PowerViewStrategy extends ReactiveElement {
|
||||
});
|
||||
}
|
||||
|
||||
if (badges.length) {
|
||||
view.badges = badges;
|
||||
tiles.forEach((card) => {
|
||||
tileSection.cards!.push({
|
||||
...card,
|
||||
grid_options: { columns: 24 / tiles.length },
|
||||
});
|
||||
});
|
||||
|
||||
if (tiles.length > 2) {
|
||||
// On small screens with 3 tiles, show them in 1 column
|
||||
tileSection.visibility = [LARGE_SCREEN_CONDITION];
|
||||
view.sections!.unshift({
|
||||
type: "grid",
|
||||
cards: tiles,
|
||||
visibility: [SMALL_SCREEN_CONDITION],
|
||||
});
|
||||
}
|
||||
|
||||
return view;
|
||||
|
||||
@@ -48,20 +48,3 @@ export interface EntityBadgeConfig extends LovelaceBadgeConfig {
|
||||
*/
|
||||
display_type?: DisplayType;
|
||||
}
|
||||
|
||||
interface EnergyTotalBadgeConfig extends LovelaceBadgeConfig {
|
||||
title?: string;
|
||||
collection_key?: string;
|
||||
}
|
||||
|
||||
export interface PowerTotalBadgeConfig extends EnergyTotalBadgeConfig {
|
||||
type: "power-total";
|
||||
}
|
||||
|
||||
export interface WaterTotalBadgeConfig extends EnergyTotalBadgeConfig {
|
||||
type: "water-total";
|
||||
}
|
||||
|
||||
export interface GasTotalBadgeConfig extends EnergyTotalBadgeConfig {
|
||||
type: "gas-total";
|
||||
}
|
||||
|
||||
@@ -49,14 +49,6 @@ class HuiClimateFanModesCardFeature
|
||||
|
||||
@state() _currentFanMode?: string;
|
||||
|
||||
private _renderFanModeIcon = (value: string) =>
|
||||
html`<ha-attribute-icon
|
||||
.hass=${this.hass}
|
||||
.stateObj=${this._stateObj}
|
||||
attribute="fan_mode"
|
||||
.attributeValue=${value}
|
||||
></ha-attribute-icon>`;
|
||||
|
||||
private get _stateObj() {
|
||||
if (!this.hass || !this.context || !this.context.entity_id) {
|
||||
return undefined;
|
||||
@@ -183,8 +175,14 @@ class HuiClimateFanModesCardFeature
|
||||
.value=${this._currentFanMode}
|
||||
.disabled=${this._stateObj.state === UNAVAILABLE}
|
||||
@wa-select=${this._valueChanged}
|
||||
.options=${options}
|
||||
.renderIcon=${this._renderFanModeIcon}
|
||||
.options=${options.map((option) => ({
|
||||
...option,
|
||||
attributeIcon: {
|
||||
stateObj: stateObj,
|
||||
attribute: "fan_mode",
|
||||
attributeValue: option.value,
|
||||
},
|
||||
}))}
|
||||
><ha-svg-icon slot="icon" .path=${mdiFan}></ha-svg-icon>
|
||||
</ha-control-select-menu>
|
||||
`;
|
||||
|
||||
@@ -48,14 +48,6 @@ class HuiClimatePresetModesCardFeature
|
||||
|
||||
@state() _currentPresetMode?: string;
|
||||
|
||||
private _renderPresetModeIcon = (value: string) =>
|
||||
html`<ha-attribute-icon
|
||||
.hass=${this.hass}
|
||||
.stateObj=${this._stateObj}
|
||||
attribute="preset_mode"
|
||||
.attributeValue=${value}
|
||||
></ha-attribute-icon>`;
|
||||
|
||||
private get _stateObj() {
|
||||
if (!this.hass || !this.context || !this.context.entity_id) {
|
||||
return undefined;
|
||||
@@ -187,8 +179,14 @@ class HuiClimatePresetModesCardFeature
|
||||
.value=${this._currentPresetMode}
|
||||
.disabled=${this._stateObj.state === UNAVAILABLE}
|
||||
@wa-select=${this._valueChanged}
|
||||
.options=${options}
|
||||
.renderIcon=${this._renderPresetModeIcon}
|
||||
.options=${options.map((option) => ({
|
||||
...option,
|
||||
attributeIcon: {
|
||||
stateObj: stateObj,
|
||||
attribute: "preset_mode",
|
||||
attributeValue: option.value,
|
||||
},
|
||||
}))}
|
||||
>
|
||||
<ha-svg-icon slot="icon" .path=${mdiTuneVariant}></ha-svg-icon>
|
||||
</ha-control-select-menu>
|
||||
|
||||
@@ -48,14 +48,6 @@ class HuiClimateSwingHorizontalModesCardFeature
|
||||
|
||||
@state() _currentSwingHorizontalMode?: string;
|
||||
|
||||
private _renderSwingHorizontalModeIcon = (value: string) =>
|
||||
html`<ha-attribute-icon
|
||||
.hass=${this.hass}
|
||||
.stateObj=${this._stateObj}
|
||||
attribute="swing_horizontal_mode"
|
||||
.attributeValue=${value}
|
||||
></ha-attribute-icon>`;
|
||||
|
||||
private get _stateObj() {
|
||||
if (!this.hass || !this.context || !this.context.entity_id) {
|
||||
return undefined;
|
||||
@@ -195,8 +187,14 @@ class HuiClimateSwingHorizontalModesCardFeature
|
||||
.value=${this._currentSwingHorizontalMode}
|
||||
.disabled=${this._stateObj.state === UNAVAILABLE}
|
||||
@wa-select=${this._valueChanged}
|
||||
.options=${options}
|
||||
.renderIcon=${this._renderSwingHorizontalModeIcon}
|
||||
.options=${options.map((option) => ({
|
||||
...option,
|
||||
attributeIcon: {
|
||||
stateObj: stateObj,
|
||||
attribute: "swing_horizontal_mode",
|
||||
attributeValue: option.value,
|
||||
},
|
||||
}))}
|
||||
>
|
||||
<ha-svg-icon slot="icon" .path=${mdiArrowOscillating}></ha-svg-icon>
|
||||
</ha-control-select-menu>
|
||||
|
||||
@@ -48,14 +48,6 @@ class HuiClimateSwingModesCardFeature
|
||||
|
||||
@state() _currentSwingMode?: string;
|
||||
|
||||
private _renderSwingModeIcon = (value: string) =>
|
||||
html`<ha-attribute-icon
|
||||
.hass=${this.hass}
|
||||
.stateObj=${this._stateObj}
|
||||
attribute="swing_mode"
|
||||
.attributeValue=${value}
|
||||
></ha-attribute-icon>`;
|
||||
|
||||
private get _stateObj() {
|
||||
if (!this.hass || !this.context || !this.context.entity_id) {
|
||||
return undefined;
|
||||
@@ -187,8 +179,14 @@ class HuiClimateSwingModesCardFeature
|
||||
.value=${this._currentSwingMode}
|
||||
.disabled=${this._stateObj.state === UNAVAILABLE}
|
||||
@wa-select=${this._valueChanged}
|
||||
.options=${options}
|
||||
.renderIcon=${this._renderSwingModeIcon}
|
||||
.options=${options.map((option) => ({
|
||||
...option,
|
||||
attributeIcon: {
|
||||
stateObj,
|
||||
attribute: "swing_mode",
|
||||
attributeValue: option.value,
|
||||
},
|
||||
}))}
|
||||
><ha-svg-icon slot="icon" .path=${mdiArrowOscillating}></ha-svg-icon>
|
||||
</ha-control-select-menu>
|
||||
`;
|
||||
|
||||
@@ -47,14 +47,6 @@ class HuiFanPresetModesCardFeature
|
||||
|
||||
@state() _currentPresetMode?: string;
|
||||
|
||||
private _renderPresetModeIcon = (value: string) =>
|
||||
html`<ha-attribute-icon
|
||||
.hass=${this.hass}
|
||||
.stateObj=${this._stateObj}
|
||||
attribute="preset_mode"
|
||||
.attributeValue=${value}
|
||||
></ha-attribute-icon>`;
|
||||
|
||||
private get _stateObj() {
|
||||
if (!this.hass || !this.context || !this.context.entity_id) {
|
||||
return undefined;
|
||||
@@ -181,8 +173,14 @@ class HuiFanPresetModesCardFeature
|
||||
.value=${this._currentPresetMode}
|
||||
.disabled=${this._stateObj.state === UNAVAILABLE}
|
||||
@wa-select=${this._valueChanged}
|
||||
.options=${options}
|
||||
.renderIcon=${this._renderPresetModeIcon}
|
||||
.options=${options.map((option) => ({
|
||||
...option,
|
||||
attributeIcon: {
|
||||
stateObj: stateObj,
|
||||
attribute: "preset_mode",
|
||||
attributeValue: option.value,
|
||||
},
|
||||
}))}
|
||||
>
|
||||
<ha-svg-icon slot="icon" .path=${mdiTuneVariant}></ha-svg-icon>
|
||||
</ha-control-select-menu>
|
||||
|
||||
@@ -48,14 +48,6 @@ class HuiHumidifierModesCardFeature
|
||||
|
||||
@state() _currentMode?: string;
|
||||
|
||||
private _renderModeIcon = (value: string) =>
|
||||
html`<ha-attribute-icon
|
||||
.hass=${this.hass}
|
||||
.stateObj=${this._stateObj}
|
||||
attribute="mode"
|
||||
.attributeValue=${value}
|
||||
></ha-attribute-icon>`;
|
||||
|
||||
private get _stateObj() {
|
||||
if (!this.hass || !this.context || !this.context.entity_id) {
|
||||
return undefined;
|
||||
@@ -182,8 +174,14 @@ class HuiHumidifierModesCardFeature
|
||||
.value=${this._currentMode}
|
||||
.disabled=${this._stateObj.state === UNAVAILABLE}
|
||||
@wa-select=${this._valueChanged}
|
||||
.options=${options}
|
||||
.renderIcon=${this._renderModeIcon}
|
||||
.options=${options.map((option) => ({
|
||||
...option,
|
||||
attributeIcon: {
|
||||
stateObj,
|
||||
attribute: "mode",
|
||||
attributeValue: option.value,
|
||||
},
|
||||
}))}
|
||||
>
|
||||
<ha-svg-icon slot="icon" .path=${mdiTuneVariant}></ha-svg-icon>
|
||||
</ha-control-select-menu>
|
||||
|
||||
@@ -49,14 +49,6 @@ class HuiWaterHeaterOperationModeCardFeature
|
||||
|
||||
@state() _currentOperationMode?: OperationMode;
|
||||
|
||||
private _renderOperationModeIcon = (value: string) =>
|
||||
html`<ha-attribute-icon
|
||||
.hass=${this.hass}
|
||||
.stateObj=${this._stateObj}
|
||||
attribute="operation_mode"
|
||||
.attributeValue=${value}
|
||||
></ha-attribute-icon>`;
|
||||
|
||||
private get _stateObj() {
|
||||
if (!this.hass || !this.context || !this.context.entity_id) {
|
||||
return undefined;
|
||||
@@ -161,8 +153,14 @@ class HuiWaterHeaterOperationModeCardFeature
|
||||
.value=${this._currentOperationMode}
|
||||
.disabled=${this._stateObj.state === UNAVAILABLE}
|
||||
@wa-select=${this._valueChanged}
|
||||
.options=${options}
|
||||
.renderIcon=${this._renderOperationModeIcon}
|
||||
.options=${options.map((option) => ({
|
||||
...option,
|
||||
attributeIcon: {
|
||||
stateObj: this._stateObj,
|
||||
attribute: "operation_mode",
|
||||
attributeValue: option.value,
|
||||
},
|
||||
}))}
|
||||
>
|
||||
<ha-svg-icon slot="icon" .path=${mdiWaterBoiler}></ha-svg-icon>
|
||||
</ha-control-select-menu>
|
||||
|
||||
@@ -218,9 +218,7 @@ function formatTooltip(
|
||||
}
|
||||
// when comparing the first value is offset to match the main period
|
||||
// and the real date is in the third value
|
||||
// find the first param with the real date to handle gap-filled entries
|
||||
const origDate = params.find((p) => p.value?.[2] != null)?.value?.[2];
|
||||
const date = new Date(origDate ?? params[0].value?.[0]);
|
||||
const date = new Date(params[0].value?.[2] ?? params[0].value?.[0]);
|
||||
let period: string;
|
||||
|
||||
if (suggestedPeriod === "month") {
|
||||
|
||||
@@ -3,8 +3,11 @@ import type { UnsubscribeFunc } from "home-assistant-js-websocket";
|
||||
import type { PropertyValues } from "lit";
|
||||
import { css, html, LitElement, nothing } from "lit";
|
||||
import { customElement, property, state } from "lit/decorators";
|
||||
import "../../../../components/ha-badge";
|
||||
import "../../../../components/ha-card";
|
||||
import "../../../../components/ha-svg-icon";
|
||||
import "../../../../components/tile/ha-tile-container";
|
||||
import "../../../../components/tile/ha-tile-icon";
|
||||
import "../../../../components/tile/ha-tile-info";
|
||||
import type { EnergyData, EnergyPreferences } from "../../../../data/energy";
|
||||
import {
|
||||
formatFlowRateShort,
|
||||
@@ -13,17 +16,18 @@ import {
|
||||
} from "../../../../data/energy";
|
||||
import { SubscribeMixin } from "../../../../mixins/subscribe-mixin";
|
||||
import type { HomeAssistant } from "../../../../types";
|
||||
import type { LovelaceBadge } from "../../types";
|
||||
import type { GasTotalBadgeConfig } from "../types";
|
||||
import type { LovelaceCard, LovelaceGridOptions } from "../../types";
|
||||
import { tileCardStyle } from "../tile/tile-card-style";
|
||||
import type { GasTotalCardConfig } from "../types";
|
||||
|
||||
@customElement("hui-gas-total-badge")
|
||||
export class HuiGasTotalBadge
|
||||
@customElement("hui-gas-total-card")
|
||||
export class HuiGasTotalCard
|
||||
extends SubscribeMixin(LitElement)
|
||||
implements LovelaceBadge
|
||||
implements LovelaceCard
|
||||
{
|
||||
@property({ attribute: false }) public hass!: HomeAssistant;
|
||||
|
||||
@state() private _config?: GasTotalBadgeConfig;
|
||||
@state() private _config?: GasTotalCardConfig;
|
||||
|
||||
@state() private _data?: EnergyData;
|
||||
|
||||
@@ -31,7 +35,7 @@ export class HuiGasTotalBadge
|
||||
|
||||
protected hassSubscribeRequiredHostProps = ["_config"];
|
||||
|
||||
public setConfig(config: GasTotalBadgeConfig): void {
|
||||
public setConfig(config: GasTotalCardConfig): void {
|
||||
this._config = config;
|
||||
}
|
||||
|
||||
@@ -45,19 +49,34 @@ export class HuiGasTotalBadge
|
||||
];
|
||||
}
|
||||
|
||||
public getCardSize(): Promise<number> | number {
|
||||
return 1;
|
||||
}
|
||||
|
||||
getGridOptions(): LovelaceGridOptions {
|
||||
return {
|
||||
columns: 12,
|
||||
min_columns: 6,
|
||||
rows: 1,
|
||||
min_rows: 1,
|
||||
};
|
||||
}
|
||||
|
||||
protected shouldUpdate(changedProps: PropertyValues): boolean {
|
||||
if (changedProps.has("_config") || changedProps.has("_data")) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Check if any of the tracked entity states have changed
|
||||
if (changedProps.has("hass")) {
|
||||
const oldHass = changedProps.get("hass") as HomeAssistant | undefined;
|
||||
if (!oldHass || !this._entities.size) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Only update if one of our tracked entities changed
|
||||
for (const entityId of this._entities) {
|
||||
if (oldHass.states[entityId] !== this.hass?.states[entityId]) {
|
||||
if (oldHass.states[entityId] !== this.hass.states[entityId]) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -103,22 +122,32 @@ export class HuiGasTotalBadge
|
||||
this.hass.localize("ui.panel.lovelace.cards.energy.gas_total_title");
|
||||
|
||||
return html`
|
||||
<ha-badge .label=${name}>
|
||||
<ha-svg-icon slot="icon" .path=${mdiFire}></ha-svg-icon>
|
||||
${displayValue}
|
||||
</ha-badge>
|
||||
<ha-card>
|
||||
<ha-tile-container .interactive=${false}>
|
||||
<ha-tile-icon slot="icon" data-domain="sensor" data-state="active">
|
||||
<ha-svg-icon slot="icon" .path=${mdiFire}></ha-svg-icon>
|
||||
</ha-tile-icon>
|
||||
<ha-tile-info slot="info">
|
||||
<span slot="primary" class="primary">${name}</span>
|
||||
<span slot="secondary" class="secondary">${displayValue}</span>
|
||||
</ha-tile-info>
|
||||
</ha-tile-container>
|
||||
</ha-card>
|
||||
`;
|
||||
}
|
||||
|
||||
static styles = css`
|
||||
ha-badge {
|
||||
--badge-color: var(--energy-gas-color);
|
||||
}
|
||||
`;
|
||||
static styles = [
|
||||
tileCardStyle,
|
||||
css`
|
||||
:host {
|
||||
--tile-color: var(--energy-gas-color);
|
||||
}
|
||||
`,
|
||||
];
|
||||
}
|
||||
|
||||
declare global {
|
||||
interface HTMLElementTagNameMap {
|
||||
"hui-gas-total-badge": HuiGasTotalBadge;
|
||||
"hui-gas-total-card": HuiGasTotalCard;
|
||||
}
|
||||
}
|
||||
@@ -4,8 +4,11 @@ import type { PropertyValues } from "lit";
|
||||
import { css, html, LitElement, nothing } from "lit";
|
||||
import { customElement, property, state } from "lit/decorators";
|
||||
import { formatNumber } from "../../../../common/number/format_number";
|
||||
import "../../../../components/ha-badge";
|
||||
import "../../../../components/ha-card";
|
||||
import "../../../../components/ha-svg-icon";
|
||||
import "../../../../components/tile/ha-tile-container";
|
||||
import "../../../../components/tile/ha-tile-icon";
|
||||
import "../../../../components/tile/ha-tile-info";
|
||||
import type { EnergyData, EnergyPreferences } from "../../../../data/energy";
|
||||
import {
|
||||
getEnergyDataCollection,
|
||||
@@ -13,17 +16,18 @@ import {
|
||||
} from "../../../../data/energy";
|
||||
import { SubscribeMixin } from "../../../../mixins/subscribe-mixin";
|
||||
import type { HomeAssistant } from "../../../../types";
|
||||
import type { LovelaceBadge } from "../../types";
|
||||
import type { PowerTotalBadgeConfig } from "../types";
|
||||
import type { LovelaceCard, LovelaceGridOptions } from "../../types";
|
||||
import { tileCardStyle } from "../tile/tile-card-style";
|
||||
import type { PowerTotalCardConfig } from "../types";
|
||||
|
||||
@customElement("hui-power-total-badge")
|
||||
export class HuiPowerTotalBadge
|
||||
@customElement("hui-power-total-card")
|
||||
export class HuiPowerTotalCard
|
||||
extends SubscribeMixin(LitElement)
|
||||
implements LovelaceBadge
|
||||
implements LovelaceCard
|
||||
{
|
||||
@property({ attribute: false }) public hass!: HomeAssistant;
|
||||
|
||||
@state() private _config?: PowerTotalBadgeConfig;
|
||||
@state() private _config?: PowerTotalCardConfig;
|
||||
|
||||
@state() private _data?: EnergyData;
|
||||
|
||||
@@ -31,7 +35,7 @@ export class HuiPowerTotalBadge
|
||||
|
||||
protected hassSubscribeRequiredHostProps = ["_config"];
|
||||
|
||||
public setConfig(config: PowerTotalBadgeConfig): void {
|
||||
public setConfig(config: PowerTotalCardConfig): void {
|
||||
this._config = config;
|
||||
}
|
||||
|
||||
@@ -45,19 +49,34 @@ export class HuiPowerTotalBadge
|
||||
];
|
||||
}
|
||||
|
||||
public getCardSize(): Promise<number> | number {
|
||||
return 1;
|
||||
}
|
||||
|
||||
getGridOptions(): LovelaceGridOptions {
|
||||
return {
|
||||
columns: 12,
|
||||
min_columns: 6,
|
||||
rows: 1,
|
||||
min_rows: 1,
|
||||
};
|
||||
}
|
||||
|
||||
protected shouldUpdate(changedProps: PropertyValues): boolean {
|
||||
if (changedProps.has("_config") || changedProps.has("_data")) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Check if any of the tracked entity states have changed
|
||||
if (changedProps.has("hass")) {
|
||||
const oldHass = changedProps.get("hass") as HomeAssistant | undefined;
|
||||
if (!oldHass || !this._entities.size) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Only update if one of our tracked entities changed
|
||||
for (const entityId of this._entities) {
|
||||
if (oldHass.states[entityId] !== this.hass?.states[entityId]) {
|
||||
if (oldHass.states[entityId] !== this.hass.states[entityId]) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -75,10 +94,10 @@ export class HuiPowerTotalBadge
|
||||
this._entities.clear();
|
||||
|
||||
let solar = 0;
|
||||
let fromGrid = 0;
|
||||
let toGrid = 0;
|
||||
let fromBattery = 0;
|
||||
let toBattery = 0;
|
||||
let from_grid = 0;
|
||||
let to_grid = 0;
|
||||
let from_battery = 0;
|
||||
let to_battery = 0;
|
||||
|
||||
prefs.energy_sources.forEach((source) => {
|
||||
if (source.type === "solar" && source.stat_rate) {
|
||||
@@ -86,17 +105,17 @@ export class HuiPowerTotalBadge
|
||||
if (value > 0) solar += value;
|
||||
} else if (source.type === "grid" && source.stat_rate) {
|
||||
const value = this._getCurrentPower(source.stat_rate);
|
||||
if (value > 0) fromGrid += value;
|
||||
else if (value < 0) toGrid += Math.abs(value);
|
||||
if (value > 0) from_grid += value;
|
||||
else if (value < 0) to_grid += Math.abs(value);
|
||||
} else if (source.type === "battery" && source.stat_rate) {
|
||||
const value = this._getCurrentPower(source.stat_rate);
|
||||
if (value > 0) fromBattery += value;
|
||||
else if (value < 0) toBattery += Math.abs(value);
|
||||
if (value > 0) from_battery += value;
|
||||
else if (value < 0) to_battery += Math.abs(value);
|
||||
}
|
||||
});
|
||||
|
||||
const usedTotal = fromGrid + solar + fromBattery - toGrid - toBattery;
|
||||
return Math.max(0, usedTotal);
|
||||
const used_total = from_grid + solar + from_battery - to_grid - to_battery;
|
||||
return Math.max(0, used_total);
|
||||
}
|
||||
|
||||
protected render() {
|
||||
@@ -122,22 +141,35 @@ export class HuiPowerTotalBadge
|
||||
this.hass.localize("ui.panel.lovelace.cards.energy.power_total_title");
|
||||
|
||||
return html`
|
||||
<ha-badge .label=${name}>
|
||||
<ha-svg-icon slot="icon" .path=${mdiHomeLightningBolt}></ha-svg-icon>
|
||||
${displayValue}
|
||||
</ha-badge>
|
||||
<ha-card>
|
||||
<ha-tile-container .interactive=${false}>
|
||||
<ha-tile-icon slot="icon" data-domain="sensor" data-state="active">
|
||||
<ha-svg-icon
|
||||
slot="icon"
|
||||
.path=${mdiHomeLightningBolt}
|
||||
></ha-svg-icon>
|
||||
</ha-tile-icon>
|
||||
<ha-tile-info slot="info">
|
||||
<span slot="primary" class="primary">${name}</span>
|
||||
<span slot="secondary" class="secondary">${displayValue}</span>
|
||||
</ha-tile-info>
|
||||
</ha-tile-container>
|
||||
</ha-card>
|
||||
`;
|
||||
}
|
||||
|
||||
static styles = css`
|
||||
ha-badge {
|
||||
--badge-color: var(--primary-color);
|
||||
}
|
||||
`;
|
||||
static styles = [
|
||||
tileCardStyle,
|
||||
css`
|
||||
:host {
|
||||
--tile-color: var(--primary-color);
|
||||
}
|
||||
`,
|
||||
];
|
||||
}
|
||||
|
||||
declare global {
|
||||
interface HTMLElementTagNameMap {
|
||||
"hui-power-total-badge": HuiPowerTotalBadge;
|
||||
"hui-power-total-card": HuiPowerTotalCard;
|
||||
}
|
||||
}
|
||||
@@ -3,8 +3,11 @@ import type { UnsubscribeFunc } from "home-assistant-js-websocket";
|
||||
import type { PropertyValues } from "lit";
|
||||
import { css, html, LitElement, nothing } from "lit";
|
||||
import { customElement, property, state } from "lit/decorators";
|
||||
import "../../../../components/ha-badge";
|
||||
import "../../../../components/ha-card";
|
||||
import "../../../../components/ha-svg-icon";
|
||||
import "../../../../components/tile/ha-tile-container";
|
||||
import "../../../../components/tile/ha-tile-icon";
|
||||
import "../../../../components/tile/ha-tile-info";
|
||||
import type { EnergyData, EnergyPreferences } from "../../../../data/energy";
|
||||
import {
|
||||
formatFlowRateShort,
|
||||
@@ -13,17 +16,18 @@ import {
|
||||
} from "../../../../data/energy";
|
||||
import { SubscribeMixin } from "../../../../mixins/subscribe-mixin";
|
||||
import type { HomeAssistant } from "../../../../types";
|
||||
import type { LovelaceBadge } from "../../types";
|
||||
import type { WaterTotalBadgeConfig } from "../types";
|
||||
import type { LovelaceCard, LovelaceGridOptions } from "../../types";
|
||||
import { tileCardStyle } from "../tile/tile-card-style";
|
||||
import type { WaterTotalCardConfig } from "../types";
|
||||
|
||||
@customElement("hui-water-total-badge")
|
||||
export class HuiWaterTotalBadge
|
||||
@customElement("hui-water-total-card")
|
||||
export class HuiWaterTotalCard
|
||||
extends SubscribeMixin(LitElement)
|
||||
implements LovelaceBadge
|
||||
implements LovelaceCard
|
||||
{
|
||||
@property({ attribute: false }) public hass!: HomeAssistant;
|
||||
|
||||
@state() private _config?: WaterTotalBadgeConfig;
|
||||
@state() private _config?: WaterTotalCardConfig;
|
||||
|
||||
@state() private _data?: EnergyData;
|
||||
|
||||
@@ -31,7 +35,7 @@ export class HuiWaterTotalBadge
|
||||
|
||||
protected hassSubscribeRequiredHostProps = ["_config"];
|
||||
|
||||
public setConfig(config: WaterTotalBadgeConfig): void {
|
||||
public setConfig(config: WaterTotalCardConfig): void {
|
||||
this._config = config;
|
||||
}
|
||||
|
||||
@@ -45,19 +49,34 @@ export class HuiWaterTotalBadge
|
||||
];
|
||||
}
|
||||
|
||||
public getCardSize(): Promise<number> | number {
|
||||
return 1;
|
||||
}
|
||||
|
||||
getGridOptions(): LovelaceGridOptions {
|
||||
return {
|
||||
columns: 12,
|
||||
min_columns: 6,
|
||||
rows: 1,
|
||||
min_rows: 1,
|
||||
};
|
||||
}
|
||||
|
||||
protected shouldUpdate(changedProps: PropertyValues): boolean {
|
||||
if (changedProps.has("_config") || changedProps.has("_data")) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Check if any of the tracked entity states have changed
|
||||
if (changedProps.has("hass")) {
|
||||
const oldHass = changedProps.get("hass") as HomeAssistant | undefined;
|
||||
if (!oldHass || !this._entities.size) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Only update if one of our tracked entities changed
|
||||
for (const entityId of this._entities) {
|
||||
if (oldHass.states[entityId] !== this.hass?.states[entityId]) {
|
||||
if (oldHass.states[entityId] !== this.hass.states[entityId]) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -103,22 +122,32 @@ export class HuiWaterTotalBadge
|
||||
this.hass.localize("ui.panel.lovelace.cards.energy.water_total_title");
|
||||
|
||||
return html`
|
||||
<ha-badge .label=${name}>
|
||||
<ha-svg-icon slot="icon" .path=${mdiWater}></ha-svg-icon>
|
||||
${displayValue}
|
||||
</ha-badge>
|
||||
<ha-card>
|
||||
<ha-tile-container .interactive=${false}>
|
||||
<ha-tile-icon slot="icon" data-domain="sensor" data-state="active">
|
||||
<ha-svg-icon slot="icon" .path=${mdiWater}></ha-svg-icon>
|
||||
</ha-tile-icon>
|
||||
<ha-tile-info slot="info">
|
||||
<span slot="primary" class="primary">${name}</span>
|
||||
<span slot="secondary" class="secondary">${displayValue}</span>
|
||||
</ha-tile-info>
|
||||
</ha-tile-container>
|
||||
</ha-card>
|
||||
`;
|
||||
}
|
||||
|
||||
static styles = css`
|
||||
ha-badge {
|
||||
--badge-color: var(--energy-water-color);
|
||||
}
|
||||
`;
|
||||
static styles = [
|
||||
tileCardStyle,
|
||||
css`
|
||||
:host {
|
||||
--tile-color: var(--energy-water-color);
|
||||
}
|
||||
`,
|
||||
];
|
||||
}
|
||||
|
||||
declare global {
|
||||
interface HTMLElementTagNameMap {
|
||||
"hui-water-total-badge": HuiWaterTotalBadge;
|
||||
"hui-water-total-card": HuiWaterTotalCard;
|
||||
}
|
||||
}
|
||||
@@ -265,6 +265,21 @@ export interface PowerSourcesGraphCardConfig extends EnergyCardBaseConfig {
|
||||
show_legend?: boolean;
|
||||
}
|
||||
|
||||
export interface PowerTotalCardConfig extends EnergyCardBaseConfig {
|
||||
type: "power-total";
|
||||
title?: string;
|
||||
}
|
||||
|
||||
export interface WaterTotalCardConfig extends EnergyCardBaseConfig {
|
||||
type: "water-total";
|
||||
title?: string;
|
||||
}
|
||||
|
||||
export interface GasTotalCardConfig extends EnergyCardBaseConfig {
|
||||
type: "gas-total";
|
||||
title?: string;
|
||||
}
|
||||
|
||||
export interface PowerSankeyCardConfig extends EnergyCardBaseConfig {
|
||||
type: "power-sankey";
|
||||
title?: string;
|
||||
|
||||
@@ -10,9 +10,6 @@ const ALWAYS_LOADED_TYPES = new Set(["error", "entity"]);
|
||||
const LAZY_LOAD_TYPES = {
|
||||
"entity-filter": () => import("../badges/hui-entity-filter-badge"),
|
||||
"state-label": () => import("../badges/hui-state-label-badge"),
|
||||
"power-total": () => import("../badges/energy/hui-power-total-badge"),
|
||||
"gas-total": () => import("../badges/energy/hui-gas-total-badge"),
|
||||
"water-total": () => import("../badges/energy/hui-water-total-badge"),
|
||||
};
|
||||
|
||||
// This will not return an error card but will throw the error
|
||||
|
||||
@@ -71,6 +71,9 @@ const LAZY_LOAD_TYPES = {
|
||||
import("../cards/water/hui-water-flow-sankey-card"),
|
||||
"power-sources-graph": () =>
|
||||
import("../cards/energy/hui-power-sources-graph-card"),
|
||||
"power-total": () => import("../cards/energy/hui-power-total-card"),
|
||||
"water-total": () => import("../cards/energy/hui-water-total-card"),
|
||||
"gas-total": () => import("../cards/energy/hui-gas-total-card"),
|
||||
"power-sankey": () => import("../cards/energy/hui-power-sankey-card"),
|
||||
"entity-filter": () => import("../cards/hui-entity-filter-card"),
|
||||
error: () => import("../cards/hui-error-card"),
|
||||
|
||||
@@ -6,7 +6,6 @@ import { isComponentLoaded } from "../../../common/config/is_component_loaded";
|
||||
import { fireEvent } from "../../../common/dom/fire_event";
|
||||
import { computeDomain } from "../../../common/entity/compute_domain";
|
||||
import "../../../components/ha-spinner";
|
||||
import type { HistoryStates } from "../../../data/history";
|
||||
import { subscribeHistoryStatesTimeWindow } from "../../../data/history";
|
||||
import type { HomeAssistant } from "../../../types";
|
||||
import { findEntities } from "../common/find-entities";
|
||||
@@ -67,8 +66,6 @@ export class HuiGraphHeaderFooter
|
||||
|
||||
private _error?: string;
|
||||
|
||||
private _history?: HistoryStates;
|
||||
|
||||
private _interval?: number;
|
||||
|
||||
private _subscribed?: Promise<(() => Promise<void>) | undefined>;
|
||||
@@ -164,8 +161,24 @@ export class HuiGraphHeaderFooter
|
||||
// Message came in before we had a chance to unload
|
||||
return;
|
||||
}
|
||||
this._history = combinedHistory;
|
||||
this._computeCoordinates();
|
||||
const width = this.clientWidth || this.offsetWidth;
|
||||
// sample to 1 point per hour or 1 point per 5 pixels
|
||||
const maxDetails = Math.max(
|
||||
10,
|
||||
this._config.detail! > 1
|
||||
? Math.max(width / 5, this._config.hours_to_show!)
|
||||
: this._config.hours_to_show!
|
||||
);
|
||||
const useMean = this._config.detail !== 2;
|
||||
const { points } = coordinatesMinimalResponseCompressedState(
|
||||
combinedHistory[this._config.entity],
|
||||
width,
|
||||
width / 5,
|
||||
maxDetails,
|
||||
{ minY: this._config.limits?.min, maxY: this._config.limits?.max },
|
||||
useMean
|
||||
);
|
||||
this._coordinates = points;
|
||||
},
|
||||
this._config.hours_to_show!,
|
||||
[this._config.entity]
|
||||
@@ -177,63 +190,10 @@ export class HuiGraphHeaderFooter
|
||||
this._setRedrawTimer();
|
||||
}
|
||||
|
||||
private _computeCoordinates() {
|
||||
if (!this._history || !this._config) {
|
||||
return;
|
||||
}
|
||||
const entityHistory = this._history[this._config.entity];
|
||||
if (!entityHistory?.length) {
|
||||
return;
|
||||
}
|
||||
const width = this.clientWidth || this.offsetWidth;
|
||||
// sample to 1 point per hour or 1 point per 5 pixels
|
||||
const maxDetails = Math.max(
|
||||
10,
|
||||
this._config.detail! > 1
|
||||
? Math.max(width / 5, this._config.hours_to_show!)
|
||||
: this._config.hours_to_show!
|
||||
);
|
||||
const useMean = this._config.detail !== 2;
|
||||
const { points } = coordinatesMinimalResponseCompressedState(
|
||||
entityHistory,
|
||||
width,
|
||||
width / 5,
|
||||
maxDetails,
|
||||
{ minY: this._config.limits?.min, maxY: this._config.limits?.max },
|
||||
useMean
|
||||
);
|
||||
this._coordinates = points;
|
||||
}
|
||||
|
||||
private _redrawGraph() {
|
||||
if (!this._history || !this._config?.hours_to_show) {
|
||||
return;
|
||||
if (this._coordinates) {
|
||||
this._coordinates = [...this._coordinates];
|
||||
}
|
||||
const entityId = this._config.entity;
|
||||
const entityHistory = this._history[entityId];
|
||||
if (entityHistory?.length) {
|
||||
const purgeBeforeTimestamp =
|
||||
(Date.now() - this._config.hours_to_show * 60 * 60 * 1000) / 1000;
|
||||
let purgedHistory = entityHistory.filter(
|
||||
(entry) => entry.lu >= purgeBeforeTimestamp
|
||||
);
|
||||
if (purgedHistory.length !== entityHistory.length) {
|
||||
if (
|
||||
!purgedHistory.length ||
|
||||
purgedHistory[0].lu !== purgeBeforeTimestamp
|
||||
) {
|
||||
// Preserve the last expired state as the start boundary
|
||||
const lastExpiredState = {
|
||||
...entityHistory[entityHistory.length - purgedHistory.length - 1],
|
||||
};
|
||||
lastExpiredState.lu = purgeBeforeTimestamp;
|
||||
delete lastExpiredState.lc;
|
||||
purgedHistory = [lastExpiredState, ...purgedHistory];
|
||||
}
|
||||
this._history = { ...this._history, [entityId]: purgedHistory };
|
||||
}
|
||||
}
|
||||
this._computeCoordinates();
|
||||
}
|
||||
|
||||
private _setRedrawTimer() {
|
||||
@@ -251,7 +211,6 @@ export class HuiGraphHeaderFooter
|
||||
this._subscribed.then((unsub) => unsub?.());
|
||||
this._subscribed = undefined;
|
||||
}
|
||||
this._history = undefined;
|
||||
}
|
||||
|
||||
protected updated(changedProps: PropertyValues) {
|
||||
|
||||
@@ -631,8 +631,11 @@ class HUIRoot extends LitElement {
|
||||
`;
|
||||
}
|
||||
|
||||
private _handleWindowScroll = () => {
|
||||
this.toggleAttribute("scrolled", window.scrollY !== 0);
|
||||
private _handleContainerScroll = () => {
|
||||
this.toggleAttribute(
|
||||
"scrolled",
|
||||
this._viewRoot ? this._viewRoot.scrollTop !== 0 : false
|
||||
);
|
||||
};
|
||||
|
||||
private _locationChanged = () => {
|
||||
@@ -663,7 +666,7 @@ class HUIRoot extends LitElement {
|
||||
|
||||
protected firstUpdated(changedProps: PropertyValues) {
|
||||
super.firstUpdated(changedProps);
|
||||
window.addEventListener("scroll", this._handleWindowScroll, {
|
||||
this._viewRoot?.addEventListener("scroll", this._handleContainerScroll, {
|
||||
passive: true,
|
||||
});
|
||||
this._handleUrlChanged();
|
||||
@@ -674,7 +677,7 @@ class HUIRoot extends LitElement {
|
||||
|
||||
public connectedCallback(): void {
|
||||
super.connectedCallback();
|
||||
window.addEventListener("scroll", this._handleWindowScroll, {
|
||||
this._viewRoot?.addEventListener("scroll", this._handleContainerScroll, {
|
||||
passive: true,
|
||||
});
|
||||
window.addEventListener("popstate", this._handlePopState);
|
||||
@@ -685,10 +688,13 @@ class HUIRoot extends LitElement {
|
||||
|
||||
public disconnectedCallback(): void {
|
||||
super.disconnectedCallback();
|
||||
window.removeEventListener("scroll", this._handleWindowScroll);
|
||||
this._viewRoot?.removeEventListener("scroll", this._handleContainerScroll);
|
||||
window.removeEventListener("popstate", this._handlePopState);
|
||||
window.removeEventListener("location-changed", this._locationChanged);
|
||||
this.toggleAttribute("scrolled", window.scrollY !== 0);
|
||||
this.toggleAttribute(
|
||||
"scrolled",
|
||||
this._viewRoot ? this._viewRoot.scrollTop !== 0 : false
|
||||
);
|
||||
// Re-enable history scroll restoration when leaving the page
|
||||
window.history.scrollRestoration = "auto";
|
||||
}
|
||||
@@ -821,9 +827,11 @@ class HUIRoot extends LitElement {
|
||||
(this._restoreScroll && this._viewScrollPositions[newSelectView]) ||
|
||||
0;
|
||||
this._restoreScroll = false;
|
||||
requestAnimationFrame(() =>
|
||||
scrollTo({ behavior: "auto", top: position })
|
||||
);
|
||||
requestAnimationFrame(() => {
|
||||
if (this._viewRoot) {
|
||||
this._viewRoot.scrollTo({ behavior: "auto", top: position });
|
||||
}
|
||||
});
|
||||
}
|
||||
this._selectView(newSelectView, force);
|
||||
});
|
||||
@@ -1148,7 +1156,7 @@ class HUIRoot extends LitElement {
|
||||
const path = this.config.views[viewIndex].path || viewIndex;
|
||||
this._navigateToView(path);
|
||||
} else if (!this._editMode) {
|
||||
scrollTo({ behavior: "smooth", top: 0 });
|
||||
this._viewRoot?.scrollTo({ behavior: "smooth", top: 0 });
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1159,7 +1167,7 @@ class HUIRoot extends LitElement {
|
||||
|
||||
// Save scroll position of current view
|
||||
if (this._curView != null) {
|
||||
this._viewScrollPositions[this._curView] = window.scrollY;
|
||||
this._viewScrollPositions[this._curView] = this._viewRoot?.scrollTop ?? 0;
|
||||
}
|
||||
|
||||
viewIndex = viewIndex === undefined ? 0 : viewIndex;
|
||||
@@ -1467,9 +1475,14 @@ class HUIRoot extends LitElement {
|
||||
hui-view-container {
|
||||
position: relative;
|
||||
display: flex;
|
||||
min-height: 100vh;
|
||||
height: calc(
|
||||
100vh - var(--header-height) - var(--safe-area-inset-top) - var(
|
||||
--view-container-padding-top,
|
||||
0px
|
||||
)
|
||||
);
|
||||
box-sizing: border-box;
|
||||
padding-top: calc(
|
||||
margin-top: calc(
|
||||
var(--header-height) + var(--safe-area-inset-top) +
|
||||
var(--view-container-padding-top, 0px)
|
||||
);
|
||||
@@ -1485,8 +1498,6 @@ class HUIRoot extends LitElement {
|
||||
padding-inline-start: var(--safe-area-inset-left);
|
||||
}
|
||||
hui-view-container > * {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex: 1 1 100%;
|
||||
max-width: 100%;
|
||||
}
|
||||
@@ -1494,7 +1505,12 @@ class HUIRoot extends LitElement {
|
||||
* In edit mode we have the tab bar on a new line *
|
||||
*/
|
||||
hui-view-container.has-tab-bar {
|
||||
padding-top: calc(
|
||||
height: calc(
|
||||
100vh - var(--header-height, 56px) - calc(
|
||||
var(--tab-bar-height, 56px) - 2px
|
||||
) - var(--safe-area-inset-top, 0px)
|
||||
);
|
||||
margin-top: calc(
|
||||
var(--header-height, 56px) +
|
||||
calc(var(--tab-bar-height, 56px) - 2px) +
|
||||
var(--safe-area-inset-top, 0px)
|
||||
|
||||
@@ -418,11 +418,15 @@ export class SectionsView extends LitElement implements LovelaceViewElement {
|
||||
}
|
||||
|
||||
private _toggleView() {
|
||||
// The scroll container is the hui-view-container parent
|
||||
const scrollContainer = this.closest("hui-view-container");
|
||||
const scrollTop = scrollContainer?.scrollTop ?? 0;
|
||||
|
||||
// Save current scroll position
|
||||
if (this._sidebarTabActive) {
|
||||
this._sidebarScrollTop = window.scrollY;
|
||||
this._sidebarScrollTop = scrollTop;
|
||||
} else {
|
||||
this._contentScrollTop = window.scrollY;
|
||||
this._contentScrollTop = scrollTop;
|
||||
}
|
||||
|
||||
this._sidebarTabActive = !this._sidebarTabActive;
|
||||
@@ -438,7 +442,7 @@ export class SectionsView extends LitElement implements LovelaceViewElement {
|
||||
const scrollY = this._sidebarTabActive
|
||||
? this._sidebarScrollTop
|
||||
: this._contentScrollTop;
|
||||
window.scrollTo(0, scrollY);
|
||||
scrollContainer?.scrollTo(0, scrollY);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -461,7 +465,6 @@ export class SectionsView extends LitElement implements LovelaceViewElement {
|
||||
--column-min-width: var(--ha-view-sections-column-min-width, 320px);
|
||||
--top-margin: var(--ha-view-sections-extra-top-margin, 80px);
|
||||
display: block;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
@media (max-width: 600px) {
|
||||
@@ -471,9 +474,7 @@ export class SectionsView extends LitElement implements LovelaceViewElement {
|
||||
}
|
||||
|
||||
.wrapper {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
min-height: calc(100% - 2 * var(--row-gap));
|
||||
display: block;
|
||||
padding: var(--row-gap) var(--column-gap);
|
||||
box-sizing: content-box;
|
||||
margin: 0 auto;
|
||||
@@ -506,7 +507,6 @@ export class SectionsView extends LitElement implements LovelaceViewElement {
|
||||
gap: var(--row-gap) var(--column-gap);
|
||||
padding: var(--row-gap) 0;
|
||||
align-items: flex-start;
|
||||
flex: 1 0 auto;
|
||||
}
|
||||
|
||||
.wrapper.has-sidebar .container {
|
||||
|
||||
@@ -4,6 +4,7 @@ import { customElement, property, state } from "lit/decorators";
|
||||
import { applyThemesOnElement } from "../../../common/dom/apply_themes_on_element";
|
||||
import { listenMediaQuery } from "../../../common/dom/media_query";
|
||||
import type { LovelaceViewConfig } from "../../../data/lovelace/config/view";
|
||||
import { haStyleScrollbar } from "../../../resources/styles";
|
||||
import type { HomeAssistant } from "../../../types";
|
||||
|
||||
type BackgroundConfig = LovelaceViewConfig["background"];
|
||||
@@ -22,6 +23,7 @@ class HuiViewContainer extends LitElement {
|
||||
|
||||
public connectedCallback(): void {
|
||||
super.connectedCallback();
|
||||
this.classList.add("ha-scrollbar");
|
||||
this._setUpMediaQuery();
|
||||
this._applyTheme();
|
||||
}
|
||||
@@ -74,11 +76,16 @@ class HuiViewContainer extends LitElement {
|
||||
}
|
||||
}
|
||||
|
||||
static styles = css`
|
||||
:host {
|
||||
display: relative;
|
||||
}
|
||||
`;
|
||||
static styles = [
|
||||
haStyleScrollbar,
|
||||
css`
|
||||
:host {
|
||||
display: block;
|
||||
height: 100%;
|
||||
-webkit-overflow-scrolling: touch;
|
||||
}
|
||||
`,
|
||||
];
|
||||
}
|
||||
|
||||
declare global {
|
||||
|
||||
@@ -102,14 +102,6 @@ export const getMyRedirects = (): Redirects => ({
|
||||
component: "zwave_js",
|
||||
redirect: "/config/zwave_js/dashboard",
|
||||
},
|
||||
config_matter: {
|
||||
component: "matter",
|
||||
redirect: "/config/matter/dashboard",
|
||||
},
|
||||
config_thread: {
|
||||
component: "thread",
|
||||
redirect: "/config/thread",
|
||||
},
|
||||
add_zigbee_device: {
|
||||
component: "zha",
|
||||
redirect: "/config/zha/add",
|
||||
|
||||
@@ -244,17 +244,20 @@ export const haStyleDialogFixedTop = css`
|
||||
`;
|
||||
|
||||
export const haStyleScrollbar = css`
|
||||
.ha-scrollbar::-webkit-scrollbar {
|
||||
.ha-scrollbar::-webkit-scrollbar,
|
||||
:host(.ha-scrollbar)::-webkit-scrollbar {
|
||||
width: 0.4rem;
|
||||
height: 0.4rem;
|
||||
}
|
||||
|
||||
.ha-scrollbar::-webkit-scrollbar-thumb {
|
||||
.ha-scrollbar::-webkit-scrollbar-thumb,
|
||||
:host(.ha-scrollbar)::-webkit-scrollbar-thumb {
|
||||
border-radius: var(--ha-border-radius-sm);
|
||||
background: var(--scrollbar-thumb-color);
|
||||
}
|
||||
|
||||
.ha-scrollbar {
|
||||
.ha-scrollbar,
|
||||
:host(.ha-scrollbar) {
|
||||
overflow-y: auto;
|
||||
scrollbar-color: var(--scrollbar-thumb-color) transparent;
|
||||
scrollbar-width: thin;
|
||||
|
||||
@@ -359,8 +359,6 @@ export const darkColorStyles = css`
|
||||
--outline-hover-color: rgba(225, 225, 225, 0.24);
|
||||
--shadow-color: rgba(0, 0, 0, 0.48);
|
||||
|
||||
--scrollbar-thumb-color: rgb(110, 110, 110);
|
||||
|
||||
--mdc-ripple-color: #aaaaaa;
|
||||
--mdc-linear-progress-buffer-color: rgba(255, 255, 255, 0.1);
|
||||
|
||||
|
||||
@@ -51,21 +51,6 @@ export const mainStyles = css`
|
||||
|
||||
/* dialog backdrop filter */
|
||||
--ha-dialog-scrim-backdrop-filter: brightness(68%);
|
||||
|
||||
/* scrollbar */
|
||||
scrollbar-color: var(--scrollbar-thumb-color) transparent;
|
||||
scrollbar-width: thin;
|
||||
}
|
||||
|
||||
html::-webkit-scrollbar {
|
||||
width: 0.4rem;
|
||||
height: 0.4rem;
|
||||
}
|
||||
|
||||
html::-webkit-scrollbar-thumb {
|
||||
border-radius: var(--ha-border-radius-sm);
|
||||
background: var(--scrollbar-thumb-color);
|
||||
border: 3px solid transparent;
|
||||
}
|
||||
`;
|
||||
|
||||
|
||||
@@ -548,7 +548,7 @@
|
||||
},
|
||||
"template": {
|
||||
"yaml_warning": "It appears you may be writing YAML into this template field (saw ''{string}''), which is likely incorrect. This field is intended for templates only (e.g. '{{ states(sensor.test) > 0 }}' ).",
|
||||
"learn_more": "Learn more about templating"
|
||||
"learn_more": "Learn more about templating."
|
||||
},
|
||||
"text": {
|
||||
"show_password": "Show password",
|
||||
@@ -679,9 +679,9 @@
|
||||
"no_entities": "You don't have any entities",
|
||||
"no_match": "No entities found for {term}",
|
||||
"show_entities": "Show entities",
|
||||
"new_entity": "Creates a new entity",
|
||||
"new_entity": "Create a new entity",
|
||||
"placeholder": "Select an entity",
|
||||
"create_helper": "Create a new {domain, select, \n undefined {} \n other {{domain} }\n }helper",
|
||||
"create_helper": "Create a new {domain, select, \n undefined {} \n other {{domain} }\n } helper.",
|
||||
"unknown": "Unknown entity selected"
|
||||
},
|
||||
"entity-name-picker": {
|
||||
@@ -1524,7 +1524,6 @@
|
||||
"settings": "Settings",
|
||||
"edit": "Edit entity",
|
||||
"details": "Details",
|
||||
"toggle_yaml_mode": "Toggle YAML mode",
|
||||
"translated": "Translated",
|
||||
"raw": "Raw",
|
||||
"back_to_info": "Back to info",
|
||||
@@ -3812,7 +3811,7 @@
|
||||
"grid": {
|
||||
"title": "Electricity grid",
|
||||
"sub": "Configure the amount of energy that you consume from the grid and, if you produce energy, give back to the grid. This allows Home Assistant to track your whole home energy usage.",
|
||||
"learn_more": "More information on how to get started",
|
||||
"learn_more": "More information on how to get started.",
|
||||
"grid_connections": "Grid connections",
|
||||
"add_connection": "Add grid connection",
|
||||
"edit_connection": "Edit grid connection",
|
||||
@@ -3873,7 +3872,7 @@
|
||||
"solar": {
|
||||
"title": "Solar panels",
|
||||
"sub": "Let Home Assistant monitor your solar panels and give you insight on their performance.",
|
||||
"learn_more": "More information on how to get started",
|
||||
"learn_more": "More information on how to get started.",
|
||||
"solar_production": "Solar production",
|
||||
"edit_solar_production": "Edit solar production",
|
||||
"delete_solar_production": "Remove solar production",
|
||||
@@ -3896,7 +3895,7 @@
|
||||
"battery": {
|
||||
"title": "Home battery storage",
|
||||
"sub": "If you have a battery system, you can configure it to monitor how much energy was stored and used from your battery.",
|
||||
"learn_more": "More information on how to get started",
|
||||
"learn_more": "More information on how to get started.",
|
||||
"battery_systems": "Battery systems",
|
||||
"edit_battery_system": "Edit battery system",
|
||||
"delete_battery_system": "Remove battery system",
|
||||
@@ -3923,7 +3922,7 @@
|
||||
"gas": {
|
||||
"title": "Gas consumption",
|
||||
"sub": "Let Home Assistant monitor your gas usage.",
|
||||
"learn_more": "More information on how to get started",
|
||||
"learn_more": "More information on how to get started.",
|
||||
"gas_consumption": "Gas consumption",
|
||||
"edit_gas_source": "Edit gas source",
|
||||
"delete_gas_source": "Remove gas source",
|
||||
@@ -3952,7 +3951,7 @@
|
||||
"water": {
|
||||
"title": "Water consumption",
|
||||
"sub": "Let Home Assistant monitor your water usage.",
|
||||
"learn_more": "More information on how to get started",
|
||||
"learn_more": "More information on how to get started.",
|
||||
"water_consumption": "Water consumption",
|
||||
"edit_water_source": "Edit water source",
|
||||
"delete_water_source": "Remove water source",
|
||||
@@ -3978,7 +3977,7 @@
|
||||
"device_consumption": {
|
||||
"title": "Individual electrical devices",
|
||||
"sub": "Tracking the energy usage of individual devices allows Home Assistant to break down your energy usage by device.",
|
||||
"learn_more": "More information on how to get started",
|
||||
"learn_more": "More information on how to get started.",
|
||||
"add_stat": "Pick entity to track energy of",
|
||||
"selected_stat": "Tracking energy for",
|
||||
"devices": "Devices",
|
||||
@@ -3997,7 +3996,7 @@
|
||||
"device_consumption_water": {
|
||||
"title": "Individual water devices",
|
||||
"sub": "Tracking the water usage of individual devices allows Home Assistant to break down your water usage by device.",
|
||||
"learn_more": "More information on how to get started",
|
||||
"learn_more": "More information on how to get started.",
|
||||
"devices": "Devices",
|
||||
"add_device": "Add device",
|
||||
"dialog": {
|
||||
@@ -5749,7 +5748,7 @@
|
||||
"key_not_null": "The field key must not be empty.",
|
||||
"key_not_unique": "The field key must not be the same value as another field.",
|
||||
"fields": "Fields",
|
||||
"link_help_fields": "Learn more about fields",
|
||||
"link_help_fields": "Learn more about fields.",
|
||||
"add_fields": "Add fields",
|
||||
"add_field": "Add field",
|
||||
"field": "field",
|
||||
@@ -5777,7 +5776,7 @@
|
||||
"delete_confirm_text": "{name} will be permanently deleted.",
|
||||
"sequence": "Sequence",
|
||||
"sequence_sentence": "The sequence of actions of this script.",
|
||||
"link_available_actions": "Learn more about available actions",
|
||||
"link_available_actions": "Learn more about available actions.",
|
||||
"leave": {
|
||||
"unsaved_new_title": "Save new script?",
|
||||
"unsaved_new_text": "You can save your changes, or delete this script. You can't undo this action.",
|
||||
@@ -6050,7 +6049,7 @@
|
||||
"no_hooks_yet_link_integration": "webhook-based integration",
|
||||
"no_hooks_yet2": " or by creating a ",
|
||||
"no_hooks_yet_link_automation": "webhook automation",
|
||||
"link_learn_more": "Learn more about creating webhook-powered automations",
|
||||
"link_learn_more": "Learn more about creating webhook-powered automations.",
|
||||
"loading": "Loading…",
|
||||
"manage": "Manage",
|
||||
"disable_hook_error_msg": "Failed to disable webhook:"
|
||||
|
||||
265
yarn.lock
265
yarn.lock
@@ -1990,75 +1990,74 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@html-eslint/core@npm:^0.57.0":
|
||||
version: 0.57.0
|
||||
resolution: "@html-eslint/core@npm:0.57.0"
|
||||
"@html-eslint/core@npm:^0.56.0":
|
||||
version: 0.56.0
|
||||
resolution: "@html-eslint/core@npm:0.56.0"
|
||||
dependencies:
|
||||
"@html-eslint/types": "npm:^0.57.0"
|
||||
"@html-eslint/types": "npm:^0.56.0"
|
||||
eslint: "npm:^9.39.1"
|
||||
html-standard: "npm:^0.0.13"
|
||||
checksum: 10/18b7aaf455969008dc5b79f6fd4b38792d893053e77c098c56a9238fe9b3ac3fa36441a88b908ade71de2f5179d5b4c45f552d7da5beff1d5c8df9cb3fd14e63
|
||||
checksum: 10/0722e7405e56b256c471229dbd0ccb49cf0edd3e5224a087240f1954c74af0a6f289e5be0b83957480f1fa5abf6f7cbad7212134a6872a3fd66e1dc1ad879d66
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@html-eslint/eslint-plugin@npm:0.57.0":
|
||||
version: 0.57.0
|
||||
resolution: "@html-eslint/eslint-plugin@npm:0.57.0"
|
||||
"@html-eslint/eslint-plugin@npm:0.56.0":
|
||||
version: 0.56.0
|
||||
resolution: "@html-eslint/eslint-plugin@npm:0.56.0"
|
||||
dependencies:
|
||||
"@eslint/plugin-kit": "npm:^0.4.1"
|
||||
"@html-eslint/core": "npm:^0.57.0"
|
||||
"@html-eslint/parser": "npm:^0.57.0"
|
||||
"@html-eslint/template-parser": "npm:^0.57.0"
|
||||
"@html-eslint/template-syntax-parser": "npm:^0.57.0"
|
||||
"@html-eslint/types": "npm:^0.57.0"
|
||||
"@rviscomi/capo.js": "npm:^2.1.0"
|
||||
"@html-eslint/core": "npm:^0.56.0"
|
||||
"@html-eslint/parser": "npm:^0.56.0"
|
||||
"@html-eslint/template-parser": "npm:^0.56.0"
|
||||
"@html-eslint/template-syntax-parser": "npm:^0.56.0"
|
||||
"@html-eslint/types": "npm:^0.56.0"
|
||||
peerDependencies:
|
||||
eslint: ">=8.0.0 || ^10.0.0-0"
|
||||
checksum: 10/34cf11eaab3c07436c9c8b2896ed331c3ba5d591db5d8a8ff79d19b174e6e090323eb71e1368ad93d2afa945d4740749c599436a03be1195d4e4a4b0d3d9e9b6
|
||||
checksum: 10/16c5d638045266ca201b5dc154b3706262801668b2edde4f0905bdba9ba2e14b7175eacf9ca7d2ad5a5a03e3369843822d34ee607b6b7fbbeb020ac7f87629fb
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@html-eslint/parser@npm:^0.57.0":
|
||||
version: 0.57.0
|
||||
resolution: "@html-eslint/parser@npm:0.57.0"
|
||||
"@html-eslint/parser@npm:^0.56.0":
|
||||
version: 0.56.0
|
||||
resolution: "@html-eslint/parser@npm:0.56.0"
|
||||
dependencies:
|
||||
"@eslint/css-tree": "npm:^3.6.9"
|
||||
"@html-eslint/template-syntax-parser": "npm:^0.57.0"
|
||||
"@html-eslint/types": "npm:^0.57.0"
|
||||
"@html-eslint/template-syntax-parser": "npm:^0.56.0"
|
||||
"@html-eslint/types": "npm:^0.56.0"
|
||||
css-tree: "npm:^3.1.0"
|
||||
es-html-parser: "npm:0.3.1"
|
||||
checksum: 10/d742a26ef8122eab82e35ab27de6fe40cd45d2ac59ade9bed9d16df0da3cd18425c7892fedd245b9d60da2a4fbfb8c6afe05b1b6415033ab8fad996b94be020e
|
||||
checksum: 10/1fead2be97481f461ee7030f4ea9274e5f969540118b4429e3eea361f62138660c1b7538668c7f8d55a8ae6985deff3056968d71bae62b91fb001d4209a24b50
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@html-eslint/template-parser@npm:^0.57.0":
|
||||
version: 0.57.0
|
||||
resolution: "@html-eslint/template-parser@npm:0.57.0"
|
||||
"@html-eslint/template-parser@npm:^0.56.0":
|
||||
version: 0.56.0
|
||||
resolution: "@html-eslint/template-parser@npm:0.56.0"
|
||||
dependencies:
|
||||
"@html-eslint/types": "npm:^0.57.0"
|
||||
"@html-eslint/types": "npm:^0.56.0"
|
||||
es-html-parser: "npm:0.3.1"
|
||||
checksum: 10/160d7f6156f242ed7bd4e7f13d79c350bf5db7fef089ba7b404ef770d80547620e9ee860ead8892a4079668db1cdccf6a6c6b91183a8c478a634314b39efea32
|
||||
checksum: 10/45e41dc8fb46336f40d1b78ef55ee3150d7a1034d393529eb40ce37a7d0a8fa04f6ed8f9a63478ff884d9588b1359b97a799681a37cd485d237dce867b7f9d20
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@html-eslint/template-syntax-parser@npm:^0.57.0":
|
||||
version: 0.57.0
|
||||
resolution: "@html-eslint/template-syntax-parser@npm:0.57.0"
|
||||
"@html-eslint/template-syntax-parser@npm:^0.56.0":
|
||||
version: 0.56.0
|
||||
resolution: "@html-eslint/template-syntax-parser@npm:0.56.0"
|
||||
dependencies:
|
||||
"@html-eslint/types": "npm:^0.57.0"
|
||||
checksum: 10/147d8d15ebc5ea9b75eea04463b9f29cfc476be2e98c5a2129442be6f66d32a9e8bb11a1be13cc3778df25e14d7ed1cd345342951ecec05292545f64bb3d92c6
|
||||
"@html-eslint/types": "npm:^0.56.0"
|
||||
checksum: 10/2cc4f2cbfa58c6381b2542ca86e424a97429326aa0b8b6b09e0a51d27b0e26fd723a4550e4c17536e00cfd506cbd0c61d8fd3dff1c829714c4432406096b4a01
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@html-eslint/types@npm:^0.57.0":
|
||||
version: 0.57.0
|
||||
resolution: "@html-eslint/types@npm:0.57.0"
|
||||
"@html-eslint/types@npm:^0.56.0":
|
||||
version: 0.56.0
|
||||
resolution: "@html-eslint/types@npm:0.56.0"
|
||||
dependencies:
|
||||
"@types/css-tree": "npm:^2.3.11"
|
||||
"@types/estree": "npm:^1.0.6"
|
||||
es-html-parser: "npm:0.3.1"
|
||||
eslint: "npm:^9.39.1"
|
||||
checksum: 10/44d0bde592786a2da966beab13c3d543e6669b1e38b6e5feea0f01121eec928be0081969df3ada1f27c9bd43d6286596afa56a2e075da843251079a940cf0825
|
||||
checksum: 10/5359ccfb8f431ccedfe7d9c0b20d883d19bbb6a24eee925c036c7774d6f2177eda021826abbc6f947b59c2364d7cf25a596591e852c1141000a3fab6ea70acc9
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@@ -4258,13 +4257,6 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@rviscomi/capo.js@npm:^2.1.0":
|
||||
version: 2.1.0
|
||||
resolution: "@rviscomi/capo.js@npm:2.1.0"
|
||||
checksum: 10/83ce30106ec6bd4b4791af12556119c568cb9d0ec7550b7b015a8c2c1c49687d8c6605564415d9d85e991581958212109ee5caa0db4166c1d3628033175e80b8
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@shoelace-style/animations@npm:^1.2.0":
|
||||
version: 1.2.0
|
||||
resolution: "@shoelace-style/animations@npm:1.2.0"
|
||||
@@ -5071,138 +5063,138 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@typescript-eslint/eslint-plugin@npm:8.56.1":
|
||||
version: 8.56.1
|
||||
resolution: "@typescript-eslint/eslint-plugin@npm:8.56.1"
|
||||
"@typescript-eslint/eslint-plugin@npm:8.56.0":
|
||||
version: 8.56.0
|
||||
resolution: "@typescript-eslint/eslint-plugin@npm:8.56.0"
|
||||
dependencies:
|
||||
"@eslint-community/regexpp": "npm:^4.12.2"
|
||||
"@typescript-eslint/scope-manager": "npm:8.56.1"
|
||||
"@typescript-eslint/type-utils": "npm:8.56.1"
|
||||
"@typescript-eslint/utils": "npm:8.56.1"
|
||||
"@typescript-eslint/visitor-keys": "npm:8.56.1"
|
||||
"@typescript-eslint/scope-manager": "npm:8.56.0"
|
||||
"@typescript-eslint/type-utils": "npm:8.56.0"
|
||||
"@typescript-eslint/utils": "npm:8.56.0"
|
||||
"@typescript-eslint/visitor-keys": "npm:8.56.0"
|
||||
ignore: "npm:^7.0.5"
|
||||
natural-compare: "npm:^1.4.0"
|
||||
ts-api-utils: "npm:^2.4.0"
|
||||
peerDependencies:
|
||||
"@typescript-eslint/parser": ^8.56.1
|
||||
"@typescript-eslint/parser": ^8.56.0
|
||||
eslint: ^8.57.0 || ^9.0.0 || ^10.0.0
|
||||
typescript: ">=4.8.4 <6.0.0"
|
||||
checksum: 10/669d19cff91fcad5fe34dba97cc8c0c2df3160ae14646759fb23dfd6ffbb861d00d8d081e74d1060d544bfba0ea4d05588c5b73ae104907af26cc18189c0d139
|
||||
checksum: 10/44201eae518c759cf3110f7e0a374372ef22bffa3cca61685aebe916b06bcb5f3ed6ffedba252199dca0006dfc22c54b132cd0337fd15e8c083eda22f9cf6b0c
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@typescript-eslint/parser@npm:8.56.1":
|
||||
version: 8.56.1
|
||||
resolution: "@typescript-eslint/parser@npm:8.56.1"
|
||||
"@typescript-eslint/parser@npm:8.56.0":
|
||||
version: 8.56.0
|
||||
resolution: "@typescript-eslint/parser@npm:8.56.0"
|
||||
dependencies:
|
||||
"@typescript-eslint/scope-manager": "npm:8.56.1"
|
||||
"@typescript-eslint/types": "npm:8.56.1"
|
||||
"@typescript-eslint/typescript-estree": "npm:8.56.1"
|
||||
"@typescript-eslint/visitor-keys": "npm:8.56.1"
|
||||
"@typescript-eslint/scope-manager": "npm:8.56.0"
|
||||
"@typescript-eslint/types": "npm:8.56.0"
|
||||
"@typescript-eslint/typescript-estree": "npm:8.56.0"
|
||||
"@typescript-eslint/visitor-keys": "npm:8.56.0"
|
||||
debug: "npm:^4.4.3"
|
||||
peerDependencies:
|
||||
eslint: ^8.57.0 || ^9.0.0 || ^10.0.0
|
||||
typescript: ">=4.8.4 <6.0.0"
|
||||
checksum: 10/280b041a69153caf9e721b307781830483dd39d881b02d993156635bd8600e30e6a816aaead8bdd662ae5149b8870aef7b3823d3b98ec974d924c23a786fb6d9
|
||||
checksum: 10/9bdb2c7915665a1031499049974997020bbc34557803a8c3718b323d5583a3fdfc27797ec714b617743225c8dce9ab589eb442b71c435b464ad45365a6fbba57
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@typescript-eslint/project-service@npm:8.56.1":
|
||||
version: 8.56.1
|
||||
resolution: "@typescript-eslint/project-service@npm:8.56.1"
|
||||
"@typescript-eslint/project-service@npm:8.56.0":
|
||||
version: 8.56.0
|
||||
resolution: "@typescript-eslint/project-service@npm:8.56.0"
|
||||
dependencies:
|
||||
"@typescript-eslint/tsconfig-utils": "npm:^8.56.1"
|
||||
"@typescript-eslint/types": "npm:^8.56.1"
|
||||
"@typescript-eslint/tsconfig-utils": "npm:^8.56.0"
|
||||
"@typescript-eslint/types": "npm:^8.56.0"
|
||||
debug: "npm:^4.4.3"
|
||||
peerDependencies:
|
||||
typescript: ">=4.8.4 <6.0.0"
|
||||
checksum: 10/5e7fdc95aebcefc72fec77806bb0821a9a59e5e88f86d72b15ad011eb6110da05419b803875f021716a219fc7fb8517331a6736364344c8613a90209539a6d32
|
||||
checksum: 10/b46cc78bfb50ee84cb12e2e99c1a3d9606161980cf56ba33be6244ccff2ba4c78ceec46706ad597508fda167e0f965d849c1c516400ad41259027be3fbd815eb
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@typescript-eslint/scope-manager@npm:8.56.1":
|
||||
version: 8.56.1
|
||||
resolution: "@typescript-eslint/scope-manager@npm:8.56.1"
|
||||
"@typescript-eslint/scope-manager@npm:8.56.0":
|
||||
version: 8.56.0
|
||||
resolution: "@typescript-eslint/scope-manager@npm:8.56.0"
|
||||
dependencies:
|
||||
"@typescript-eslint/types": "npm:8.56.1"
|
||||
"@typescript-eslint/visitor-keys": "npm:8.56.1"
|
||||
checksum: 10/f358cf8bd32952eed005d4f34c1e95805baefe35abee96d866222b0eff8027cc02f831cee04b308707d74db2b415437a134191207b4213ee8acbc6d67a435616
|
||||
"@typescript-eslint/types": "npm:8.56.0"
|
||||
"@typescript-eslint/visitor-keys": "npm:8.56.0"
|
||||
checksum: 10/3662355120ea8e21ce01c999decbd2a09fe4edb1c01e376fe347952d968ecfedff99b9484334e133e41284a15f2e1bc8efd490b1e73a16980614445c25b07b0d
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@typescript-eslint/tsconfig-utils@npm:8.56.1, @typescript-eslint/tsconfig-utils@npm:^8.56.1":
|
||||
version: 8.56.1
|
||||
resolution: "@typescript-eslint/tsconfig-utils@npm:8.56.1"
|
||||
"@typescript-eslint/tsconfig-utils@npm:8.56.0, @typescript-eslint/tsconfig-utils@npm:^8.56.0":
|
||||
version: 8.56.0
|
||||
resolution: "@typescript-eslint/tsconfig-utils@npm:8.56.0"
|
||||
peerDependencies:
|
||||
typescript: ">=4.8.4 <6.0.0"
|
||||
checksum: 10/d509f1ae4b14969173e498db6d15c833b6407db456c7fca9e25396798a35014229a73754691f353c4a99f5f0bbb4535b4144f42f84e596645a16d88a2022135f
|
||||
checksum: 10/b1834aeffcdc07835eae0bf52aca573cba7e6528b5c1483e9b1f7f4f9e1f6450a8650796be11140e0437caf7eb1b0f9711c22989c8294547534f12614a759760
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@typescript-eslint/type-utils@npm:8.56.1":
|
||||
version: 8.56.1
|
||||
resolution: "@typescript-eslint/type-utils@npm:8.56.1"
|
||||
"@typescript-eslint/type-utils@npm:8.56.0":
|
||||
version: 8.56.0
|
||||
resolution: "@typescript-eslint/type-utils@npm:8.56.0"
|
||||
dependencies:
|
||||
"@typescript-eslint/types": "npm:8.56.1"
|
||||
"@typescript-eslint/typescript-estree": "npm:8.56.1"
|
||||
"@typescript-eslint/utils": "npm:8.56.1"
|
||||
"@typescript-eslint/types": "npm:8.56.0"
|
||||
"@typescript-eslint/typescript-estree": "npm:8.56.0"
|
||||
"@typescript-eslint/utils": "npm:8.56.0"
|
||||
debug: "npm:^4.4.3"
|
||||
ts-api-utils: "npm:^2.4.0"
|
||||
peerDependencies:
|
||||
eslint: ^8.57.0 || ^9.0.0 || ^10.0.0
|
||||
typescript: ">=4.8.4 <6.0.0"
|
||||
checksum: 10/2b07c674c26d797d05c05779ac5c89761b6b96680ecaf01440957727d12c6d06a2e48f0b139e45752eb4b53bf13c03940628656c519d362082b716d6a0ece6d9
|
||||
checksum: 10/f272b9acc004f125cbf0df18265a43ba50cd3666262afc663585acdd1be6b6b30724bd8cf4cd5aa2757b7f10ceafa92fd1af30c1931fb22ac38521eda7f79c89
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@typescript-eslint/types@npm:8.56.1, @typescript-eslint/types@npm:^8.56.1":
|
||||
version: 8.56.1
|
||||
resolution: "@typescript-eslint/types@npm:8.56.1"
|
||||
checksum: 10/4bcffab5b0fd48adb731fcade86a776ca4a66e229defa5a282b58ba9c95af16ffc459a7d188e27c988a35be1f6fb5b812f9cf0952692eac38d5b3e87daafb20a
|
||||
"@typescript-eslint/types@npm:8.56.0, @typescript-eslint/types@npm:^8.56.0":
|
||||
version: 8.56.0
|
||||
resolution: "@typescript-eslint/types@npm:8.56.0"
|
||||
checksum: 10/d7549535c99d9202742bf0191bcc2822c2d18a03e206be9ad5a6f6b0902de7381c93e8c238754fe5d1dfdcc22d7e3bbafa032f63ba165d6dc03e180f84b138f9
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@typescript-eslint/typescript-estree@npm:8.56.1":
|
||||
version: 8.56.1
|
||||
resolution: "@typescript-eslint/typescript-estree@npm:8.56.1"
|
||||
"@typescript-eslint/typescript-estree@npm:8.56.0":
|
||||
version: 8.56.0
|
||||
resolution: "@typescript-eslint/typescript-estree@npm:8.56.0"
|
||||
dependencies:
|
||||
"@typescript-eslint/project-service": "npm:8.56.1"
|
||||
"@typescript-eslint/tsconfig-utils": "npm:8.56.1"
|
||||
"@typescript-eslint/types": "npm:8.56.1"
|
||||
"@typescript-eslint/visitor-keys": "npm:8.56.1"
|
||||
"@typescript-eslint/project-service": "npm:8.56.0"
|
||||
"@typescript-eslint/tsconfig-utils": "npm:8.56.0"
|
||||
"@typescript-eslint/types": "npm:8.56.0"
|
||||
"@typescript-eslint/visitor-keys": "npm:8.56.0"
|
||||
debug: "npm:^4.4.3"
|
||||
minimatch: "npm:^10.2.2"
|
||||
minimatch: "npm:^9.0.5"
|
||||
semver: "npm:^7.7.3"
|
||||
tinyglobby: "npm:^0.2.15"
|
||||
ts-api-utils: "npm:^2.4.0"
|
||||
peerDependencies:
|
||||
typescript: ">=4.8.4 <6.0.0"
|
||||
checksum: 10/af39dae0a8fada72295a11f0efb49f311241134b0a3d819100eeda6a2f92368844645873ba785de5513ad541cd9c2ba17b9bfed2679daac4682fa2a3b627f087
|
||||
checksum: 10/55c8cfc7e265f320d780e69a677838821225fad8b853108ce2095f01509bf2ee8943280df9ac75560ed86265ef0e0a979ae4cb375d712f648b336032de79d19b
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@typescript-eslint/utils@npm:8.56.1":
|
||||
version: 8.56.1
|
||||
resolution: "@typescript-eslint/utils@npm:8.56.1"
|
||||
"@typescript-eslint/utils@npm:8.56.0":
|
||||
version: 8.56.0
|
||||
resolution: "@typescript-eslint/utils@npm:8.56.0"
|
||||
dependencies:
|
||||
"@eslint-community/eslint-utils": "npm:^4.9.1"
|
||||
"@typescript-eslint/scope-manager": "npm:8.56.1"
|
||||
"@typescript-eslint/types": "npm:8.56.1"
|
||||
"@typescript-eslint/typescript-estree": "npm:8.56.1"
|
||||
"@typescript-eslint/scope-manager": "npm:8.56.0"
|
||||
"@typescript-eslint/types": "npm:8.56.0"
|
||||
"@typescript-eslint/typescript-estree": "npm:8.56.0"
|
||||
peerDependencies:
|
||||
eslint: ^8.57.0 || ^9.0.0 || ^10.0.0
|
||||
typescript: ">=4.8.4 <6.0.0"
|
||||
checksum: 10/528cbd187d8288a8cfce24a043f993b93711087f53d2b6f95cdd615a1a4087af1dab083a747761af97474a621c7b14f11c84ee50c250f31566ebc64cf73867fe
|
||||
checksum: 10/f357bd15fe568cba0b89371e9a724eda38d78361a21dc0c4f49b0af4a23a140c77e2a8c6285c6fe8d8277e256a8a137aef7bcf6d97428eecd0c6e72ef08849ae
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@typescript-eslint/visitor-keys@npm:8.56.1":
|
||||
version: 8.56.1
|
||||
resolution: "@typescript-eslint/visitor-keys@npm:8.56.1"
|
||||
"@typescript-eslint/visitor-keys@npm:8.56.0":
|
||||
version: 8.56.0
|
||||
resolution: "@typescript-eslint/visitor-keys@npm:8.56.0"
|
||||
dependencies:
|
||||
"@typescript-eslint/types": "npm:8.56.1"
|
||||
"@typescript-eslint/types": "npm:8.56.0"
|
||||
eslint-visitor-keys: "npm:^5.0.0"
|
||||
checksum: 10/efed6a9867e7be203eec543e5a65da5aaec96aae55fba6fe74a305bf600e57c707764835e82bb8eb541f49a9b70442ff1e1a0ecf3543c78c91b84dda43b95c53
|
||||
checksum: 10/1eaa26ffe8a2c83d42d428beef207d793aef73c2e306f94e716d39519eaaa07547da898c7d63a5c406a3662895d735b4b1f33b513a1addb69473c65e7d92a2b5
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@@ -6086,12 +6078,12 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"barcode-detector@npm:3.1.0":
|
||||
version: 3.1.0
|
||||
resolution: "barcode-detector@npm:3.1.0"
|
||||
"barcode-detector@npm:3.0.8":
|
||||
version: 3.0.8
|
||||
resolution: "barcode-detector@npm:3.0.8"
|
||||
dependencies:
|
||||
zxing-wasm: "npm:3.0.0"
|
||||
checksum: 10/60767161081b827e290b60bb3416999dee616bab39291ee55565df9b72d59f0bbbf511fd3bb85db18eee7c0ad9acf1ff90359cdb21e10f80793acd0105c86a1d
|
||||
zxing-wasm: "npm:2.2.4"
|
||||
checksum: 10/7de6225f659c69a0f4101d080a9e0812f2404c485fa2406424b8b13eaff274f6e7405c94de24827a09def52c32a63b19b9c9fba61c5274b074d558f696ec1684
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@@ -9200,7 +9192,7 @@ __metadata:
|
||||
"@fullcalendar/luxon3": "npm:6.1.20"
|
||||
"@fullcalendar/timegrid": "npm:6.1.20"
|
||||
"@home-assistant/webawesome": "npm:3.2.1-ha.3"
|
||||
"@html-eslint/eslint-plugin": "npm:0.57.0"
|
||||
"@html-eslint/eslint-plugin": "npm:0.56.0"
|
||||
"@lezer/highlight": "npm:1.2.3"
|
||||
"@lit-labs/motion": "npm:1.1.0"
|
||||
"@lit-labs/observers": "npm:2.1.0"
|
||||
@@ -9268,7 +9260,7 @@ __metadata:
|
||||
app-datepicker: "npm:5.1.1"
|
||||
babel-loader: "npm:10.0.0"
|
||||
babel-plugin-template-html-minifier: "npm:4.1.0"
|
||||
barcode-detector: "npm:3.1.0"
|
||||
barcode-detector: "npm:3.0.8"
|
||||
browserslist-useragent-regexp: "npm:4.1.3"
|
||||
color-name: "npm:2.1.0"
|
||||
comlink: "npm:4.4.2"
|
||||
@@ -9343,7 +9335,7 @@ __metadata:
|
||||
tinykeys: "npm:3.0.0"
|
||||
ts-lit-plugin: "npm:2.0.2"
|
||||
typescript: "npm:5.9.3"
|
||||
typescript-eslint: "npm:8.56.1"
|
||||
typescript-eslint: "npm:8.56.0"
|
||||
ua-parser-js: "npm:2.0.9"
|
||||
vite-tsconfig-paths: "npm:6.1.1"
|
||||
vitest: "npm:4.0.18"
|
||||
@@ -11125,6 +11117,15 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"minimatch@npm:^9.0.5":
|
||||
version: 9.0.5
|
||||
resolution: "minimatch@npm:9.0.5"
|
||||
dependencies:
|
||||
brace-expansion: "npm:^2.0.1"
|
||||
checksum: 10/dd6a8927b063aca6d910b119e1f2df6d2ce7d36eab91de83167dd136bb85e1ebff97b0d3de1cb08bd1f7e018ca170b4962479fefab5b2a69e2ae12cb2edc8348
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"minimist@npm:^1.2.0, minimist@npm:^1.2.6":
|
||||
version: 1.2.8
|
||||
resolution: "minimist@npm:1.2.8"
|
||||
@@ -14139,12 +14140,12 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"type-fest@npm:^5.4.4":
|
||||
version: 5.4.4
|
||||
resolution: "type-fest@npm:5.4.4"
|
||||
"type-fest@npm:^5.2.0":
|
||||
version: 5.4.1
|
||||
resolution: "type-fest@npm:5.4.1"
|
||||
dependencies:
|
||||
tagged-tag: "npm:^1.0.0"
|
||||
checksum: 10/0bbdca645f95740587f389a2d712fe8d5e9ab7d13e74aac97cf396112510abcaab6b75fd90d65172bc13b02fdfc827e6a871322cc9c1c1a5a2754d9ab264c6f5
|
||||
checksum: 10/be7d4749e1e5cf2e2c9904fa1aaf9da5eef6c47c130881bf93bfd5a670b2ab59c5502466768e42c521281056a2375b1617176a75cf6c52b575f4bbabbd450b21
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@@ -14211,18 +14212,18 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"typescript-eslint@npm:8.56.1":
|
||||
version: 8.56.1
|
||||
resolution: "typescript-eslint@npm:8.56.1"
|
||||
"typescript-eslint@npm:8.56.0":
|
||||
version: 8.56.0
|
||||
resolution: "typescript-eslint@npm:8.56.0"
|
||||
dependencies:
|
||||
"@typescript-eslint/eslint-plugin": "npm:8.56.1"
|
||||
"@typescript-eslint/parser": "npm:8.56.1"
|
||||
"@typescript-eslint/typescript-estree": "npm:8.56.1"
|
||||
"@typescript-eslint/utils": "npm:8.56.1"
|
||||
"@typescript-eslint/eslint-plugin": "npm:8.56.0"
|
||||
"@typescript-eslint/parser": "npm:8.56.0"
|
||||
"@typescript-eslint/typescript-estree": "npm:8.56.0"
|
||||
"@typescript-eslint/utils": "npm:8.56.0"
|
||||
peerDependencies:
|
||||
eslint: ^8.57.0 || ^9.0.0 || ^10.0.0
|
||||
typescript: ">=4.8.4 <6.0.0"
|
||||
checksum: 10/e18cd347ddce0f0e5b28121346f27736a418adf68e73d613690ea3a1d0adfe03bc393f77a8872c2cef77ca74bcc0974212d1775c360de33a9987a94cda11a05b
|
||||
checksum: 10/7c07af35e6b4eaaebad4b50c37bc6dd50f0cecebe5a4e648ef117fd43a8496f3132020061e19a2fbaf826978e91c100054e638701bf89db8f342dd1353bb5b7e
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@@ -15703,14 +15704,14 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"zxing-wasm@npm:3.0.0":
|
||||
version: 3.0.0
|
||||
resolution: "zxing-wasm@npm:3.0.0"
|
||||
"zxing-wasm@npm:2.2.4":
|
||||
version: 2.2.4
|
||||
resolution: "zxing-wasm@npm:2.2.4"
|
||||
dependencies:
|
||||
"@types/emscripten": "npm:^1.41.5"
|
||||
type-fest: "npm:^5.4.4"
|
||||
type-fest: "npm:^5.2.0"
|
||||
peerDependencies:
|
||||
"@types/emscripten": ">=1.39.6"
|
||||
checksum: 10/0acf04829acf8f3987173af011784642792fc877c7765f79222fe33efff8af09fbf95bf5d590d2490ae39ec411e6c4de06ea24e96d4eb48189b9d06f7502eaa2
|
||||
checksum: 10/e5928cbb066c854c970cbf724e978e502c3469d69de2469bd37d1f6ab8f5d2a2acdbaa9dea32d35cfc058e2b482e29a9c4f12161d9df3e1e952c30dda3a96d8c
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
Reference in New Issue
Block a user