mirror of
https://github.com/home-assistant/frontend.git
synced 2026-05-01 15:03:05 +00:00
Compare commits
12 Commits
add-contro
...
dev
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c78cfb4012 | ||
|
|
09e993ffd6 | ||
|
|
f8f175426d | ||
|
|
89e3687f22 | ||
|
|
18a20576a9 | ||
|
|
8ee41e5d9b | ||
|
|
cac31ac55a | ||
|
|
8f002f2783 | ||
|
|
df754fcd0d | ||
|
|
bc4437b3b5 | ||
|
|
c99b43dcf3 | ||
|
|
8945b917b3 |
@@ -54,7 +54,7 @@
|
||||
"@fullcalendar/list": "6.1.20",
|
||||
"@fullcalendar/luxon3": "6.1.20",
|
||||
"@fullcalendar/timegrid": "6.1.20",
|
||||
"@home-assistant/webawesome": "3.3.1-ha.1",
|
||||
"@home-assistant/webawesome": "3.3.1-ha.2",
|
||||
"@lezer/highlight": "1.2.3",
|
||||
"@lit-labs/motion": "1.1.0",
|
||||
"@lit-labs/observers": "2.1.0",
|
||||
@@ -201,7 +201,7 @@
|
||||
"terser-webpack-plugin": "5.5.0",
|
||||
"ts-lit-plugin": "2.0.2",
|
||||
"typescript": "6.0.3",
|
||||
"typescript-eslint": "8.59.0",
|
||||
"typescript-eslint": "8.59.1",
|
||||
"vite-tsconfig-paths": "6.1.1",
|
||||
"vitest": "4.1.5",
|
||||
"webpack-stats-plugin": "1.1.3",
|
||||
|
||||
@@ -1499,6 +1499,7 @@ export class HaChartBase extends LitElement {
|
||||
margin-inline-start: var(--ha-space-1);
|
||||
flex-shrink: 0;
|
||||
white-space: nowrap;
|
||||
line-height: 1;
|
||||
}
|
||||
.chart-legend .legend-toggle {
|
||||
background: none;
|
||||
|
||||
@@ -166,7 +166,6 @@ export class HaEntityToggle extends LitElement {
|
||||
ha-control-switch {
|
||||
--control-switch-thickness: 20px;
|
||||
--control-switch-off-color: var(--state-inactive-color);
|
||||
--control-switch-touch-area-size: var(--ha-space-2);
|
||||
}
|
||||
ha-icon-button {
|
||||
--ha-icon-button-size: 40px;
|
||||
|
||||
42
src/components/ha-code-editor-jinja-arg-hover.ts
Normal file
42
src/components/ha-code-editor-jinja-arg-hover.ts
Normal file
@@ -0,0 +1,42 @@
|
||||
import { css, html, LitElement, nothing } from "lit";
|
||||
import { customElement, property } from "lit/decorators";
|
||||
import type { CompletionItem } from "./ha-code-editor-completion-items";
|
||||
import "./ha-code-editor-completion-items";
|
||||
|
||||
@customElement("ha-code-editor-jinja-arg-hover")
|
||||
export class HaCodeEditorJinjaArgHover extends LitElement {
|
||||
/** Bold heading shown above the items grid (e.g. entity/device/area name). */
|
||||
@property({ attribute: false }) public heading?: string;
|
||||
|
||||
@property({ attribute: false }) public items: CompletionItem[] = [];
|
||||
|
||||
render() {
|
||||
return html`
|
||||
${this.heading
|
||||
? html`<div class="heading">${this.heading}</div>`
|
||||
: nothing}
|
||||
<ha-code-editor-completion-items
|
||||
.items=${this.items}
|
||||
></ha-code-editor-completion-items>
|
||||
`;
|
||||
}
|
||||
|
||||
static styles = css`
|
||||
:host {
|
||||
display: block;
|
||||
padding: 6px 10px;
|
||||
max-width: 360px;
|
||||
}
|
||||
|
||||
.heading {
|
||||
font-weight: var(--ha-font-weight-bold);
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
`;
|
||||
}
|
||||
|
||||
declare global {
|
||||
interface HTMLElementTagNameMap {
|
||||
"ha-code-editor-jinja-arg-hover": HaCodeEditorJinjaArgHover;
|
||||
}
|
||||
}
|
||||
101
src/components/ha-code-editor-jinja-hover.ts
Normal file
101
src/components/ha-code-editor-jinja-hover.ts
Normal file
@@ -0,0 +1,101 @@
|
||||
import type { Completion } from "@codemirror/autocomplete";
|
||||
import { css, html, LitElement, nothing } from "lit";
|
||||
import { customElement, property } from "lit/decorators";
|
||||
import { mdiHelpCircleOutline } from "@mdi/js";
|
||||
import "./ha-svg-icon";
|
||||
|
||||
@customElement("ha-code-editor-jinja-hover")
|
||||
export class HaCodeEditorJinjaHover extends LitElement {
|
||||
@property({ attribute: false }) public completion!: Completion;
|
||||
|
||||
@property({ attribute: false }) public docUrl?: string;
|
||||
|
||||
@property({ attribute: false }) public openDocumentation =
|
||||
"Open documentation";
|
||||
|
||||
render() {
|
||||
const info =
|
||||
typeof this.completion.info === "string"
|
||||
? this.completion.info
|
||||
: undefined;
|
||||
|
||||
return html`
|
||||
<div class="header">
|
||||
<div class="sig">
|
||||
<strong>${this.completion.label}</strong>
|
||||
${this.completion.detail
|
||||
? html`<span class="detail">(${this.completion.detail})</span>`
|
||||
: nothing}
|
||||
</div>
|
||||
${this.docUrl
|
||||
? html`<a
|
||||
class="doc-link"
|
||||
href=${this.docUrl}
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
title=${this.openDocumentation}
|
||||
><ha-svg-icon .path=${mdiHelpCircleOutline}></ha-svg-icon
|
||||
></a>`
|
||||
: nothing}
|
||||
</div>
|
||||
${info ? html`<div class="desc">${info}</div>` : nothing}
|
||||
`;
|
||||
}
|
||||
|
||||
static styles = css`
|
||||
:host {
|
||||
display: block;
|
||||
padding: 6px 10px;
|
||||
max-width: 360px;
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
.header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
|
||||
.sig {
|
||||
font-family: var(--ha-font-family-code);
|
||||
font-size: 0.9em;
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.detail {
|
||||
color: var(--secondary-text-color);
|
||||
}
|
||||
|
||||
.doc-link {
|
||||
flex-shrink: 0;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
color: var(--secondary-text-color);
|
||||
opacity: 0.7;
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.doc-link:hover {
|
||||
opacity: 1;
|
||||
color: var(--primary-color);
|
||||
}
|
||||
|
||||
.doc-link ha-svg-icon {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
}
|
||||
|
||||
.desc {
|
||||
font-size: 0.9em;
|
||||
color: var(--secondary-text-color);
|
||||
}
|
||||
`;
|
||||
}
|
||||
|
||||
declare global {
|
||||
interface HTMLElementTagNameMap {
|
||||
"ha-code-editor-jinja-hover": HaCodeEditorJinjaHover;
|
||||
}
|
||||
}
|
||||
@@ -36,9 +36,13 @@ import { computeAreaName } from "../common/entity/compute_area_name";
|
||||
import { computeFloorName } from "../common/entity/compute_floor_name";
|
||||
import { copyToClipboard } from "../common/util/copy-clipboard";
|
||||
import { haStyleScrollbar } from "../resources/styles";
|
||||
import type { JinjaArgType } from "../resources/jinja_ha_completions";
|
||||
import type {
|
||||
JinjaArgType,
|
||||
HassArgHoverContext,
|
||||
} from "../resources/jinja_ha_completions";
|
||||
import type { HomeAssistant } from "../types";
|
||||
import { showToast } from "../util/toast";
|
||||
import { documentationUrl } from "../util/documentation-url";
|
||||
import { labelsContext } from "../data/context";
|
||||
import type { LabelRegistryEntry } from "../data/label/label_registry";
|
||||
import "./ha-code-editor-completion-items";
|
||||
@@ -387,6 +391,16 @@ export class HaCodeEditor extends ReactiveElement {
|
||||
this._loadedCodeMirror.tooltips({
|
||||
position: "absolute",
|
||||
}),
|
||||
this._loadedCodeMirror.hoverTooltip(
|
||||
(view, pos) =>
|
||||
this._loadedCodeMirror!.haJinjaHoverSource(
|
||||
view,
|
||||
pos,
|
||||
this.hass ? documentationUrl(this.hass, "") : undefined,
|
||||
this.hass ? this._hassArgHoverContext() : undefined
|
||||
),
|
||||
{ hoverTime: 300 }
|
||||
),
|
||||
...(this.placeholder ? [placeholder(this.placeholder)] : []),
|
||||
];
|
||||
|
||||
@@ -636,6 +650,48 @@ export class HaCodeEditor extends ReactiveElement {
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Builds a HassArgHoverContext from the current hass object so that
|
||||
* haJinjaHoverSource can resolve entity / device / area friendly names
|
||||
* without importing the full HomeAssistant type into the resource file.
|
||||
*/
|
||||
private _hassArgHoverContext(): HassArgHoverContext {
|
||||
const hass = this.hass!;
|
||||
const labelMap: Record<
|
||||
string,
|
||||
{ name: string; description?: string | null }
|
||||
> = {};
|
||||
for (const label of this._labels ?? []) {
|
||||
labelMap[label.label_id] = {
|
||||
name: label.name,
|
||||
description: label.description,
|
||||
};
|
||||
}
|
||||
return {
|
||||
states: hass.states as HassArgHoverContext["states"],
|
||||
devices: hass.devices as HassArgHoverContext["devices"],
|
||||
areas: hass.areas as HassArgHoverContext["areas"],
|
||||
floors: hass.floors as HassArgHoverContext["floors"],
|
||||
entities: hass.entities as HassArgHoverContext["entities"],
|
||||
labels: labelMap,
|
||||
formatEntityState: (entityId) =>
|
||||
hass.formatEntityState(hass.states[entityId]),
|
||||
formatEntityName: (entityId) => {
|
||||
const stateObj = hass.states[entityId];
|
||||
return (
|
||||
(stateObj?.attributes.friendly_name as string | undefined) ??
|
||||
hass.entities[entityId]?.name ??
|
||||
undefined
|
||||
);
|
||||
},
|
||||
formatAttributeName: (entityId, attribute) =>
|
||||
hass.formatEntityAttributeName(hass.states[entityId], attribute),
|
||||
formatAttributeValue: (entityId, attribute) =>
|
||||
hass.formatEntityAttributeValue(hass.states[entityId], attribute),
|
||||
localize: (key) => hass.localize(key as never),
|
||||
};
|
||||
}
|
||||
|
||||
private _renderInfo = (completion: Completion): CompletionInfo => {
|
||||
const key =
|
||||
typeof completion.apply === "string"
|
||||
|
||||
@@ -8,7 +8,7 @@ import {
|
||||
} from "@egjs/hammerjs";
|
||||
import type { PropertyValues, TemplateResult } from "lit";
|
||||
import { css, html, LitElement } from "lit";
|
||||
import { customElement, property } from "lit/decorators";
|
||||
import { customElement, property, query } from "lit/decorators";
|
||||
import { ifDefined } from "lit/directives/if-defined";
|
||||
import { fireEvent } from "../common/dom/fire_event";
|
||||
import { mainWindow } from "../common/dom/get_main_window";
|
||||
@@ -71,13 +71,16 @@ export class HaControlSwitch extends LitElement {
|
||||
this.destroyListeners();
|
||||
}
|
||||
|
||||
@query("#switch")
|
||||
private switch!: HTMLDivElement;
|
||||
|
||||
setupSwipeListeners() {
|
||||
if (this.disabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!this._mc) {
|
||||
this._mc = new Manager(this, {
|
||||
if (this.switch && !this._mc) {
|
||||
this._mc = new Manager(this.switch, {
|
||||
touchAction: this.touchAction ?? (this.vertical ? "pan-x" : "pan-y"),
|
||||
});
|
||||
this._mc.add(
|
||||
@@ -188,7 +191,6 @@ export class HaControlSwitch extends LitElement {
|
||||
static styles = css`
|
||||
:host {
|
||||
display: block;
|
||||
position: relative;
|
||||
--control-switch-on-color: var(--primary-color);
|
||||
--control-switch-off-color: var(--disabled-color);
|
||||
--control-switch-background-opacity: 0.2;
|
||||
@@ -196,7 +198,6 @@ export class HaControlSwitch extends LitElement {
|
||||
--control-switch-thickness: 40px;
|
||||
--control-switch-border-radius: var(--ha-border-radius-lg);
|
||||
--control-switch-padding: 4px;
|
||||
--control-switch-touch-area-size: 0px;
|
||||
--mdc-icon-size: 20px;
|
||||
height: var(--control-switch-thickness);
|
||||
width: 100%;
|
||||
@@ -205,11 +206,6 @@ export class HaControlSwitch extends LitElement {
|
||||
transition: box-shadow 180ms ease-in-out;
|
||||
-webkit-tap-highlight-color: transparent;
|
||||
}
|
||||
:host::before {
|
||||
content: "";
|
||||
position: absolute;
|
||||
inset: calc(-1 * var(--control-switch-touch-area-size));
|
||||
}
|
||||
.switch:not([disabled]):focus-visible {
|
||||
box-shadow: 0 0 0 2px var(--control-switch-off-color);
|
||||
}
|
||||
|
||||
@@ -53,7 +53,10 @@ export class HaIconButton extends LitElement {
|
||||
.download=${this.download}
|
||||
>
|
||||
${this.path
|
||||
? html`<ha-svg-icon .path=${this.path}></ha-svg-icon>`
|
||||
? html`<ha-svg-icon
|
||||
aria-hidden="true"
|
||||
.path=${this.path}
|
||||
></ha-svg-icon>`
|
||||
: html`<span><slot></slot></span>`}
|
||||
</ha-button>
|
||||
`;
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
import { consume, type ContextType } from "@lit/context";
|
||||
import { mdiMagnify } from "@mdi/js";
|
||||
import { css, html, type PropertyValues } from "lit";
|
||||
import { customElement, state } from "lit/decorators";
|
||||
import { internationalizationContext } from "../../data/context";
|
||||
import { customElement } from "lit/decorators";
|
||||
import { HaInput } from "./ha-input";
|
||||
|
||||
/**
|
||||
@@ -17,10 +15,6 @@ import { HaInput } from "./ha-input";
|
||||
*/
|
||||
@customElement("ha-input-search")
|
||||
export class HaInputSearch extends HaInput {
|
||||
@state()
|
||||
@consume({ context: internationalizationContext, subscribe: true })
|
||||
private _i18n!: ContextType<typeof internationalizationContext>;
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
this.withClear = true;
|
||||
@@ -35,7 +29,7 @@ export class HaInputSearch extends HaInput {
|
||||
!this.placeholder &&
|
||||
(!this.hasUpdated || changedProps.has("_i18n"))
|
||||
) {
|
||||
this.placeholder = this._i18n.localize("ui.common.search");
|
||||
this.placeholder = this.i18n?.localize?.("ui.common.search") || "Search";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -2,19 +2,21 @@ import "@home-assistant/webawesome/dist/components/animation/animation";
|
||||
import "@home-assistant/webawesome/dist/components/input/input";
|
||||
import type WaInput from "@home-assistant/webawesome/dist/components/input/input";
|
||||
import { HasSlotController } from "@home-assistant/webawesome/dist/internal/slot";
|
||||
import { consume, type ContextType } from "@lit/context";
|
||||
import { mdiClose, mdiEye, mdiEyeOff } from "@mdi/js";
|
||||
import {
|
||||
LitElement,
|
||||
type PropertyValues,
|
||||
type TemplateResult,
|
||||
css,
|
||||
html,
|
||||
LitElement,
|
||||
nothing,
|
||||
type PropertyValues,
|
||||
type TemplateResult,
|
||||
} from "lit";
|
||||
import { customElement, property, query } from "lit/decorators";
|
||||
import { customElement, property, query, state } from "lit/decorators";
|
||||
import { classMap } from "lit/directives/class-map";
|
||||
import { ifDefined } from "lit/directives/if-defined";
|
||||
import { stopPropagation } from "../../common/dom/stop_propagation";
|
||||
import { internationalizationContext } from "../../data/context";
|
||||
import "../ha-icon-button";
|
||||
import "../ha-svg-icon";
|
||||
import "../ha-tooltip";
|
||||
@@ -125,6 +127,10 @@ export class HaInput extends WaInputMixin(LitElement) {
|
||||
@query("wa-input")
|
||||
private _input?: WaInput;
|
||||
|
||||
@state()
|
||||
@consume({ context: internationalizationContext, subscribe: true })
|
||||
protected i18n?: ContextType<typeof internationalizationContext>;
|
||||
|
||||
private readonly _hasSlotController = new HasSlotController(
|
||||
this,
|
||||
"label",
|
||||
@@ -233,19 +239,22 @@ export class HaInput extends WaInputMixin(LitElement) {
|
||||
${this.renderStartDefault()}
|
||||
</slot>
|
||||
<slot name="end" slot="end"> ${this.renderEndDefault()} </slot>
|
||||
<slot name="clear-icon" slot="clear-icon">
|
||||
<ha-icon-button .path=${mdiClose}></ha-icon-button>
|
||||
</slot>
|
||||
<slot name="show-password-icon" slot="show-password-icon">
|
||||
<slot name="clear-button" slot="clear-button">
|
||||
<ha-icon-button
|
||||
@keydown=${stopPropagation}
|
||||
.path=${mdiEye}
|
||||
@click=${this._handleClearClick}
|
||||
.label=${this.i18n?.localize?.("ui.components.input.clear") ||
|
||||
"Clear"}
|
||||
.path=${mdiClose}
|
||||
></ha-icon-button>
|
||||
</slot>
|
||||
<slot name="hide-password-icon" slot="hide-password-icon">
|
||||
<slot name="password-toggle-button" slot="password-toggle-button">
|
||||
<ha-icon-button
|
||||
@keydown=${stopPropagation}
|
||||
.path=${mdiEyeOff}
|
||||
@click=${this._handlePasswordToggle}
|
||||
.label=${this.i18n?.localize?.(
|
||||
`ui.components.input.${this.passwordVisible ? "hide_password" : "show_password"}`
|
||||
) || (this.passwordVisible ? "Hide password" : "Show password")}
|
||||
.path=${this.passwordVisible ? mdiEyeOff : mdiEye}
|
||||
></ha-icon-button>
|
||||
</slot>
|
||||
<div
|
||||
@@ -293,6 +302,14 @@ export class HaInput extends WaInputMixin(LitElement) {
|
||||
}
|
||||
};
|
||||
|
||||
private _handleClearClick() {
|
||||
this._input?.clear();
|
||||
}
|
||||
|
||||
private _handlePasswordToggle() {
|
||||
this.passwordVisible = !this.passwordVisible;
|
||||
}
|
||||
|
||||
static styles = [
|
||||
waInputStyles,
|
||||
css`
|
||||
@@ -414,6 +431,12 @@ export class HaInput extends WaInputMixin(LitElement) {
|
||||
color: var(--ha-color-text-secondary);
|
||||
}
|
||||
|
||||
ha-icon-button {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
color: var(--ha-color-text-secondary);
|
||||
}
|
||||
|
||||
:host([appearance="outlined"]) wa-input.no-label {
|
||||
--ha-icon-button-size: 24px;
|
||||
--mdc-icon-size: 18px;
|
||||
|
||||
@@ -189,6 +189,20 @@ export const updateBackupConfig = (
|
||||
config: BackupMutableConfig
|
||||
) => hass.callWS({ type: "backup/config/update", ...config });
|
||||
|
||||
export const saveBackupConfig = (hass: HomeAssistant, config: BackupConfig) =>
|
||||
updateBackupConfig(hass, {
|
||||
create_backup: {
|
||||
agent_ids: config.create_backup.agent_ids,
|
||||
include_folders: config.create_backup.include_folders ?? [],
|
||||
include_database: config.create_backup.include_database,
|
||||
include_addons: config.create_backup.include_addons ?? [],
|
||||
include_all_addons: config.create_backup.include_all_addons,
|
||||
password: config.create_backup.password,
|
||||
},
|
||||
retention: config.retention,
|
||||
schedule: config.schedule,
|
||||
});
|
||||
|
||||
export const getBackupDownloadUrl = (
|
||||
id: string,
|
||||
agentId: string,
|
||||
|
||||
@@ -134,6 +134,7 @@ type AutomationItem = AutomationEntity & {
|
||||
formatted_state: string;
|
||||
category: string | undefined;
|
||||
label_entries: LabelRegistryEntry[];
|
||||
labels: string[]; // search only
|
||||
assistants: string[];
|
||||
assistants_sortable_key: string | undefined;
|
||||
};
|
||||
@@ -256,6 +257,9 @@ class HaAutomationPicker extends SubscribeMixin(LitElement) {
|
||||
);
|
||||
const category = entityRegEntry?.categories.automation;
|
||||
const labels = labelReg && entityRegEntry?.labels;
|
||||
const label_entries = (labels || [])
|
||||
.map((lbl) => labelReg!.find((label) => label.label_id === lbl)!)
|
||||
.filter(Boolean);
|
||||
const assistants = getEntityVoiceAssistantsIds(
|
||||
entityReg,
|
||||
automation.entity_id
|
||||
@@ -271,9 +275,8 @@ class HaAutomationPicker extends SubscribeMixin(LitElement) {
|
||||
category: category
|
||||
? categoryReg?.find((cat) => cat.category_id === category)?.name
|
||||
: undefined,
|
||||
label_entries: (labels || [])
|
||||
.map((lbl) => labelReg!.find((label) => label.label_id === lbl)!)
|
||||
.filter(Boolean),
|
||||
label_entries,
|
||||
labels: label_entries.map((lbl) => lbl.name),
|
||||
assistants,
|
||||
assistants_sortable_key: getAssistantsSortableKey(assistants),
|
||||
selectable: entityRegEntry !== undefined,
|
||||
|
||||
@@ -0,0 +1,123 @@
|
||||
import { mdiPuzzle } from "@mdi/js";
|
||||
import type { CSSResultGroup } from "lit";
|
||||
import { css, html, LitElement } from "lit";
|
||||
import { customElement, property, state } from "lit/decorators";
|
||||
import "../../../../../components/ha-card";
|
||||
import "../../../../../components/ha-icon-next";
|
||||
import "../../../../../components/ha-md-list";
|
||||
import "../../../../../components/ha-md-list-item";
|
||||
import "../../../../../components/ha-svg-icon";
|
||||
import {
|
||||
getSupervisorUpdateConfig,
|
||||
type SupervisorUpdateConfig,
|
||||
} from "../../../../../data/supervisor/update";
|
||||
import { haStyle } from "../../../../../resources/styles";
|
||||
import type { HomeAssistant } from "../../../../../types";
|
||||
|
||||
@customElement("ha-backup-overview-app-update-backup")
|
||||
class HaBackupOverviewAppUpdateBackup extends LitElement {
|
||||
@property({ attribute: false }) public hass!: HomeAssistant;
|
||||
|
||||
@state() private _supervisorUpdateConfig?: SupervisorUpdateConfig;
|
||||
|
||||
protected firstUpdated() {
|
||||
this._fetchSupervisorUpdateConfig();
|
||||
}
|
||||
|
||||
public connectedCallback() {
|
||||
super.connectedCallback();
|
||||
if (this.hasUpdated) {
|
||||
this._fetchSupervisorUpdateConfig();
|
||||
}
|
||||
}
|
||||
|
||||
private async _fetchSupervisorUpdateConfig() {
|
||||
try {
|
||||
this._supervisorUpdateConfig = await getSupervisorUpdateConfig(this.hass);
|
||||
} catch (err) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.error(err);
|
||||
}
|
||||
}
|
||||
|
||||
private _appUpdateBackupDescription() {
|
||||
if (!this._supervisorUpdateConfig) {
|
||||
return this.hass.localize(
|
||||
"ui.panel.config.backup.settings.app_update_backup.local_only"
|
||||
);
|
||||
}
|
||||
|
||||
if (!this._supervisorUpdateConfig.add_on_backup_before_update) {
|
||||
return this.hass.localize(
|
||||
"ui.panel.config.backup.schedule.update_preference.skip_backups"
|
||||
);
|
||||
}
|
||||
|
||||
const copies =
|
||||
this._supervisorUpdateConfig.add_on_backup_retain_copies || 1;
|
||||
|
||||
return `${this.hass.localize(
|
||||
"ui.panel.config.backup.schedule.update_preference.backup_before_update"
|
||||
)} ${this.hass.localize(
|
||||
"ui.panel.config.backup.overview.settings.schedule_copies_backups",
|
||||
{ count: copies }
|
||||
)}`;
|
||||
}
|
||||
|
||||
protected render() {
|
||||
return html`
|
||||
<ha-card>
|
||||
<div class="card-header">
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.backup.overview.app_update_backup.title"
|
||||
)}
|
||||
</div>
|
||||
<div class="card-content">
|
||||
<ha-md-list>
|
||||
<ha-md-list-item
|
||||
type="link"
|
||||
href="/config/backup/app-update-backups"
|
||||
>
|
||||
<ha-svg-icon slot="start" .path=${mdiPuzzle}></ha-svg-icon>
|
||||
<div slot="headline">${this._appUpdateBackupDescription()}</div>
|
||||
<div slot="supporting-text">
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.backup.overview.app_update_backup.description"
|
||||
)}
|
||||
</div>
|
||||
<ha-icon-next slot="end"></ha-icon-next>
|
||||
</ha-md-list-item>
|
||||
</ha-md-list>
|
||||
</div>
|
||||
</ha-card>
|
||||
`;
|
||||
}
|
||||
|
||||
static get styles(): CSSResultGroup {
|
||||
return [
|
||||
haStyle,
|
||||
css`
|
||||
.card-header {
|
||||
padding-bottom: 8px;
|
||||
}
|
||||
|
||||
.card-content {
|
||||
padding-left: 0;
|
||||
padding-right: 0;
|
||||
padding-top: 0;
|
||||
}
|
||||
|
||||
ha-md-list {
|
||||
padding-top: 0;
|
||||
padding-bottom: 0;
|
||||
}
|
||||
`,
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
declare global {
|
||||
interface HTMLElementTagNameMap {
|
||||
"ha-backup-overview-app-update-backup": HaBackupOverviewAppUpdateBackup;
|
||||
}
|
||||
}
|
||||
154
src/panels/config/backup/ha-config-backup-app-update-backups.ts
Normal file
154
src/panels/config/backup/ha-config-backup-app-update-backups.ts
Normal file
@@ -0,0 +1,154 @@
|
||||
import { css, html, LitElement, nothing } from "lit";
|
||||
import type { PropertyValues } from "lit";
|
||||
import { customElement, property, state } from "lit/decorators";
|
||||
import { isComponentLoaded } from "../../../common/config/is_component_loaded";
|
||||
import { debounce } from "../../../common/util/debounce";
|
||||
import "../../../components/ha-alert";
|
||||
import "../../../components/ha-card";
|
||||
import {
|
||||
getSupervisorUpdateConfig,
|
||||
updateSupervisorUpdateConfig,
|
||||
type SupervisorUpdateConfig,
|
||||
} from "../../../data/supervisor/update";
|
||||
import "../../../layouts/hass-subpage";
|
||||
import type { HomeAssistant } from "../../../types";
|
||||
import "./components/config/ha-backup-config-addon";
|
||||
|
||||
@customElement("ha-config-backup-app-update-backups")
|
||||
class HaConfigBackupAppUpdateBackups extends LitElement {
|
||||
@property({ attribute: false }) public hass!: HomeAssistant;
|
||||
|
||||
@property({ type: Boolean }) public narrow = false;
|
||||
|
||||
@state() private _supervisorUpdateConfig?: SupervisorUpdateConfig;
|
||||
|
||||
@state() private _error?: string;
|
||||
|
||||
protected willUpdate(changedProps: PropertyValues<this>): void {
|
||||
super.willUpdate(changedProps);
|
||||
|
||||
if (
|
||||
!this.hasUpdated &&
|
||||
this.hass &&
|
||||
isComponentLoaded(this.hass.config, "hassio")
|
||||
) {
|
||||
this._getSupervisorUpdateConfig();
|
||||
}
|
||||
}
|
||||
|
||||
protected render() {
|
||||
return html`
|
||||
<hass-subpage
|
||||
back-path="/config/backup/overview"
|
||||
.hass=${this.hass}
|
||||
.narrow=${this.narrow}
|
||||
.header=${this.hass.localize(
|
||||
"ui.panel.config.backup.app_update_backups.header"
|
||||
)}
|
||||
>
|
||||
<div class="content">
|
||||
<ha-card>
|
||||
<div class="card-content">
|
||||
<p>
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.backup.settings.app_update_backup.description"
|
||||
)}
|
||||
</p>
|
||||
<p>
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.backup.settings.app_update_backup.local_only"
|
||||
)}
|
||||
</p>
|
||||
${this._error
|
||||
? html`<ha-alert alert-type="error">${this._error}</ha-alert>`
|
||||
: nothing}
|
||||
<ha-backup-config-addon
|
||||
.hass=${this.hass}
|
||||
.supervisorUpdateConfig=${this._supervisorUpdateConfig}
|
||||
@update-config-changed=${this._supervisorUpdateConfigChanged}
|
||||
></ha-backup-config-addon>
|
||||
</div>
|
||||
</ha-card>
|
||||
</div>
|
||||
</hass-subpage>
|
||||
`;
|
||||
}
|
||||
|
||||
private async _getSupervisorUpdateConfig() {
|
||||
try {
|
||||
this._supervisorUpdateConfig = await getSupervisorUpdateConfig(this.hass);
|
||||
this._error = undefined;
|
||||
} catch (err: any) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.error(err);
|
||||
this._error = this.hass.localize(
|
||||
"ui.panel.config.backup.settings.app_update_backup.error_load",
|
||||
{
|
||||
error: err?.message || err,
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
private async _supervisorUpdateConfigChanged(ev) {
|
||||
const config = ev.detail.value as SupervisorUpdateConfig;
|
||||
this._supervisorUpdateConfig = {
|
||||
...this._supervisorUpdateConfig,
|
||||
...config,
|
||||
} as SupervisorUpdateConfig;
|
||||
this._debounceSaveSupervisorUpdateConfig();
|
||||
}
|
||||
|
||||
private _debounceSaveSupervisorUpdateConfig = debounce(
|
||||
() => this._saveSupervisorUpdateConfig(),
|
||||
500
|
||||
);
|
||||
|
||||
private async _saveSupervisorUpdateConfig() {
|
||||
if (!this._supervisorUpdateConfig) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
await updateSupervisorUpdateConfig(
|
||||
this.hass,
|
||||
this._supervisorUpdateConfig
|
||||
);
|
||||
this._error = undefined;
|
||||
} catch (err: any) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.error(err);
|
||||
this._error = this.hass.localize(
|
||||
"ui.panel.config.backup.settings.app_update_backup.error_save",
|
||||
{
|
||||
error: err?.message || err?.toString(),
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
static styles = css`
|
||||
p {
|
||||
color: var(--secondary-text-color);
|
||||
}
|
||||
|
||||
.content {
|
||||
padding: 28px 20px 0;
|
||||
max-width: 690px;
|
||||
margin: 0 auto;
|
||||
gap: var(--ha-space-6);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
margin-bottom: 24px;
|
||||
}
|
||||
|
||||
.card-content {
|
||||
padding-bottom: 0;
|
||||
}
|
||||
`;
|
||||
}
|
||||
|
||||
declare global {
|
||||
interface HTMLElementTagNameMap {
|
||||
"ha-config-backup-app-update-backups": HaConfigBackupAppUpdateBackups;
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,9 @@
|
||||
import { mdiDotsVertical, mdiPlus, mdiUpload } from "@mdi/js";
|
||||
import type { CSSResultGroup, TemplateResult } from "lit";
|
||||
import type { CSSResultGroup, PropertyValues, TemplateResult } from "lit";
|
||||
import { css, html, LitElement, nothing } from "lit";
|
||||
import { customElement, property } from "lit/decorators";
|
||||
import { customElement, property, state } from "lit/decorators";
|
||||
import { fireEvent } from "../../../common/dom/fire_event";
|
||||
import { debounce } from "../../../common/util/debounce";
|
||||
import "../../../components/ha-button";
|
||||
import "../../../components/ha-card";
|
||||
import "../../../components/ha-dropdown";
|
||||
@@ -23,6 +24,7 @@ import {
|
||||
computeBackupAgentName,
|
||||
generateBackup,
|
||||
generateBackupWithAutomaticSettings,
|
||||
saveBackupConfig,
|
||||
} from "../../../data/backup";
|
||||
import type { ManagerStateEvent } from "../../../data/backup_manager";
|
||||
import type { CloudStatus } from "../../../data/cloud";
|
||||
@@ -32,10 +34,12 @@ import { haStyle } from "../../../resources/styles";
|
||||
import type { HomeAssistant, Route } from "../../../types";
|
||||
import { showAlertDialog } from "../../lovelace/custom-card-helpers";
|
||||
import "./components/overview/ha-backup-overview-backups";
|
||||
import "./components/overview/ha-backup-overview-app-update-backup";
|
||||
import "./components/overview/ha-backup-overview-onboarding";
|
||||
import "./components/overview/ha-backup-overview-progress";
|
||||
import "./components/overview/ha-backup-overview-settings";
|
||||
import "./components/overview/ha-backup-overview-summary";
|
||||
import "./components/config/ha-backup-config-encryption-key";
|
||||
import { showBackupOnboardingDialog } from "./dialogs/show-dialog-backup_onboarding";
|
||||
import { showGenerateBackupDialog } from "./dialogs/show-dialog-generate-backup";
|
||||
import { showNewBackupDialog } from "./dialogs/show-dialog-new-backup";
|
||||
@@ -68,10 +72,54 @@ class HaConfigBackupOverview extends LitElement {
|
||||
{ uploaded_bytes: number; total_bytes: number }
|
||||
> = {};
|
||||
|
||||
@state() private _config?: BackupConfig;
|
||||
|
||||
protected willUpdate(changedProperties: PropertyValues<this>): void {
|
||||
super.willUpdate(changedProperties);
|
||||
if (changedProperties.has("config") && !this._config) {
|
||||
this._config = this.config;
|
||||
}
|
||||
}
|
||||
|
||||
public connectedCallback(): void {
|
||||
super.connectedCallback();
|
||||
// Update config when the page is displayed (e.g. when coming back from a settings page)
|
||||
this._config = this.config;
|
||||
}
|
||||
|
||||
private _uploadBackup = async () => {
|
||||
await showUploadBackupDialog(this, {});
|
||||
};
|
||||
|
||||
private _encryptionKeyChanged(ev) {
|
||||
if (!this._config) {
|
||||
return;
|
||||
}
|
||||
|
||||
const password = ev.detail.value as string;
|
||||
this._config = {
|
||||
...this._config,
|
||||
create_backup: {
|
||||
...this._config.create_backup,
|
||||
password,
|
||||
},
|
||||
};
|
||||
|
||||
this._debounceSaveConfig();
|
||||
}
|
||||
|
||||
private _debounceSaveConfig = debounce(() => this._saveConfig(), 500);
|
||||
|
||||
private async _saveConfig() {
|
||||
if (!this._config) {
|
||||
return;
|
||||
}
|
||||
|
||||
await saveBackupConfig(this.hass, this._config);
|
||||
|
||||
fireEvent(this, "ha-refresh-backup-config");
|
||||
}
|
||||
|
||||
private _handleOnboardingButtonClick(ev) {
|
||||
ev.stopPropagation();
|
||||
this._setupAutomaticBackup(true);
|
||||
@@ -234,13 +282,41 @@ class HaConfigBackupOverview extends LitElement {
|
||||
.backups=${this.backups}
|
||||
></ha-backup-overview-backups>
|
||||
|
||||
${!this._needsOnboarding && this.config
|
||||
${!this._needsOnboarding && this._config
|
||||
? html`
|
||||
<ha-card>
|
||||
<div class="card-header">
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.backup.settings.encryption_key.title"
|
||||
)}
|
||||
</div>
|
||||
<div class="card-content">
|
||||
<p>
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.backup.settings.encryption_key.description"
|
||||
)}
|
||||
</p>
|
||||
<ha-backup-config-encryption-key
|
||||
.hass=${this.hass}
|
||||
.value=${this._config.create_backup.password}
|
||||
@value-changed=${this._encryptionKeyChanged}
|
||||
></ha-backup-config-encryption-key>
|
||||
</div>
|
||||
</ha-card>
|
||||
|
||||
<ha-backup-overview-settings
|
||||
.hass=${this.hass}
|
||||
.config=${this.config!}
|
||||
.config=${this._config}
|
||||
.agents=${this.agents}
|
||||
></ha-backup-overview-settings>
|
||||
|
||||
${this.hass.config.components.includes("hassio")
|
||||
? html`
|
||||
<ha-backup-overview-app-update-backup
|
||||
.hass=${this.hass}
|
||||
></ha-backup-overview-app-update-backup>
|
||||
`
|
||||
: nothing}
|
||||
`
|
||||
: nothing}
|
||||
</div>
|
||||
@@ -270,6 +346,10 @@ class HaConfigBackupOverview extends LitElement {
|
||||
return [
|
||||
haStyle,
|
||||
css`
|
||||
p {
|
||||
color: var(--secondary-text-color);
|
||||
}
|
||||
|
||||
.content {
|
||||
padding: 28px 20px 0;
|
||||
max-width: 690px;
|
||||
@@ -283,10 +363,6 @@ class HaConfigBackupOverview extends LitElement {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
}
|
||||
.card-content {
|
||||
padding-left: 0;
|
||||
padding-right: 0;
|
||||
}
|
||||
.loading {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
@@ -16,7 +16,7 @@ import "../../../components/ha-icon-button";
|
||||
import "../../../components/ha-icon-next";
|
||||
import "../../../components/ha-svg-icon";
|
||||
import type { BackupAgent, BackupConfig } from "../../../data/backup";
|
||||
import { updateBackupConfig } from "../../../data/backup";
|
||||
import { saveBackupConfig } from "../../../data/backup";
|
||||
import type { CloudStatus } from "../../../data/cloud";
|
||||
import {
|
||||
getSupervisorUpdateConfig,
|
||||
@@ -27,11 +27,9 @@ import "../../../layouts/hass-subpage";
|
||||
import type { HomeAssistant } from "../../../types";
|
||||
import { brandsUrl } from "../../../util/brands-url";
|
||||
import { documentationUrl } from "../../../util/documentation-url";
|
||||
import "./components/config/ha-backup-config-addon";
|
||||
import "./components/config/ha-backup-config-agents";
|
||||
import "./components/config/ha-backup-config-data";
|
||||
import type { BackupConfigData } from "./components/config/ha-backup-config-data";
|
||||
import "./components/config/ha-backup-config-encryption-key";
|
||||
import "./components/config/ha-backup-config-schedule";
|
||||
import type { BackupConfigSchedule } from "./components/config/ha-backup-config-schedule";
|
||||
import { showLocalBackupLocationDialog } from "./dialogs/show-dialog-local-backup-location";
|
||||
@@ -79,7 +77,7 @@ class HaConfigBackupSettings extends LitElement {
|
||||
// eslint-disable-next-line no-console
|
||||
console.error(err);
|
||||
this._supervisorUpdateConfigError = this.hass.localize(
|
||||
"ui.panel.config.backup.settings.app_update_backup.error_load",
|
||||
"ui.panel.config.backup.settings.schedule.error_load",
|
||||
{
|
||||
error: err?.message || err,
|
||||
}
|
||||
@@ -315,57 +313,6 @@ class HaConfigBackupSettings extends LitElement {
|
||||
: nothing}
|
||||
</div>
|
||||
</ha-card>
|
||||
${supervisor
|
||||
? html`<ha-card>
|
||||
<div class="card-header">
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.backup.settings.app_update_backup.title"
|
||||
)}
|
||||
</div>
|
||||
<div class="card-content">
|
||||
<p>
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.backup.settings.app_update_backup.description"
|
||||
)}
|
||||
</p>
|
||||
<p>
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.backup.settings.app_update_backup.local_only"
|
||||
)}
|
||||
</p>
|
||||
${this._supervisorUpdateConfigError
|
||||
? html`<ha-alert alert-type="error">
|
||||
${this._supervisorUpdateConfigError}
|
||||
</ha-alert>`
|
||||
: nothing}
|
||||
<ha-backup-config-addon
|
||||
.hass=${this.hass}
|
||||
.supervisorUpdateConfig=${this._supervisorUpdateConfig}
|
||||
@update-config-changed=${this
|
||||
._supervisorUpdateConfigChanged}
|
||||
></ha-backup-config-addon>
|
||||
</div>
|
||||
</ha-card>`
|
||||
: nothing}
|
||||
<ha-card>
|
||||
<div class="card-header">
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.backup.settings.encryption_key.title"
|
||||
)}
|
||||
</div>
|
||||
<div class="card-content">
|
||||
<p>
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.backup.settings.encryption_key.description"
|
||||
)}
|
||||
</p>
|
||||
<ha-backup-config-encryption-key
|
||||
.hass=${this.hass}
|
||||
.value=${this._config.create_backup.password}
|
||||
@value-changed=${this._encryptionKeyChanged}
|
||||
></ha-backup-config-encryption-key>
|
||||
</div>
|
||||
</ha-card>
|
||||
</div>
|
||||
</hass-subpage>
|
||||
`;
|
||||
@@ -438,18 +385,6 @@ class HaConfigBackupSettings extends LitElement {
|
||||
this._debounceSave();
|
||||
}
|
||||
|
||||
private _encryptionKeyChanged(ev) {
|
||||
const password = ev.detail.value as string;
|
||||
this._config = {
|
||||
...this._config!,
|
||||
create_backup: {
|
||||
...this._config!.create_backup,
|
||||
password: password,
|
||||
},
|
||||
};
|
||||
this._debounceSave();
|
||||
}
|
||||
|
||||
private _debounceSaveSupervisorUpdateConfig = debounce(
|
||||
() => this._saveSupervisorUpdateConfig(),
|
||||
500
|
||||
@@ -468,7 +403,7 @@ class HaConfigBackupSettings extends LitElement {
|
||||
// eslint-disable-next-line no-console
|
||||
console.error(err);
|
||||
this._supervisorUpdateConfigError = this.hass.localize(
|
||||
"ui.panel.config.backup.settings.app_update_backup.error_save",
|
||||
"ui.panel.config.backup.settings.schedule.error_save",
|
||||
{
|
||||
error: err?.message || err?.toString(),
|
||||
}
|
||||
@@ -479,18 +414,7 @@ class HaConfigBackupSettings extends LitElement {
|
||||
private _debounceSave = debounce(() => this._save(), 500);
|
||||
|
||||
private async _save() {
|
||||
await updateBackupConfig(this.hass, {
|
||||
create_backup: {
|
||||
agent_ids: this._config!.create_backup.agent_ids,
|
||||
include_folders: this._config!.create_backup.include_folders ?? [],
|
||||
include_database: this._config!.create_backup.include_database,
|
||||
include_addons: this._config!.create_backup.include_addons ?? [],
|
||||
include_all_addons: this._config!.create_backup.include_all_addons,
|
||||
password: this._config!.create_backup.password,
|
||||
},
|
||||
retention: this._config!.retention,
|
||||
schedule: this._config!.schedule,
|
||||
});
|
||||
await saveBackupConfig(this.hass, this._config!);
|
||||
fireEvent(this, "ha-refresh-backup-config");
|
||||
}
|
||||
|
||||
|
||||
@@ -125,6 +125,11 @@ class HaConfigBackup extends SubscribeMixin(HassRouterPage) {
|
||||
load: () => import("./ha-config-backup-settings"),
|
||||
cache: true,
|
||||
},
|
||||
"app-update-backups": {
|
||||
tag: "ha-config-backup-app-update-backups",
|
||||
load: () => import("./ha-config-backup-app-update-backups"),
|
||||
cache: true,
|
||||
},
|
||||
location: {
|
||||
tag: "ha-config-backup-location",
|
||||
load: () => import("./ha-config-backup-location"),
|
||||
|
||||
@@ -244,9 +244,13 @@ class HaPanelDevAssist extends SubscribeMixin(LitElement) {
|
||||
max-width: 1040px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
.card-content {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: var(--ha-space-4);
|
||||
}
|
||||
.description {
|
||||
margin: 0;
|
||||
margin-bottom: var(--ha-space-4);
|
||||
}
|
||||
ha-textarea {
|
||||
width: 100%;
|
||||
|
||||
@@ -9,6 +9,7 @@ import "../../../../components/ha-button";
|
||||
import "../../../../components/ha-card";
|
||||
import "../../../../components/ha-code-editor";
|
||||
import "../../../../components/ha-spinner";
|
||||
import "../../../../components/ha-tip";
|
||||
import type { RenderTemplateResult } from "../../../../data/ws-templates";
|
||||
import { subscribeRenderTemplate } from "../../../../data/ws-templates";
|
||||
import { showConfirmationDialog } from "../../../../dialogs/generic/show-dialog-box";
|
||||
@@ -158,6 +159,14 @@ class HaPanelDevTemplate extends LitElement {
|
||||
${this.hass.localize("ui.common.clear")}
|
||||
</ha-button>
|
||||
</div>
|
||||
<ha-tip .hass=${this.hass}>
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.developer-tools.tabs.templates.keyboard_tip",
|
||||
{
|
||||
autocomplete: html`<kbd>Ctrl</kbd>+<kbd>Space</kbd>`,
|
||||
}
|
||||
)}
|
||||
</ha-tip>
|
||||
</ha-card>
|
||||
|
||||
<ha-card
|
||||
@@ -361,6 +370,22 @@ ${type === "object"
|
||||
color: var(--warning-color);
|
||||
}
|
||||
|
||||
ha-tip {
|
||||
padding: 0 var(--ha-space-4) var(--ha-space-4);
|
||||
display: block;
|
||||
}
|
||||
|
||||
kbd {
|
||||
display: inline-block;
|
||||
font-family: var(--ha-font-family-code);
|
||||
font-size: 0.85em;
|
||||
padding: 1px 5px;
|
||||
border: 1px solid var(--divider-color);
|
||||
border-radius: var(--ha-border-radius-xs);
|
||||
background-color: var(--secondary-background-color);
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
@media all and (max-width: 870px) {
|
||||
.content ha-card {
|
||||
max-width: 100%;
|
||||
|
||||
@@ -146,6 +146,7 @@ interface HelperItem {
|
||||
category: string | undefined;
|
||||
area?: string;
|
||||
label_entries: LabelRegistryEntry[];
|
||||
labels: string[]; // search only
|
||||
assistants: string[];
|
||||
assistants_sortable_key: string | undefined;
|
||||
disabled?: boolean;
|
||||
@@ -552,6 +553,9 @@ export class HaConfigHelpers extends SubscribeMixin(LitElement) {
|
||||
const entityRegEntry =
|
||||
entityRegistryByEntityId(entityReg)[item.entity_id];
|
||||
const labels = labelReg && entityRegEntry?.labels;
|
||||
const label_entries = (labels || []).map(
|
||||
(lbl) => labelReg!.find((label) => label.label_id === lbl)!
|
||||
);
|
||||
const category = entityRegEntry?.categories.helpers;
|
||||
const deviceId = entityRegEntry?.device_id;
|
||||
const areaId =
|
||||
@@ -572,9 +576,8 @@ export class HaConfigHelpers extends SubscribeMixin(LitElement) {
|
||||
`ui.panel.config.helpers.types.${item.type}` as LocalizeKeys
|
||||
) ||
|
||||
item.type,
|
||||
label_entries: (labels || []).map(
|
||||
(lbl) => labelReg!.find((label) => label.label_id === lbl)!
|
||||
),
|
||||
label_entries,
|
||||
labels: label_entries.map((lbl) => lbl.name),
|
||||
category: category
|
||||
? categoryReg?.find((cat) => cat.category_id === category)?.name
|
||||
: undefined,
|
||||
|
||||
@@ -122,6 +122,7 @@ type SceneItem = SceneEntity & {
|
||||
area: string | undefined;
|
||||
category: string | undefined;
|
||||
label_entries: LabelRegistryEntry[];
|
||||
labels: string[]; // search only
|
||||
assistants: string[];
|
||||
assistants_sortable_key: string | undefined;
|
||||
editable: boolean;
|
||||
@@ -239,6 +240,9 @@ class HaSceneDashboard extends SubscribeMixin(LitElement) {
|
||||
);
|
||||
const category = entityRegEntry?.categories.scene;
|
||||
const labels = labelReg && entityRegEntry?.labels;
|
||||
const label_entries = (labels || []).map(
|
||||
(lbl) => labelReg!.find((label) => label.label_id === lbl)!
|
||||
);
|
||||
const assistants = getEntityVoiceAssistantsIds(
|
||||
entityReg,
|
||||
scene.entity_id
|
||||
@@ -252,9 +256,8 @@ class HaSceneDashboard extends SubscribeMixin(LitElement) {
|
||||
category: category
|
||||
? categoryReg?.find((cat) => cat.category_id === category)?.name
|
||||
: undefined,
|
||||
label_entries: (labels || []).map(
|
||||
(lbl) => labelReg!.find((label) => label.label_id === lbl)!
|
||||
),
|
||||
label_entries,
|
||||
labels: label_entries.map((lbl) => lbl.name),
|
||||
assistants,
|
||||
assistants_sortable_key: getAssistantsSortableKey(assistants),
|
||||
selectable: entityRegEntry !== undefined,
|
||||
|
||||
@@ -127,6 +127,7 @@ type ScriptItem = ScriptEntity & {
|
||||
last_triggered: string | undefined;
|
||||
category: string | undefined;
|
||||
label_entries: LabelRegistryEntry[];
|
||||
labels: string[]; // search only
|
||||
assistants: string[];
|
||||
assistants_sortable_key: string | undefined;
|
||||
};
|
||||
@@ -245,6 +246,9 @@ class HaScriptPicker extends SubscribeMixin(LitElement) {
|
||||
);
|
||||
const category = entityRegEntry?.categories.script;
|
||||
const labels = labelReg && entityRegEntry?.labels;
|
||||
const label_entries = (labels || []).map(
|
||||
(lbl) => labelReg!.find((label) => label.label_id === lbl)!
|
||||
);
|
||||
const assistants = getEntityVoiceAssistantsIds(
|
||||
entityReg,
|
||||
script.entity_id
|
||||
@@ -259,9 +263,8 @@ class HaScriptPicker extends SubscribeMixin(LitElement) {
|
||||
category: category
|
||||
? categoryReg?.find((cat) => cat.category_id === category)?.name
|
||||
: undefined,
|
||||
label_entries: (labels || []).map(
|
||||
(lbl) => labelReg!.find((label) => label.label_id === lbl)!
|
||||
),
|
||||
label_entries,
|
||||
labels: label_entries.map((lbl) => lbl.name),
|
||||
assistants,
|
||||
assistants_sortable_key: getAssistantsSortableKey(assistants),
|
||||
selectable: entityRegEntry !== undefined,
|
||||
|
||||
@@ -35,7 +35,10 @@ import {
|
||||
HOME_SUMMARIES_ICONS,
|
||||
type HomeSummary,
|
||||
} from "../strategies/home/helpers/home-summaries";
|
||||
import { filterNeedsAttentionEntities } from "../../maintenance/strategies/maintenance-view-strategy";
|
||||
import {
|
||||
filterLowBatteryEntities,
|
||||
filterUnavailableBatteryEntities,
|
||||
} from "../../maintenance/strategies/maintenance-view-strategy";
|
||||
import type { LovelaceCard, LovelaceGridOptions } from "../types";
|
||||
import { tileCardStyle } from "./tile/tile-card-style";
|
||||
import type { HomeSummaryCard } from "./types";
|
||||
@@ -258,19 +261,48 @@ export class HuiHomeSummaryCard
|
||||
maintenanceFilters
|
||||
);
|
||||
|
||||
const needsAttentionEntities = filterNeedsAttentionEntities(
|
||||
const lowBatteryEntities = filterLowBatteryEntities(
|
||||
this.hass!,
|
||||
maintenanceEntities
|
||||
);
|
||||
|
||||
if (needsAttentionEntities.length > 0) {
|
||||
return this.hass.localize(
|
||||
"ui.card.home-summary.count_maintenance_issues",
|
||||
{
|
||||
count: needsAttentionEntities.length,
|
||||
}
|
||||
);
|
||||
const unavailableBatteryEntities = filterUnavailableBatteryEntities(
|
||||
this.hass!,
|
||||
maintenanceEntities
|
||||
);
|
||||
|
||||
const lowBatteryText =
|
||||
lowBatteryEntities.length > 0
|
||||
? this.hass.localize(
|
||||
"ui.card.home-summary.count_maintenance_low_battery_issues",
|
||||
{
|
||||
count: lowBatteryEntities.length,
|
||||
}
|
||||
)
|
||||
: undefined;
|
||||
|
||||
const unavailableText =
|
||||
unavailableBatteryEntities.length > 0
|
||||
? this.hass.localize(
|
||||
"ui.card.home-summary.count_maintenance_issues_unavailable_battery_entities",
|
||||
{
|
||||
count: unavailableBatteryEntities.length,
|
||||
}
|
||||
)
|
||||
: undefined;
|
||||
|
||||
if (lowBatteryText && unavailableText) {
|
||||
return `${lowBatteryText}, ${unavailableText}`;
|
||||
}
|
||||
|
||||
if (lowBatteryText) {
|
||||
return lowBatteryText;
|
||||
}
|
||||
|
||||
if (unavailableText) {
|
||||
return unavailableText;
|
||||
}
|
||||
|
||||
return this.hass.localize("ui.card.home-summary.all_maintenance_good");
|
||||
}
|
||||
case "energy": {
|
||||
|
||||
@@ -12,7 +12,7 @@ import type { ActionHandlerEvent } from "../../../data/lovelace/action_handler";
|
||||
import type { HomeAssistant } from "../../../types";
|
||||
import { actionHandler } from "../common/directives/action-handler-directive";
|
||||
import { handleAction } from "../common/handle-action";
|
||||
import { hasAction } from "../common/has-action";
|
||||
import { hasAction, hasAnyAction } from "../common/has-action";
|
||||
import { hasConfigChanged } from "../common/has-changed";
|
||||
import { createEntityNotFoundWarning } from "../components/hui-warning";
|
||||
import type { LovelaceCard, LovelaceCardEditor } from "../types";
|
||||
@@ -52,10 +52,17 @@ export class HuiPictureCard extends LitElement implements LovelaceCard {
|
||||
throw new Error("Image required");
|
||||
}
|
||||
|
||||
this._config = {
|
||||
tap_action: { action: "more-info" },
|
||||
...config,
|
||||
};
|
||||
if (config.image_entity) {
|
||||
this._config = {
|
||||
tap_action: { action: "more-info" },
|
||||
...config,
|
||||
};
|
||||
} else {
|
||||
this._config = {
|
||||
tap_action: { action: "none" },
|
||||
...config,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
protected shouldUpdate(changedProps: PropertyValues): boolean {
|
||||
@@ -167,6 +174,11 @@ export class HuiPictureCard extends LitElement implements LovelaceCard {
|
||||
return nothing;
|
||||
}
|
||||
|
||||
const clickable = Boolean(
|
||||
(this._config.image_entity && !this._config.tap_action) ||
|
||||
hasAnyAction(this._config)
|
||||
);
|
||||
|
||||
return html`
|
||||
<ha-card
|
||||
@action=${this._handleAction}
|
||||
@@ -180,15 +192,7 @@ export class HuiPictureCard extends LitElement implements LovelaceCard {
|
||||
: undefined
|
||||
)}
|
||||
class=${classMap({
|
||||
clickable: Boolean(
|
||||
(this._config.image_entity && !this._config.tap_action) ||
|
||||
(this._config.tap_action &&
|
||||
this._config.tap_action.action !== "none") ||
|
||||
(this._config.hold_action &&
|
||||
this._config.hold_action.action !== "none") ||
|
||||
(this._config.double_tap_action &&
|
||||
this._config.double_tap_action.action !== "none")
|
||||
),
|
||||
clickable,
|
||||
})}
|
||||
>
|
||||
<img
|
||||
|
||||
@@ -55,7 +55,6 @@ class HuiEntitiesToggle extends LitElement {
|
||||
ha-control-switch {
|
||||
--control-switch-thickness: 20px;
|
||||
--control-switch-off-color: var(--state-inactive-color);
|
||||
--control-switch-touch-area-size: var(--ha-space-2);
|
||||
}
|
||||
`;
|
||||
|
||||
|
||||
@@ -419,6 +419,7 @@ export class HuiDialogEditBadge
|
||||
.content {
|
||||
width: 100%;
|
||||
max-width: 100%;
|
||||
gap: var(--ha-space-3);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -419,6 +419,7 @@ export class HuiDialogEditCard
|
||||
.content {
|
||||
width: 100%;
|
||||
max-width: 100%;
|
||||
gap: var(--ha-space-3);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -68,9 +68,7 @@ export class HuiPictureCardEditor
|
||||
{
|
||||
name: "tap_action",
|
||||
selector: {
|
||||
ui_action: {
|
||||
default_action: "more-info",
|
||||
},
|
||||
ui_action: {},
|
||||
},
|
||||
context: ACTION_RELATED_CONTEXT,
|
||||
},
|
||||
|
||||
@@ -8,7 +8,7 @@ import type { ActionHandlerEvent } from "../../../data/lovelace/action_handler";
|
||||
import type { HomeAssistant } from "../../../types";
|
||||
import { actionHandler } from "../common/directives/action-handler-directive";
|
||||
import { handleAction } from "../common/handle-action";
|
||||
import { hasAction } from "../common/has-action";
|
||||
import { hasAction, hasAnyAction } from "../common/has-action";
|
||||
import type { LovelaceHeaderFooter } from "../types";
|
||||
import type { PictureHeaderFooterConfig } from "./types";
|
||||
|
||||
@@ -56,9 +56,7 @@ export class HuiPictureHeaderFooter
|
||||
return nothing;
|
||||
}
|
||||
|
||||
const clickable = Boolean(
|
||||
this._config.tap_action || this._config.hold_action
|
||||
);
|
||||
const clickable = hasAnyAction(this._config);
|
||||
|
||||
return html`
|
||||
<img
|
||||
|
||||
@@ -409,6 +409,8 @@ class HUIRoot extends LitElement {
|
||||
slot="actionItems"
|
||||
.id="button-${index}"
|
||||
.path=${item.icon}
|
||||
.label=${label}
|
||||
hide-title
|
||||
@click=${item.buttonAction}
|
||||
></ha-icon-button>
|
||||
<ha-tooltip placement="bottom" .for="button-${index}">
|
||||
|
||||
@@ -31,7 +31,7 @@ export const maintenanceEntityFilters: EntityFilter[] = [
|
||||
|
||||
const LOW_BATTERY_THRESHOLD = 20;
|
||||
|
||||
export const filterNeedsAttentionEntities = (
|
||||
export const filterLowBatteryEntities = (
|
||||
hass: HomeAssistant,
|
||||
entityIds: string[]
|
||||
): string[] =>
|
||||
@@ -40,6 +40,14 @@ export const filterNeedsAttentionEntities = (
|
||||
return !isNaN(stateValue) && stateValue <= LOW_BATTERY_THRESHOLD;
|
||||
});
|
||||
|
||||
export const filterUnavailableBatteryEntities = (
|
||||
hass: HomeAssistant,
|
||||
entityIds: string[]
|
||||
): string[] =>
|
||||
entityIds.filter((entityId) => {
|
||||
return hass.states[entityId]?.state === "unavailable";
|
||||
});
|
||||
|
||||
const computeBatteryTileCard = (entityId: string): TileCardConfig => ({
|
||||
type: "tile",
|
||||
entity: entityId,
|
||||
|
||||
@@ -44,6 +44,7 @@ export {
|
||||
drawSelection,
|
||||
EditorView,
|
||||
highlightActiveLine,
|
||||
hoverTooltip,
|
||||
keymap,
|
||||
lineNumbers,
|
||||
rectangularSelection,
|
||||
@@ -71,9 +72,10 @@ export const closeBracketsOverride = Prec.highest(
|
||||
|
||||
export {
|
||||
haJinjaCompletionSource,
|
||||
haJinjaHoverSource,
|
||||
JINJA_FUNCTION_ARG_TYPES,
|
||||
} from "./jinja_ha_completions";
|
||||
export type { JinjaArgType } from "./jinja_ha_completions";
|
||||
export type { HassArgHoverContext, JinjaArgType } from "./jinja_ha_completions";
|
||||
export { closePercentBrace };
|
||||
|
||||
export const langCompartment = new Compartment();
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -218,7 +218,8 @@
|
||||
"all_secure": "All secure",
|
||||
"no_media_playing": "No media playing",
|
||||
"count_media_playing": "{count} {count, plural,\n one {playing}\n other {playing}\n}",
|
||||
"count_maintenance_issues": "{count} {count, plural,\n one {issue}\n other {issues}\n}",
|
||||
"count_maintenance_low_battery_issues": "{count} {count, plural,\n one {low battery}\n other {low batteries}\n}",
|
||||
"count_maintenance_issues_unavailable_battery_entities": "{count} {count, plural,\n one {unavailable device}\n other {unavailable devices}\n}",
|
||||
"all_maintenance_good": "All good",
|
||||
"count_persons_home": "{count} {count, plural,\n one {person}\n other {people}\n} home",
|
||||
"nobody_home": "No one home"
|
||||
@@ -491,6 +492,11 @@
|
||||
"markdown": "Markdown"
|
||||
},
|
||||
"components": {
|
||||
"input": {
|
||||
"clear": "Clear",
|
||||
"show_password": "Show password",
|
||||
"hide_password": "Hide password"
|
||||
},
|
||||
"selectors": {
|
||||
"serial_port": {
|
||||
"enter_manually": "Enter manually",
|
||||
@@ -1498,6 +1504,9 @@
|
||||
"area_label": "Area",
|
||||
"description": "Configure which areas correspond to each vacuum segment"
|
||||
},
|
||||
"codemirror": {
|
||||
"open_documentation": "Open documentation"
|
||||
},
|
||||
"safe_mode": {
|
||||
"title": "Safe mode",
|
||||
"text": "Home Assistant is running in safe mode, custom integrations and community frontend modules are not available. Restart Home Assistant to exit safe mode."
|
||||
@@ -3558,7 +3567,7 @@
|
||||
"show_all": "Show all backups"
|
||||
},
|
||||
"settings": {
|
||||
"title": "Backup settings",
|
||||
"title": "Automatic backup",
|
||||
"configure": "Configure backup settings",
|
||||
"schedule": "Automatic backup schedule and retention",
|
||||
"schedule_copies_all": "and keep all backups",
|
||||
@@ -3604,6 +3613,10 @@
|
||||
"sat": "Sa",
|
||||
"sun": "Su"
|
||||
}
|
||||
},
|
||||
"app_update_backup": {
|
||||
"title": "App update backup",
|
||||
"description": "Backup behavior for app updates"
|
||||
}
|
||||
},
|
||||
"backups": {
|
||||
@@ -3615,13 +3628,15 @@
|
||||
"new_backup": "[%key:ui::panel::config::backup::overview::new_backup%]"
|
||||
},
|
||||
"settings": {
|
||||
"header": "Backup settings",
|
||||
"header": "Automatic backups",
|
||||
"menu": {
|
||||
"change_default_location": "Change default action location"
|
||||
},
|
||||
"schedule": {
|
||||
"title": "Automatic backups",
|
||||
"description": "Let Home Assistant take care of your backups by creating a scheduled backup that also removes older backups."
|
||||
"title": "Backup cycle",
|
||||
"description": "Let Home Assistant take care of your backups by creating a scheduled backup that also removes older backups.",
|
||||
"error_load": "Error loading Supervisor update config: {error}",
|
||||
"error_save": "Error saving Supervisor update config: {error}"
|
||||
},
|
||||
"data": {
|
||||
"title": "Backup data"
|
||||
@@ -3649,6 +3664,9 @@
|
||||
"error_save": "Error saving Supervisor update config: {error}"
|
||||
}
|
||||
},
|
||||
"app_update_backups": {
|
||||
"header": "App update backups"
|
||||
},
|
||||
"details": {
|
||||
"header": "Backup",
|
||||
"not_found": "Not found",
|
||||
@@ -3876,7 +3894,8 @@
|
||||
"no_listeners": "This template does not listen for any events and will not update automatically.",
|
||||
"listeners": "This template listens for the following state changed events:",
|
||||
"entity": "Entity",
|
||||
"domain": "Domain"
|
||||
"domain": "Domain",
|
||||
"keyboard_tip": "Press {autocomplete} to trigger autocomplete, when your cursor is inside a function that supports it."
|
||||
},
|
||||
"statistics": {
|
||||
"title": "Statistics",
|
||||
|
||||
156
yarn.lock
156
yarn.lock
@@ -1857,9 +1857,9 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@home-assistant/webawesome@npm:3.3.1-ha.1":
|
||||
version: 3.3.1-ha.1
|
||||
resolution: "@home-assistant/webawesome@npm:3.3.1-ha.1"
|
||||
"@home-assistant/webawesome@npm:3.3.1-ha.2":
|
||||
version: 3.3.1-ha.2
|
||||
resolution: "@home-assistant/webawesome@npm:3.3.1-ha.2"
|
||||
dependencies:
|
||||
"@ctrl/tinycolor": "npm:4.1.0"
|
||||
"@floating-ui/dom": "npm:^1.6.13"
|
||||
@@ -1870,7 +1870,7 @@ __metadata:
|
||||
lit: "npm:^3.2.1"
|
||||
nanoid: "npm:^5.1.5"
|
||||
qr-creator: "npm:^1.0.0"
|
||||
checksum: 10/903b7e5e44a9c4afa5120b5fbbf139880889798a82262b10b5c5fa51cd56cd344d8027d69658b15c85efc579688476bbd8e5eff73535f903959bbd9ffd00051f
|
||||
checksum: 10/c66965544bb34eb9d6d131579c31e4c6d21c8c231bdf565db61195da03a995d17e25d6d997875c902d7d2f3020c70434088efb7299b2626d4a7d1343cb33d726
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@@ -4383,105 +4383,105 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@typescript-eslint/eslint-plugin@npm:8.59.0":
|
||||
version: 8.59.0
|
||||
resolution: "@typescript-eslint/eslint-plugin@npm:8.59.0"
|
||||
"@typescript-eslint/eslint-plugin@npm:8.59.1":
|
||||
version: 8.59.1
|
||||
resolution: "@typescript-eslint/eslint-plugin@npm:8.59.1"
|
||||
dependencies:
|
||||
"@eslint-community/regexpp": "npm:^4.12.2"
|
||||
"@typescript-eslint/scope-manager": "npm:8.59.0"
|
||||
"@typescript-eslint/type-utils": "npm:8.59.0"
|
||||
"@typescript-eslint/utils": "npm:8.59.0"
|
||||
"@typescript-eslint/visitor-keys": "npm:8.59.0"
|
||||
"@typescript-eslint/scope-manager": "npm:8.59.1"
|
||||
"@typescript-eslint/type-utils": "npm:8.59.1"
|
||||
"@typescript-eslint/utils": "npm:8.59.1"
|
||||
"@typescript-eslint/visitor-keys": "npm:8.59.1"
|
||||
ignore: "npm:^7.0.5"
|
||||
natural-compare: "npm:^1.4.0"
|
||||
ts-api-utils: "npm:^2.5.0"
|
||||
peerDependencies:
|
||||
"@typescript-eslint/parser": ^8.59.0
|
||||
"@typescript-eslint/parser": ^8.59.1
|
||||
eslint: ^8.57.0 || ^9.0.0 || ^10.0.0
|
||||
typescript: ">=4.8.4 <6.1.0"
|
||||
checksum: 10/fcf2c85cb37d61854d2c03fa11c66ad58d99f4eee731dd09663f20f0395e642b12edeab2a6c368ac1806505b2071a01de01bc30b9011fa309299836e868a293a
|
||||
checksum: 10/c736ee32211a3751e31151b51dacc8cfa5bf18e086f2a87aba7ee325f7e2fa96d8b9febdbaf4dfa70d14954312b7b9740fbe5d5886b3f8561c4a94a9c7ff7688
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@typescript-eslint/parser@npm:8.59.0":
|
||||
version: 8.59.0
|
||||
resolution: "@typescript-eslint/parser@npm:8.59.0"
|
||||
"@typescript-eslint/parser@npm:8.59.1":
|
||||
version: 8.59.1
|
||||
resolution: "@typescript-eslint/parser@npm:8.59.1"
|
||||
dependencies:
|
||||
"@typescript-eslint/scope-manager": "npm:8.59.0"
|
||||
"@typescript-eslint/types": "npm:8.59.0"
|
||||
"@typescript-eslint/typescript-estree": "npm:8.59.0"
|
||||
"@typescript-eslint/visitor-keys": "npm:8.59.0"
|
||||
"@typescript-eslint/scope-manager": "npm:8.59.1"
|
||||
"@typescript-eslint/types": "npm:8.59.1"
|
||||
"@typescript-eslint/typescript-estree": "npm:8.59.1"
|
||||
"@typescript-eslint/visitor-keys": "npm:8.59.1"
|
||||
debug: "npm:^4.4.3"
|
||||
peerDependencies:
|
||||
eslint: ^8.57.0 || ^9.0.0 || ^10.0.0
|
||||
typescript: ">=4.8.4 <6.1.0"
|
||||
checksum: 10/b8990e1b67e6f55aa4884807e6c3b6bd08c58f96ea4f03f19e7aba3fc1b16f040fe58378490de9bd831c804eb48e633e30e5baf291b8e8dd53960424e5751391
|
||||
checksum: 10/b014b485e5ec9c7430a87117271836b86fd80083fe6b1d216167313518f26222f45c0ee3f4cbc0616dbd6335cbde50336d8953ca5ffefecc55b2d896ac7645f9
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@typescript-eslint/project-service@npm:8.59.0":
|
||||
version: 8.59.0
|
||||
resolution: "@typescript-eslint/project-service@npm:8.59.0"
|
||||
"@typescript-eslint/project-service@npm:8.59.1":
|
||||
version: 8.59.1
|
||||
resolution: "@typescript-eslint/project-service@npm:8.59.1"
|
||||
dependencies:
|
||||
"@typescript-eslint/tsconfig-utils": "npm:^8.59.0"
|
||||
"@typescript-eslint/types": "npm:^8.59.0"
|
||||
"@typescript-eslint/tsconfig-utils": "npm:^8.59.1"
|
||||
"@typescript-eslint/types": "npm:^8.59.1"
|
||||
debug: "npm:^4.4.3"
|
||||
peerDependencies:
|
||||
typescript: ">=4.8.4 <6.1.0"
|
||||
checksum: 10/b842f1e0623c3a679d21d76c7ca38698787681d40f6a9ce93c8983120fb6795a2395907d530e4f8d89b4ac5bc65e71bbfdf2d8060f210c8487cffdae40baea74
|
||||
checksum: 10/dd98f49a407cb21999d31ec527a0f8c2c34422dde9fdb21210d66c3cc3d498d9d3678d95c99d76450af68ce3392692902d9ba044718d6c99122655df7afdc0a7
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@typescript-eslint/scope-manager@npm:8.59.0":
|
||||
version: 8.59.0
|
||||
resolution: "@typescript-eslint/scope-manager@npm:8.59.0"
|
||||
"@typescript-eslint/scope-manager@npm:8.59.1":
|
||||
version: 8.59.1
|
||||
resolution: "@typescript-eslint/scope-manager@npm:8.59.1"
|
||||
dependencies:
|
||||
"@typescript-eslint/types": "npm:8.59.0"
|
||||
"@typescript-eslint/visitor-keys": "npm:8.59.0"
|
||||
checksum: 10/8bb1182559e7676120ba12bdac11edea9fb414bd33d379a1902b035b8b4b68d23ad239d845bfe6943b5da13ecd938ea1482c73e8c6ddb4d7e3e0f8e111467e28
|
||||
"@typescript-eslint/types": "npm:8.59.1"
|
||||
"@typescript-eslint/visitor-keys": "npm:8.59.1"
|
||||
checksum: 10/50c941d1af470d3e67a9bd2247c541a676ae6bb2931440a44458682d61382ba1194ce29d0388dd1e538c5a35d7a542febd9519d8170abe758692d1b6cd196eab
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@typescript-eslint/tsconfig-utils@npm:8.59.0, @typescript-eslint/tsconfig-utils@npm:^8.59.0":
|
||||
version: 8.59.0
|
||||
resolution: "@typescript-eslint/tsconfig-utils@npm:8.59.0"
|
||||
"@typescript-eslint/tsconfig-utils@npm:8.59.1, @typescript-eslint/tsconfig-utils@npm:^8.59.1":
|
||||
version: 8.59.1
|
||||
resolution: "@typescript-eslint/tsconfig-utils@npm:8.59.1"
|
||||
peerDependencies:
|
||||
typescript: ">=4.8.4 <6.1.0"
|
||||
checksum: 10/9c094c199be4803d696dbf7cb5cdb76741876e412bf97ddde0133a75e11bc47345354b3bb188a0ff101b7ce2c582187e758696ab89c1981892a43162f36d0af1
|
||||
checksum: 10/9e3351bb182bb02f6f140759472f08ce334c7c96f4ebfeec8e9e404fe60b8fe1865e1a6d1b50526f83f41e7224301485e46459df6c3675923f3b657177415cd7
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@typescript-eslint/type-utils@npm:8.59.0":
|
||||
version: 8.59.0
|
||||
resolution: "@typescript-eslint/type-utils@npm:8.59.0"
|
||||
"@typescript-eslint/type-utils@npm:8.59.1":
|
||||
version: 8.59.1
|
||||
resolution: "@typescript-eslint/type-utils@npm:8.59.1"
|
||||
dependencies:
|
||||
"@typescript-eslint/types": "npm:8.59.0"
|
||||
"@typescript-eslint/typescript-estree": "npm:8.59.0"
|
||||
"@typescript-eslint/utils": "npm:8.59.0"
|
||||
"@typescript-eslint/types": "npm:8.59.1"
|
||||
"@typescript-eslint/typescript-estree": "npm:8.59.1"
|
||||
"@typescript-eslint/utils": "npm:8.59.1"
|
||||
debug: "npm:^4.4.3"
|
||||
ts-api-utils: "npm:^2.5.0"
|
||||
peerDependencies:
|
||||
eslint: ^8.57.0 || ^9.0.0 || ^10.0.0
|
||||
typescript: ">=4.8.4 <6.1.0"
|
||||
checksum: 10/9c2d34c10676d5726f93b975136295971ac7d2a53f74bfba51ae71deefaa36292adda79d016782196b729429143634b7f90224c27dcdb3a884b9771128be7490
|
||||
checksum: 10/8a8a71656f8fab446024e55b24f6f6c4b3ee4d4cdcb593ff68ec0ca10530fcb4d451628c03898c929e91445a999cbe980c0cfaec1b53a7c5ddc8ac899ad665fa
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@typescript-eslint/types@npm:8.59.0, @typescript-eslint/types@npm:^8.56.0, @typescript-eslint/types@npm:^8.59.0":
|
||||
version: 8.59.0
|
||||
resolution: "@typescript-eslint/types@npm:8.59.0"
|
||||
checksum: 10/51a773339c58a350d0ddaecba46ba735696f11829cab1f9b3d5d58a4bbd498693296ae742e3959d32f3bb29676c8e6bd120b970379d749a5a9b419393696930d
|
||||
"@typescript-eslint/types@npm:8.59.1, @typescript-eslint/types@npm:^8.56.0, @typescript-eslint/types@npm:^8.59.1":
|
||||
version: 8.59.1
|
||||
resolution: "@typescript-eslint/types@npm:8.59.1"
|
||||
checksum: 10/4d324a01c2314d8e196b43b9dc5fe9a4d82c1b65f4915cd2f965879c5565d4453603b6f7b6bcdc436fb629135f07ad0f9d274e4697b02ce8bc1c0310916f7ace
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@typescript-eslint/typescript-estree@npm:8.59.0":
|
||||
version: 8.59.0
|
||||
resolution: "@typescript-eslint/typescript-estree@npm:8.59.0"
|
||||
"@typescript-eslint/typescript-estree@npm:8.59.1":
|
||||
version: 8.59.1
|
||||
resolution: "@typescript-eslint/typescript-estree@npm:8.59.1"
|
||||
dependencies:
|
||||
"@typescript-eslint/project-service": "npm:8.59.0"
|
||||
"@typescript-eslint/tsconfig-utils": "npm:8.59.0"
|
||||
"@typescript-eslint/types": "npm:8.59.0"
|
||||
"@typescript-eslint/visitor-keys": "npm:8.59.0"
|
||||
"@typescript-eslint/project-service": "npm:8.59.1"
|
||||
"@typescript-eslint/tsconfig-utils": "npm:8.59.1"
|
||||
"@typescript-eslint/types": "npm:8.59.1"
|
||||
"@typescript-eslint/visitor-keys": "npm:8.59.1"
|
||||
debug: "npm:^4.4.3"
|
||||
minimatch: "npm:^10.2.2"
|
||||
semver: "npm:^7.7.3"
|
||||
@@ -4489,32 +4489,32 @@ __metadata:
|
||||
ts-api-utils: "npm:^2.5.0"
|
||||
peerDependencies:
|
||||
typescript: ">=4.8.4 <6.1.0"
|
||||
checksum: 10/48eba6a117a36c4bf569aa1a728463619b131a45a6891cc0a5d2454828d9d3d07a499e9906de0df31de57761ce1d13aebb635a059782f3cc16563e3e63a29713
|
||||
checksum: 10/8ede99640ac8b08ac73905bbc66dd06b2c4dc211240a4a9cb532b0fcf5c36ec9e7639ed7e1c17f86a948499279ff93e9dbcdf9170661d9f8347fcb53e8266772
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@typescript-eslint/utils@npm:8.59.0":
|
||||
version: 8.59.0
|
||||
resolution: "@typescript-eslint/utils@npm:8.59.0"
|
||||
"@typescript-eslint/utils@npm:8.59.1":
|
||||
version: 8.59.1
|
||||
resolution: "@typescript-eslint/utils@npm:8.59.1"
|
||||
dependencies:
|
||||
"@eslint-community/eslint-utils": "npm:^4.9.1"
|
||||
"@typescript-eslint/scope-manager": "npm:8.59.0"
|
||||
"@typescript-eslint/types": "npm:8.59.0"
|
||||
"@typescript-eslint/typescript-estree": "npm:8.59.0"
|
||||
"@typescript-eslint/scope-manager": "npm:8.59.1"
|
||||
"@typescript-eslint/types": "npm:8.59.1"
|
||||
"@typescript-eslint/typescript-estree": "npm:8.59.1"
|
||||
peerDependencies:
|
||||
eslint: ^8.57.0 || ^9.0.0 || ^10.0.0
|
||||
typescript: ">=4.8.4 <6.1.0"
|
||||
checksum: 10/70547510f16459ca29e207584676f7c15626b5f7e2562643144fe037a1a9c4ca7116be99e67b9045f0de60db0022affb58c34c553a5370276ff8f542f7b05732
|
||||
checksum: 10/26ae39a574e56d92b6fc406113e797c354fce8b377721cc5dd50579a0e9f8c3efe23c7693826ce2c16be96490520dd6ce7e145c4c39c22d8d00f2614791603ba
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@typescript-eslint/visitor-keys@npm:8.59.0":
|
||||
version: 8.59.0
|
||||
resolution: "@typescript-eslint/visitor-keys@npm:8.59.0"
|
||||
"@typescript-eslint/visitor-keys@npm:8.59.1":
|
||||
version: 8.59.1
|
||||
resolution: "@typescript-eslint/visitor-keys@npm:8.59.1"
|
||||
dependencies:
|
||||
"@typescript-eslint/types": "npm:8.59.0"
|
||||
"@typescript-eslint/types": "npm:8.59.1"
|
||||
eslint-visitor-keys: "npm:^5.0.0"
|
||||
checksum: 10/b81753b9ddddeb3564e44d1199ba5546028731c7b5b3270938525f1f2b549d1df5fa8f203d9b3eacc120fa6b5af314cb1fb69d3a12d1dcce18a52a0fe316628d
|
||||
checksum: 10/5343f3424cafdcaf2550fade29eca6b86ad3f6ac953aef6ba1dccd39789a1c38520634fbbc0814419d9227f508789053c1c9f59c2841d72e56431c3fdd93ac65
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@@ -8144,7 +8144,7 @@ __metadata:
|
||||
"@fullcalendar/list": "npm:6.1.20"
|
||||
"@fullcalendar/luxon3": "npm:6.1.20"
|
||||
"@fullcalendar/timegrid": "npm:6.1.20"
|
||||
"@home-assistant/webawesome": "npm:3.3.1-ha.1"
|
||||
"@home-assistant/webawesome": "npm:3.3.1-ha.2"
|
||||
"@html-eslint/eslint-plugin": "npm:0.59.0"
|
||||
"@lezer/highlight": "npm:1.2.3"
|
||||
"@lit-labs/motion": "npm:1.1.0"
|
||||
@@ -8275,7 +8275,7 @@ __metadata:
|
||||
tinykeys: "npm:3.0.0"
|
||||
ts-lit-plugin: "npm:2.0.2"
|
||||
typescript: "npm:6.0.3"
|
||||
typescript-eslint: "npm:8.59.0"
|
||||
typescript-eslint: "npm:8.59.1"
|
||||
vite-tsconfig-paths: "npm:6.1.1"
|
||||
vitest: "npm:4.1.5"
|
||||
webpack-stats-plugin: "npm:1.1.3"
|
||||
@@ -12568,18 +12568,18 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"typescript-eslint@npm:8.59.0":
|
||||
version: 8.59.0
|
||||
resolution: "typescript-eslint@npm:8.59.0"
|
||||
"typescript-eslint@npm:8.59.1":
|
||||
version: 8.59.1
|
||||
resolution: "typescript-eslint@npm:8.59.1"
|
||||
dependencies:
|
||||
"@typescript-eslint/eslint-plugin": "npm:8.59.0"
|
||||
"@typescript-eslint/parser": "npm:8.59.0"
|
||||
"@typescript-eslint/typescript-estree": "npm:8.59.0"
|
||||
"@typescript-eslint/utils": "npm:8.59.0"
|
||||
"@typescript-eslint/eslint-plugin": "npm:8.59.1"
|
||||
"@typescript-eslint/parser": "npm:8.59.1"
|
||||
"@typescript-eslint/typescript-estree": "npm:8.59.1"
|
||||
"@typescript-eslint/utils": "npm:8.59.1"
|
||||
peerDependencies:
|
||||
eslint: ^8.57.0 || ^9.0.0 || ^10.0.0
|
||||
typescript: ">=4.8.4 <6.1.0"
|
||||
checksum: 10/e015494cae2ae88c291e87d9d8c2c8d9924536f2edfac1a1da5e05f5ee083df7a8d916549f87af8a7b818d01de2bd505e29fdf991a086522a062387b4c2f1f64
|
||||
checksum: 10/d35d30bdcff5b9644c9bf500d3ad74cebbd41612bf2669c3e3208cd74ee43302941666336acfca65bc44352b9b58c0455afe0a9e7106f12e54789b8c1f16dc11
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
|
||||
Reference in New Issue
Block a user