mirror of
https://github.com/home-assistant/frontend.git
synced 2026-05-19 23:57:07 +00:00
Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 190ef6bb87 |
@@ -1,2 +1,3 @@
|
||||
[build.environment]
|
||||
YARN_VERSION = "1.22.11"
|
||||
NODE_OPTIONS = "--max_old_space_size=6144"
|
||||
|
||||
+3
-3
@@ -74,8 +74,8 @@
|
||||
"@replit/codemirror-indentation-markers": "6.5.3",
|
||||
"@swc/helpers": "0.5.21",
|
||||
"@thomasloven/round-slider": "0.6.0",
|
||||
"@tsparticles/engine": "4.0.2",
|
||||
"@tsparticles/preset-links": "4.0.2",
|
||||
"@tsparticles/engine": "4.0.1",
|
||||
"@tsparticles/preset-links": "4.0.1",
|
||||
"@vibrant/color": "4.0.4",
|
||||
"@webcomponents/scoped-custom-element-registry": "0.0.10",
|
||||
"@webcomponents/webcomponentsjs": "2.8.0",
|
||||
@@ -187,7 +187,7 @@
|
||||
"jsdom": "29.1.1",
|
||||
"jszip": "3.10.1",
|
||||
"license-checker-rseidelsohn": "4.4.2",
|
||||
"lint-staged": "17.0.5",
|
||||
"lint-staged": "17.0.4",
|
||||
"lit-analyzer": "2.0.3",
|
||||
"lodash.merge": "4.6.2",
|
||||
"lodash.template": "4.18.1",
|
||||
|
||||
@@ -18,46 +18,7 @@
|
||||
"enabled": true,
|
||||
"schedule": ["on the 19th day of the month before 4am"]
|
||||
},
|
||||
"customDatasources": {
|
||||
"ha-core-python": {
|
||||
"defaultRegistryUrlTemplate": "https://raw.githubusercontent.com/home-assistant/core/dev/.python-version",
|
||||
"format": "plain"
|
||||
}
|
||||
},
|
||||
"customManagers": [
|
||||
{
|
||||
"description": "Keep PYTHON_VERSION in sync with home-assistant/core (patch + minor)",
|
||||
"customType": "regex",
|
||||
"managerFilePatterns": ["/^\\.github/workflows/[^/]+\\.ya?ml$/"],
|
||||
"matchStrings": ["PYTHON_VERSION: \"(?<currentValue>[^\"]+)\""],
|
||||
"depNameTemplate": "python",
|
||||
"datasourceTemplate": "custom.ha-core-python",
|
||||
"versioningTemplate": "python"
|
||||
},
|
||||
{
|
||||
"description": "Keep devcontainer image and requires-python in sync with home-assistant/core (minor only)",
|
||||
"customType": "regex",
|
||||
"managerFilePatterns": [
|
||||
"/^\\.devcontainer/Dockerfile$/",
|
||||
"/^pyproject\\.toml$/"
|
||||
],
|
||||
"matchStrings": [
|
||||
"devcontainers/python:(?<currentValue>[\\d.]+)",
|
||||
"requires-python = \">=(?<currentValue>[^\"]+)\""
|
||||
],
|
||||
"depNameTemplate": "python",
|
||||
"datasourceTemplate": "custom.ha-core-python",
|
||||
"versioningTemplate": "python",
|
||||
"extractVersionTemplate": "^(?<version>\\d+\\.\\d+)"
|
||||
}
|
||||
],
|
||||
"packageRules": [
|
||||
{
|
||||
"description": "Group all Python version updates from home-assistant/core",
|
||||
"matchDepNames": ["python"],
|
||||
"matchDatasources": ["custom.ha-core-python"],
|
||||
"groupName": "Python version"
|
||||
},
|
||||
{
|
||||
"description": "MDC packages are pinned to the same version as MWC",
|
||||
"extends": ["monorepo:material-components-web"],
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
* @param arr - The array to get combinations of
|
||||
* @returns A multidimensional array of all possible combinations
|
||||
*/
|
||||
export function getAllCombinations<T>(arr: readonly T[]): T[][] {
|
||||
export function getAllCombinations<T>(arr: T[]) {
|
||||
return arr.reduce<T[][]>(
|
||||
(combinations, element) =>
|
||||
combinations.concat(
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import type { HassEntity } from "home-assistant-js-websocket";
|
||||
import { UNAVAILABLE, UNKNOWN } from "../../data/entity/entity";
|
||||
import { isUnavailableState } from "../../data/entity/entity";
|
||||
import type { HomeAssistant } from "../../types";
|
||||
|
||||
interface EntityUnitStubConfig {
|
||||
@@ -21,24 +21,32 @@ export const computeEntityUnitDisplay = (
|
||||
stateObj: HassEntity | undefined,
|
||||
config: EntityUnitStubConfig
|
||||
): string => {
|
||||
let unit;
|
||||
if (
|
||||
!stateObj ||
|
||||
stateObj.state === UNAVAILABLE ||
|
||||
stateObj.state === UNKNOWN ||
|
||||
(!config.attribute && stateObj.attributes.device_class === "duration")
|
||||
stateObj &&
|
||||
!isUnavailableState(stateObj.state) &&
|
||||
(config.attribute || stateObj.attributes.device_class !== "duration")
|
||||
) {
|
||||
return "";
|
||||
// check for an explicitly defined unit in config
|
||||
unit = config.unit;
|
||||
|
||||
if (!unit) {
|
||||
if (!config.attribute) {
|
||||
// use entity's unit_of_measurement
|
||||
const stateParts = hass.formatEntityStateToParts(stateObj);
|
||||
unit = stateParts.find((part) => part.type === "unit")?.value;
|
||||
} else {
|
||||
// use attribute's unit if available
|
||||
const attrParts = hass.formatEntityAttributeValueToParts(
|
||||
stateObj,
|
||||
config.attribute
|
||||
);
|
||||
unit = attrParts.find((part) => part.type === "unit")?.value;
|
||||
}
|
||||
}
|
||||
|
||||
return unit ?? "";
|
||||
}
|
||||
|
||||
// check for an explicitly defined unit in config
|
||||
if (config.unit) {
|
||||
return config.unit;
|
||||
}
|
||||
|
||||
// otherwise derive from the entity's state or attribute
|
||||
const parts = config.attribute
|
||||
? hass.formatEntityAttributeValueToParts(stateObj, config.attribute)
|
||||
: hass.formatEntityStateToParts(stateObj);
|
||||
|
||||
return parts.find((part) => part.type === "unit")?.value ?? "";
|
||||
return "";
|
||||
};
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import type { HassEntity } from "home-assistant-js-websocket";
|
||||
import { UNAVAILABLE, UNKNOWN } from "../../data/entity/entity";
|
||||
import { UNAVAILABLE_STATES } from "../../data/entity/entity";
|
||||
import type { HomeAssistant } from "../../types";
|
||||
import { stringCompare } from "../string/compare";
|
||||
import { computeDomain } from "./compute_domain";
|
||||
@@ -253,7 +253,7 @@ export const getStatesDomain = (
|
||||
|
||||
if (!attribute) {
|
||||
// All entities can have unavailable states
|
||||
result.push(UNAVAILABLE, UNKNOWN);
|
||||
result.push(...UNAVAILABLE_STATES);
|
||||
}
|
||||
|
||||
if (!attribute && domain in FIXED_DOMAIN_STATES) {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import type { HassEntity } from "home-assistant-js-websocket";
|
||||
import { UNAVAILABLE, UNKNOWN } from "../../data/entity/entity";
|
||||
import { isUnavailableState, UNAVAILABLE } from "../../data/entity/entity";
|
||||
import type { HomeAssistant } from "../../types";
|
||||
import { computeStateDomain } from "./compute_state_domain";
|
||||
|
||||
@@ -8,18 +8,12 @@ export const computeGroupEntitiesState = (states: HassEntity[]): string => {
|
||||
return UNAVAILABLE;
|
||||
}
|
||||
|
||||
const allUnavailable = states.every(
|
||||
(stateObj) => stateObj.state === UNAVAILABLE
|
||||
const validState = states.some(
|
||||
(stateObj) => !isUnavailableState(stateObj.state)
|
||||
);
|
||||
if (allUnavailable) {
|
||||
return UNAVAILABLE;
|
||||
}
|
||||
|
||||
const hasValidState = states.some(
|
||||
(stateObj) => stateObj.state !== UNAVAILABLE && stateObj.state !== UNKNOWN
|
||||
);
|
||||
if (!hasValidState) {
|
||||
return UNKNOWN;
|
||||
if (!validState) {
|
||||
return UNAVAILABLE;
|
||||
}
|
||||
|
||||
// Use the first state to determine the domain
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import type { HassEntity } from "home-assistant-js-websocket";
|
||||
import { OFF, UNAVAILABLE, UNKNOWN } from "../../data/entity/entity";
|
||||
import { isUnavailableState, OFF, UNAVAILABLE } from "../../data/entity/entity";
|
||||
import { computeDomain } from "./compute_domain";
|
||||
|
||||
export function stateActive(stateObj: HassEntity, state?: string): boolean {
|
||||
@@ -19,7 +19,7 @@ export function stateActive(stateObj: HassEntity, state?: string): boolean {
|
||||
return compareState !== UNAVAILABLE;
|
||||
}
|
||||
|
||||
if (compareState === UNAVAILABLE || compareState === UNKNOWN) {
|
||||
if (isUnavailableState(compareState)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -116,7 +116,7 @@ export class HaProgressButton extends LitElement {
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
:host([appearance="brand"]) ha-svg-icon {
|
||||
ha-svg-icon {
|
||||
color: var(--white-color);
|
||||
}
|
||||
`;
|
||||
|
||||
@@ -6,7 +6,11 @@ import { customElement, property, state } from "lit/decorators";
|
||||
import { STATES_OFF } from "../../common/const";
|
||||
import { computeStateDomain } from "../../common/entity/compute_state_domain";
|
||||
import { computeStateName } from "../../common/entity/compute_state_name";
|
||||
import { UNAVAILABLE, UNKNOWN } from "../../data/entity/entity";
|
||||
import {
|
||||
UNAVAILABLE,
|
||||
UNKNOWN,
|
||||
isUnavailableState,
|
||||
} from "../../data/entity/entity";
|
||||
import { forwardHaptic } from "../../data/haptics";
|
||||
import type { HomeAssistant } from "../../types";
|
||||
import "../ha-formfield";
|
||||
@@ -16,8 +20,7 @@ import "../ha-switch";
|
||||
const isOn = (stateObj?: HassEntity) =>
|
||||
stateObj !== undefined &&
|
||||
!STATES_OFF.includes(stateObj.state) &&
|
||||
stateObj.state !== UNAVAILABLE &&
|
||||
stateObj.state !== UNKNOWN;
|
||||
!isUnavailableState(stateObj.state);
|
||||
|
||||
/**
|
||||
* @element ha-entity-toggle
|
||||
|
||||
@@ -9,7 +9,7 @@ import secondsToDuration from "../../common/datetime/seconds_to_duration";
|
||||
import { computeStateDomain } from "../../common/entity/compute_state_domain";
|
||||
import { computeStateName } from "../../common/entity/compute_state_name";
|
||||
import { FIXED_DOMAIN_STATES } from "../../common/entity/get_states";
|
||||
import { UNAVAILABLE, UNKNOWN } from "../../data/entity/entity";
|
||||
import { isUnavailableState, UNAVAILABLE } from "../../data/entity/entity";
|
||||
import type { EntityRegistryDisplayEntry } from "../../data/entity/entity_registry";
|
||||
import { timerTimeRemaining } from "../../data/timer";
|
||||
import type { HomeAssistant } from "../../types";
|
||||
@@ -170,8 +170,7 @@ export class HaStateLabelBadge extends LitElement {
|
||||
}
|
||||
// eslint-disable-next-line: disable=no-fallthrough
|
||||
default:
|
||||
return entityState.state === UNAVAILABLE ||
|
||||
entityState.state === UNKNOWN
|
||||
return isUnavailableState(entityState.state)
|
||||
? "—"
|
||||
: this.hass!.formatEntityStateToParts(entityState).find(
|
||||
(part) => part.type === "value"
|
||||
@@ -210,7 +209,7 @@ export class HaStateLabelBadge extends LitElement {
|
||||
_timerTimeRemaining = 0
|
||||
) {
|
||||
// For unavailable states or certain domains, use a special translation that is truncated to fit within the badge label
|
||||
if (entityState.state === UNAVAILABLE || entityState.state === UNKNOWN) {
|
||||
if (isUnavailableState(entityState.state)) {
|
||||
return this.hass!.localize(`state_badge.default.${entityState.state}`);
|
||||
}
|
||||
const domainStateKey = getTruncatedKey(domain, entityState.state);
|
||||
|
||||
@@ -29,7 +29,7 @@ export interface AreaControlPickerItem extends PickerComboBoxItem {
|
||||
deviceClass?: string;
|
||||
}
|
||||
|
||||
const AREA_CONTROL_DOMAINS = [
|
||||
const AREA_CONTROL_DOMAINS: readonly AreaControlDomain[] = [
|
||||
"light",
|
||||
"fan",
|
||||
"switch",
|
||||
@@ -43,7 +43,7 @@ const AREA_CONTROL_DOMAINS = [
|
||||
"cover-door",
|
||||
"cover-window",
|
||||
"cover-damper",
|
||||
] as const satisfies readonly AreaControlDomain[];
|
||||
] as const;
|
||||
|
||||
@customElement("ha-area-controls-picker")
|
||||
export class HaAreaControlsPicker extends LitElement {
|
||||
@@ -130,7 +130,7 @@ export class HaAreaControlsPicker extends LitElement {
|
||||
(excludeValues !== undefined && excludeValues.includes(id));
|
||||
|
||||
const controlEntities = getAreaControlEntities(
|
||||
AREA_CONTROL_DOMAINS,
|
||||
AREA_CONTROL_DOMAINS as unknown as AreaControlDomain[],
|
||||
areaId,
|
||||
excludeEntities,
|
||||
this.hass
|
||||
|
||||
@@ -3,7 +3,7 @@ import { css, html, LitElement, nothing } from "lit";
|
||||
import { customElement, property } from "lit/decorators";
|
||||
import type { ClimateEntity } from "../data/climate";
|
||||
import { CLIMATE_PRESET_NONE } from "../data/climate";
|
||||
import { OFF, UNAVAILABLE, UNKNOWN } from "../data/entity/entity";
|
||||
import { isUnavailableState, OFF } from "../data/entity/entity";
|
||||
import type { HomeAssistant } from "../types";
|
||||
|
||||
@customElement("ha-climate-state")
|
||||
@@ -14,11 +14,9 @@ class HaClimateState extends LitElement {
|
||||
|
||||
protected render(): TemplateResult {
|
||||
const currentStatus = this._computeCurrentStatus();
|
||||
const noValue =
|
||||
this.stateObj.state === UNAVAILABLE || this.stateObj.state === UNKNOWN;
|
||||
|
||||
return html`<div class="target">
|
||||
${!noValue
|
||||
${!isUnavailableState(this.stateObj.state)
|
||||
? html`<span class="state-label">
|
||||
${this._localizeState()}
|
||||
${this.stateObj.attributes.preset_mode &&
|
||||
@@ -34,7 +32,7 @@ class HaClimateState extends LitElement {
|
||||
: this._localizeState()}
|
||||
</div>
|
||||
|
||||
${currentStatus && !noValue
|
||||
${currentStatus && !isUnavailableState(this.stateObj.state)
|
||||
? html`
|
||||
<div class="current">
|
||||
${this.hass.localize("ui.card.climate.currently")}:
|
||||
@@ -121,10 +119,7 @@ class HaClimateState extends LitElement {
|
||||
}
|
||||
|
||||
private _localizeState(): string {
|
||||
if (
|
||||
this.stateObj.state === UNAVAILABLE ||
|
||||
this.stateObj.state === UNKNOWN
|
||||
) {
|
||||
if (isUnavailableState(this.stateObj.state)) {
|
||||
return this.hass.localize(`state.default.${this.stateObj.state}`);
|
||||
}
|
||||
|
||||
|
||||
@@ -6,18 +6,11 @@ import type { HaIconButton } from "./ha-icon-button";
|
||||
|
||||
/**
|
||||
* Event type for the ha-dropdown component when an item is selected.
|
||||
* @param TValue - The type of the selected item's `value`.
|
||||
* @param TData - The type of the selected item's `data` when set on `ha-dropdown-item`.
|
||||
* @param T - The type of the value of the selected item.
|
||||
*/
|
||||
export type HaDropdownSelectEvent<TValue = string, TData = undefined> = [
|
||||
TData,
|
||||
] extends [undefined]
|
||||
? CustomEvent<{
|
||||
item: Omit<HaDropdownItem, "value"> & { value: TValue };
|
||||
}>
|
||||
: CustomEvent<{
|
||||
item: Omit<HaDropdownItem, "value"> & { value: TValue; data: TData };
|
||||
}>;
|
||||
export type HaDropdownSelectEvent<T = string> = CustomEvent<{
|
||||
item: Omit<HaDropdownItem, "value"> & { value: T };
|
||||
}>;
|
||||
|
||||
/**
|
||||
* Home Assistant dropdown component
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import type { TemplateResult } from "lit";
|
||||
import { css, html, LitElement } from "lit";
|
||||
import { customElement, property } from "lit/decorators";
|
||||
import { OFF, UNAVAILABLE, UNKNOWN } from "../data/entity/entity";
|
||||
import { isUnavailableState, OFF } from "../data/entity/entity";
|
||||
import type { HumidifierEntity } from "../data/humidifier";
|
||||
import type { HomeAssistant } from "../types";
|
||||
|
||||
@@ -13,11 +13,9 @@ class HaHumidifierState extends LitElement {
|
||||
|
||||
protected render(): TemplateResult {
|
||||
const currentStatus = this._computeCurrentStatus();
|
||||
const noValue =
|
||||
this.stateObj.state === UNAVAILABLE || this.stateObj.state === UNKNOWN;
|
||||
|
||||
return html`<div class="target">
|
||||
${!noValue
|
||||
${!isUnavailableState(this.stateObj.state)
|
||||
? html`<span class="state-label">
|
||||
${this._localizeState()}
|
||||
${this.stateObj.attributes.mode
|
||||
@@ -32,7 +30,7 @@ class HaHumidifierState extends LitElement {
|
||||
: this._localizeState()}
|
||||
</div>
|
||||
|
||||
${currentStatus && !noValue
|
||||
${currentStatus && !isUnavailableState(this.stateObj.state)
|
||||
? html`<div class="current">
|
||||
${this.hass.localize("ui.card.humidifier.currently")}:
|
||||
<div class="unit">${currentStatus}</div>
|
||||
@@ -71,10 +69,7 @@ class HaHumidifierState extends LitElement {
|
||||
}
|
||||
|
||||
private _localizeState(): string {
|
||||
if (
|
||||
this.stateObj.state === UNAVAILABLE ||
|
||||
this.stateObj.state === UNKNOWN
|
||||
) {
|
||||
if (isUnavailableState(this.stateObj.state)) {
|
||||
return this.hass.localize(`state.default.${this.stateObj.state}`);
|
||||
}
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@ import { html, LitElement } from "lit";
|
||||
import { customElement, property } from "lit/decorators";
|
||||
import { styleMap } from "lit/directives/style-map";
|
||||
import memoizeOne from "memoize-one";
|
||||
import { fireEvent, type HASSDomEvent } from "../../common/dom/fire_event";
|
||||
import { fireEvent } from "../../common/dom/fire_event";
|
||||
import type { ColorTempSelector } from "../../data/selector";
|
||||
import type { HomeAssistant } from "../../types";
|
||||
import "../ha-labeled-slider";
|
||||
@@ -94,10 +94,10 @@ export class HaColorTempSelector extends LitElement {
|
||||
}
|
||||
);
|
||||
|
||||
private _valueChanged(ev: HASSDomEvent<HASSDomEvents["value-changed"]>) {
|
||||
private _valueChanged(ev: CustomEvent) {
|
||||
ev.stopPropagation();
|
||||
fireEvent(this, "value-changed", {
|
||||
value: Number(ev.detail.value),
|
||||
value: Number((ev.detail as any).value),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,7 +17,7 @@ import { until } from "lit/directives/until";
|
||||
import { fireEvent } from "../../common/dom/fire_event";
|
||||
import { slugify } from "../../common/string/slugify";
|
||||
import { debounce } from "../../common/util/debounce";
|
||||
import { UNAVAILABLE } from "../../data/entity/entity";
|
||||
import { isUnavailableState } from "../../data/entity/entity";
|
||||
import type {
|
||||
MediaPickedEvent,
|
||||
MediaPlayerBrowseAction,
|
||||
@@ -290,7 +290,7 @@ export class HaMediaPlayerBrowse extends LitElement {
|
||||
} else if (
|
||||
err.code === "entity_not_found" &&
|
||||
this.entityId &&
|
||||
this.hass.states[this.entityId]?.state === UNAVAILABLE
|
||||
isUnavailableState(this.hass.states[this.entityId]?.state)
|
||||
) {
|
||||
this._setError({
|
||||
message: this.hass.localize(
|
||||
|
||||
@@ -62,7 +62,7 @@ export const AREA_CONTROLS_BUTTONS: Record<
|
||||
};
|
||||
|
||||
export const getAreaControlEntities = (
|
||||
controls: readonly AreaControlDomain[],
|
||||
controls: AreaControlDomain[],
|
||||
areaId: string,
|
||||
excludeEntities: string[] | undefined,
|
||||
hass: HomeAssistant
|
||||
|
||||
@@ -6,7 +6,7 @@ import { getColorByIndex } from "../common/color/colors";
|
||||
import { computeDomain } from "../common/entity/compute_domain";
|
||||
import { computeStateName } from "../common/entity/compute_state_name";
|
||||
import type { HomeAssistant } from "../types";
|
||||
import { UNAVAILABLE } from "./entity/entity";
|
||||
import { isUnavailableState } from "./entity/entity";
|
||||
import type { EntityRegistryEntry } from "./entity/entity_registry";
|
||||
|
||||
export interface Calendar {
|
||||
@@ -120,7 +120,7 @@ export const getCalendars = (
|
||||
.filter(
|
||||
(eid) =>
|
||||
computeDomain(eid) === "calendar" &&
|
||||
hass.states[eid].state !== UNAVAILABLE &&
|
||||
!isUnavailableState(hass.states[eid].state) &&
|
||||
hass.entities[eid]?.hidden !== true
|
||||
)
|
||||
.sort()
|
||||
|
||||
@@ -6,8 +6,10 @@ export const UNKNOWN = "unknown";
|
||||
export const ON = "on";
|
||||
export const OFF = "off";
|
||||
|
||||
export const UNAVAILABLE_STATES = [UNAVAILABLE, UNKNOWN] as const;
|
||||
export const OFF_STATES = [UNAVAILABLE, UNKNOWN, OFF] as const;
|
||||
|
||||
export const isUnavailableState = arrayLiteralIncludes(UNAVAILABLE_STATES);
|
||||
export const isOffState = arrayLiteralIncludes(OFF_STATES);
|
||||
|
||||
export type HaEntityPickerEntityFilterFunc = (entityId: HassEntity) => boolean;
|
||||
|
||||
+199
-97
@@ -1,15 +1,11 @@
|
||||
import { atLeastVersion } from "../../common/config/version";
|
||||
import type { HaFormSchema } from "../../components/ha-form/types";
|
||||
import type {
|
||||
CallWS,
|
||||
HomeAssistant,
|
||||
HomeAssistantApi,
|
||||
TranslationDict,
|
||||
} from "../../types";
|
||||
import type { HomeAssistant, TranslationDict } from "../../types";
|
||||
import { supervisorApiCall } from "../supervisor/common";
|
||||
import type { StoreAddonDetails } from "../supervisor/store";
|
||||
import type { Supervisor, SupervisorArch } from "../supervisor/supervisor";
|
||||
import type { HassioResponse } from "./common";
|
||||
import { extractApiErrorMessage } from "./common";
|
||||
import { extractApiErrorMessage, hassioApiResultExtractor } from "./common";
|
||||
|
||||
export type AddonCapability = Exclude<
|
||||
keyof TranslationDict["ui"]["panel"]["config"]["apps"]["dashboard"]["capability"],
|
||||
@@ -147,38 +143,57 @@ export interface HassioAddonSetOptionParams {
|
||||
}
|
||||
|
||||
export const reloadHassioAddons = async (hass: HomeAssistant) => {
|
||||
await hass.callWS({
|
||||
type: "supervisor/api",
|
||||
endpoint: "/addons/reload",
|
||||
method: "post",
|
||||
});
|
||||
if (atLeastVersion(hass.config.version, 2021, 2, 4)) {
|
||||
await hass.callWS({
|
||||
type: "supervisor/api",
|
||||
endpoint: "/addons/reload",
|
||||
method: "post",
|
||||
});
|
||||
return;
|
||||
}
|
||||
await hass.callApi<HassioResponse<void>>("POST", `hassio/addons/reload`);
|
||||
};
|
||||
|
||||
export const fetchHassioAddonsInfo = async (
|
||||
hass: HomeAssistant
|
||||
): Promise<HassioAddonsInfo> => {
|
||||
return hass.callWS({
|
||||
type: "supervisor/api",
|
||||
endpoint: "/addons",
|
||||
method: "get",
|
||||
});
|
||||
if (atLeastVersion(hass.config.version, 2021, 2, 4)) {
|
||||
return hass.callWS({
|
||||
type: "supervisor/api",
|
||||
endpoint: "/addons",
|
||||
method: "get",
|
||||
});
|
||||
}
|
||||
|
||||
return hassioApiResultExtractor(
|
||||
await hass.callApi<HassioResponse<HassioAddonsInfo>>("GET", `hassio/addons`)
|
||||
);
|
||||
};
|
||||
|
||||
export const fetchHassioAddonInfo = async (
|
||||
callWS: CallWS,
|
||||
hass: HomeAssistant,
|
||||
slug: string
|
||||
): Promise<HassioAddonDetails> => {
|
||||
return callWS({
|
||||
type: "supervisor/api",
|
||||
endpoint: `/addons/${slug}/info`,
|
||||
method: "get",
|
||||
});
|
||||
if (atLeastVersion(hass.config.version, 2021, 2, 4)) {
|
||||
return hass.callWS({
|
||||
type: "supervisor/api",
|
||||
endpoint: `/addons/${slug}/info`,
|
||||
method: "get",
|
||||
});
|
||||
}
|
||||
|
||||
return hassioApiResultExtractor(
|
||||
await hass.callApi<HassioResponse<HassioAddonDetails>>(
|
||||
"GET",
|
||||
`hassio/addons/${slug}/info`
|
||||
)
|
||||
);
|
||||
};
|
||||
|
||||
export const fetchHassioAddonChangelog = async (
|
||||
api: HomeAssistantApi,
|
||||
hass: HomeAssistant,
|
||||
slug: string
|
||||
) => api.callApi<string>("GET", `hassio/addons/${slug}/changelog`);
|
||||
) => hass.callApi<string>("GET", `hassio/addons/${slug}/changelog`);
|
||||
|
||||
export const fetchHassioAddonLogs = async (hass: HomeAssistant, slug: string) =>
|
||||
hass.callApi<string>("GET", `hassio/addons/${slug}/logs`);
|
||||
@@ -189,77 +204,119 @@ export const fetchHassioAddonDocumentation = async (
|
||||
) => hass.callApi<string>("GET", `hassio/addons/${slug}/documentation`);
|
||||
|
||||
export const setHassioAddonOption = async (
|
||||
callWS: CallWS,
|
||||
hass: HomeAssistant,
|
||||
slug: string,
|
||||
data: HassioAddonSetOptionParams
|
||||
) => {
|
||||
const response = await callWS<HassioResponse<any>>({
|
||||
type: "supervisor/api",
|
||||
endpoint: `/addons/${slug}/options`,
|
||||
method: "post",
|
||||
data,
|
||||
});
|
||||
if (atLeastVersion(hass.config.version, 2021, 2, 4)) {
|
||||
const response = await hass.callWS<HassioResponse<any>>({
|
||||
type: "supervisor/api",
|
||||
endpoint: `/addons/${slug}/options`,
|
||||
method: "post",
|
||||
data,
|
||||
});
|
||||
|
||||
if (response.result === "error") {
|
||||
throw Error(extractApiErrorMessage(response));
|
||||
if (response.result === "error") {
|
||||
throw Error(extractApiErrorMessage(response));
|
||||
}
|
||||
return response;
|
||||
}
|
||||
return response;
|
||||
|
||||
return hass.callApi<HassioResponse<any>>(
|
||||
"POST",
|
||||
`hassio/addons/${slug}/options`,
|
||||
data
|
||||
);
|
||||
};
|
||||
|
||||
export const validateHassioAddonOption = async (
|
||||
callWS: CallWS,
|
||||
hass: HomeAssistant,
|
||||
slug: string,
|
||||
data?: any
|
||||
): Promise<{ message: string; valid: boolean }> => {
|
||||
return callWS({
|
||||
type: "supervisor/api",
|
||||
endpoint: `/addons/${slug}/options/validate`,
|
||||
method: "post",
|
||||
data,
|
||||
});
|
||||
if (atLeastVersion(hass.config.version, 2021, 2, 4)) {
|
||||
return hass.callWS({
|
||||
type: "supervisor/api",
|
||||
endpoint: `/addons/${slug}/options/validate`,
|
||||
method: "post",
|
||||
data,
|
||||
});
|
||||
}
|
||||
|
||||
return (
|
||||
await hass.callApi<HassioResponse<{ message: string; valid: boolean }>>(
|
||||
"POST",
|
||||
`hassio/addons/${slug}/options/validate`
|
||||
)
|
||||
).data;
|
||||
};
|
||||
|
||||
export const startHassioAddon = async (callWS: CallWS, slug: string) => {
|
||||
return callWS({
|
||||
type: "supervisor/api",
|
||||
endpoint: `/addons/${slug}/start`,
|
||||
method: "post",
|
||||
timeout: null,
|
||||
});
|
||||
export const startHassioAddon = async (hass: HomeAssistant, slug: string) => {
|
||||
if (atLeastVersion(hass.config.version, 2021, 2, 4)) {
|
||||
return hass.callWS({
|
||||
type: "supervisor/api",
|
||||
endpoint: `/addons/${slug}/start`,
|
||||
method: "post",
|
||||
timeout: null,
|
||||
});
|
||||
}
|
||||
|
||||
return hass.callApi<string>("POST", `hassio/addons/${slug}/start`);
|
||||
};
|
||||
|
||||
export const stopHassioAddon = async (callWS: CallWS, slug: string) => {
|
||||
return callWS({
|
||||
type: "supervisor/api",
|
||||
endpoint: `/addons/${slug}/stop`,
|
||||
method: "post",
|
||||
timeout: null,
|
||||
});
|
||||
export const stopHassioAddon = async (hass: HomeAssistant, slug: string) => {
|
||||
if (atLeastVersion(hass.config.version, 2021, 2, 4)) {
|
||||
return hass.callWS({
|
||||
type: "supervisor/api",
|
||||
endpoint: `/addons/${slug}/stop`,
|
||||
method: "post",
|
||||
timeout: null,
|
||||
});
|
||||
}
|
||||
|
||||
return hass.callApi<string>("POST", `hassio/addons/${slug}/stop`);
|
||||
};
|
||||
|
||||
export const setHassioAddonSecurity = async (
|
||||
callWS: CallWS,
|
||||
hass: HomeAssistant,
|
||||
slug: string,
|
||||
data: HassioAddonSetSecurityParams
|
||||
) => {
|
||||
await callWS({
|
||||
type: "supervisor/api",
|
||||
endpoint: `/addons/${slug}/security`,
|
||||
method: "post",
|
||||
data,
|
||||
});
|
||||
if (atLeastVersion(hass.config.version, 2021, 2, 4)) {
|
||||
await hass.callWS({
|
||||
type: "supervisor/api",
|
||||
endpoint: `/addons/${slug}/security`,
|
||||
method: "post",
|
||||
data,
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
await hass.callApi<HassioResponse<void>>(
|
||||
"POST",
|
||||
`hassio/addons/${slug}/security`,
|
||||
data
|
||||
);
|
||||
};
|
||||
|
||||
export const installHassioAddon = async (
|
||||
callWS: CallWS,
|
||||
hass: HomeAssistant,
|
||||
slug: string
|
||||
): Promise<void> => {
|
||||
await callWS({
|
||||
type: "supervisor/api",
|
||||
endpoint: `/addons/${slug}/install`,
|
||||
method: "post",
|
||||
timeout: null,
|
||||
});
|
||||
if (atLeastVersion(hass.config.version, 2021, 2, 4)) {
|
||||
await hass.callWS({
|
||||
type: "supervisor/api",
|
||||
endpoint: `/addons/${slug}/install`,
|
||||
method: "post",
|
||||
timeout: null,
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
await hass.callApi<HassioResponse<void>>(
|
||||
"POST",
|
||||
`hassio/addons/${slug}/install`
|
||||
);
|
||||
};
|
||||
|
||||
export const updateHassioAddon = async (
|
||||
@@ -267,37 +324,74 @@ export const updateHassioAddon = async (
|
||||
slug: string,
|
||||
backup: boolean
|
||||
): Promise<void> => {
|
||||
await hass.callWS({
|
||||
type: "hassio/update/addon",
|
||||
addon: slug,
|
||||
backup: backup,
|
||||
});
|
||||
if (atLeastVersion(hass.config.version, 2025, 2, 0)) {
|
||||
await hass.callWS({
|
||||
type: "hassio/update/addon",
|
||||
addon: slug,
|
||||
backup: backup,
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
if (atLeastVersion(hass.config.version, 2021, 2, 4)) {
|
||||
await hass.callWS({
|
||||
type: "supervisor/api",
|
||||
endpoint: `/store/addons/${slug}/update`,
|
||||
method: "post",
|
||||
timeout: null,
|
||||
data: { backup },
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
await hass.callApi<HassioResponse<void>>(
|
||||
"POST",
|
||||
`hassio/addons/${slug}/update`,
|
||||
{ backup }
|
||||
);
|
||||
};
|
||||
|
||||
export const restartHassioAddon = async (
|
||||
callWS: CallWS,
|
||||
hass: HomeAssistant,
|
||||
slug: string
|
||||
): Promise<void> => {
|
||||
await callWS({
|
||||
type: "supervisor/api",
|
||||
endpoint: `/addons/${slug}/restart`,
|
||||
method: "post",
|
||||
timeout: null,
|
||||
});
|
||||
if (atLeastVersion(hass.config.version, 2021, 2, 4)) {
|
||||
await hass.callWS({
|
||||
type: "supervisor/api",
|
||||
endpoint: `/addons/${slug}/restart`,
|
||||
method: "post",
|
||||
timeout: null,
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
await hass.callApi<HassioResponse<void>>(
|
||||
"POST",
|
||||
`hassio/addons/${slug}/restart`
|
||||
);
|
||||
};
|
||||
|
||||
export const uninstallHassioAddon = async (
|
||||
callWS: CallWS,
|
||||
hass: HomeAssistant,
|
||||
slug: string,
|
||||
removeData: boolean
|
||||
): Promise<void> => {
|
||||
await callWS({
|
||||
type: "supervisor/api",
|
||||
endpoint: `/addons/${slug}/uninstall`,
|
||||
method: "post",
|
||||
timeout: null,
|
||||
data: { remove_config: removeData },
|
||||
});
|
||||
if (atLeastVersion(hass.config.version, 2021, 2, 4)) {
|
||||
await hass.callWS({
|
||||
type: "supervisor/api",
|
||||
endpoint: `/addons/${slug}/uninstall`,
|
||||
method: "post",
|
||||
timeout: null,
|
||||
data: { remove_config: removeData },
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
await hass.callApi<HassioResponse<void>>(
|
||||
"POST",
|
||||
`hassio/addons/${slug}/uninstall`,
|
||||
{ remove_config: removeData }
|
||||
);
|
||||
};
|
||||
|
||||
export const fetchAddonInfo = (
|
||||
@@ -313,13 +407,21 @@ export const fetchAddonInfo = (
|
||||
);
|
||||
|
||||
export const rebuildLocalAddon = async (
|
||||
callWS: CallWS,
|
||||
hass: HomeAssistant,
|
||||
slug: string
|
||||
): Promise<void> => {
|
||||
return callWS<undefined>({
|
||||
type: "supervisor/api",
|
||||
endpoint: `/addons/${slug}/rebuild`,
|
||||
method: "post",
|
||||
timeout: null,
|
||||
});
|
||||
if (atLeastVersion(hass.config.version, 2021, 2, 4)) {
|
||||
return hass.callWS<undefined>({
|
||||
type: "supervisor/api",
|
||||
endpoint: `/addons/${slug}/rebuild`,
|
||||
method: "post",
|
||||
timeout: null,
|
||||
});
|
||||
}
|
||||
return (
|
||||
await hass.callApi<HassioResponse<void>>(
|
||||
"POST",
|
||||
`hassio/addons/${slug}rebuild`
|
||||
)
|
||||
).data;
|
||||
};
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import type { CallWS } from "../../types";
|
||||
import { atLeastVersion } from "../../common/config/version";
|
||||
import type { HomeAssistant } from "../../types";
|
||||
|
||||
export interface HassioResponse<T> {
|
||||
data: T;
|
||||
@@ -45,12 +46,21 @@ export const ignoreSupervisorError = (error): boolean => {
|
||||
};
|
||||
|
||||
export const fetchHassioStats = async (
|
||||
callWS: CallWS,
|
||||
hass: HomeAssistant,
|
||||
container: string
|
||||
): Promise<HassioStats> => {
|
||||
return callWS({
|
||||
type: "supervisor/api",
|
||||
endpoint: `/${container}/stats`,
|
||||
method: "get",
|
||||
});
|
||||
if (atLeastVersion(hass.config.version, 2021, 2, 4)) {
|
||||
return hass.callWS({
|
||||
type: "supervisor/api",
|
||||
endpoint: `/${container}/stats`,
|
||||
method: "get",
|
||||
});
|
||||
}
|
||||
|
||||
return hassioApiResultExtractor(
|
||||
await hass.callApi<HassioResponse<HassioStats>>(
|
||||
"GET",
|
||||
`hassio/${container}/stats`
|
||||
)
|
||||
);
|
||||
};
|
||||
|
||||
+2
-2
@@ -2,7 +2,7 @@ import { computeDomain } from "../common/entity/compute_domain";
|
||||
import { computeStateName } from "../common/entity/compute_state_name";
|
||||
import { stringCompare } from "../common/string/compare";
|
||||
import type { HomeAssistant, ServiceCallResponse } from "../types";
|
||||
import { UNAVAILABLE } from "./entity/entity";
|
||||
import { isUnavailableState } from "./entity/entity";
|
||||
|
||||
export interface TodoList {
|
||||
entity_id: string;
|
||||
@@ -49,7 +49,7 @@ export const getTodoLists = (
|
||||
.filter(
|
||||
(entityId) =>
|
||||
computeDomain(entityId) === "todo" &&
|
||||
hass.states[entityId].state !== UNAVAILABLE &&
|
||||
!isUnavailableState(hass.states[entityId].state) &&
|
||||
(includeHidden || hass.entities[entityId]?.hidden !== true)
|
||||
)
|
||||
.map((entityId) => ({
|
||||
|
||||
@@ -18,7 +18,7 @@ import "../../../components/ha-slider";
|
||||
import "../../../components/ha-time-input";
|
||||
import "../../../components/input/ha-input";
|
||||
import { isTiltOnly } from "../../../data/cover";
|
||||
import { UNAVAILABLE, UNKNOWN } from "../../../data/entity/entity";
|
||||
import { isUnavailableState, UNAVAILABLE } from "../../../data/entity/entity";
|
||||
import type { ImageEntity } from "../../../data/image";
|
||||
import { computeImageUrl } from "../../../data/image";
|
||||
import "../../../panels/lovelace/components/hui-timestamp-display";
|
||||
@@ -108,13 +108,14 @@ class EntityPreviewRow extends LitElement {
|
||||
|
||||
private _renderEntityState(stateObj: HassEntity): TemplateResult | string {
|
||||
const domain = stateObj.entity_id.split(".", 1)[0];
|
||||
const disabled = stateObj.state === UNAVAILABLE;
|
||||
const noValue =
|
||||
stateObj.state === UNAVAILABLE || stateObj.state === UNKNOWN;
|
||||
|
||||
if (domain === "button") {
|
||||
return html`
|
||||
<ha-button appearance="plain" size="small" .disabled=${disabled}>
|
||||
<ha-button
|
||||
appearance="plain"
|
||||
size="small"
|
||||
.disabled=${isUnavailableState(stateObj.state)}
|
||||
>
|
||||
${this.hass.localize("ui.card.button.press")}
|
||||
</ha-button>
|
||||
`;
|
||||
@@ -150,15 +151,19 @@ class EntityPreviewRow extends LitElement {
|
||||
return html`
|
||||
<ha-date-input
|
||||
.locale=${this.hass.locale}
|
||||
.disabled=${disabled}
|
||||
.value=${noValue ? undefined : stateObj.state}
|
||||
.disabled=${isUnavailableState(stateObj.state)}
|
||||
.value=${isUnavailableState(stateObj.state)
|
||||
? undefined
|
||||
: stateObj.state}
|
||||
>
|
||||
</ha-date-input>
|
||||
`;
|
||||
}
|
||||
|
||||
if (domain === "datetime") {
|
||||
const dateObj = noValue ? undefined : new Date(stateObj.state);
|
||||
const dateObj = isUnavailableState(stateObj.state)
|
||||
? undefined
|
||||
: new Date(stateObj.state);
|
||||
const time = dateObj ? format(dateObj, "HH:mm:ss") : undefined;
|
||||
const date = dateObj ? format(dateObj, "yyyy-MM-dd") : undefined;
|
||||
return html`
|
||||
@@ -167,12 +172,12 @@ class EntityPreviewRow extends LitElement {
|
||||
.label=${computeStateName(stateObj)}
|
||||
.locale=${this.hass.locale}
|
||||
.value=${date}
|
||||
.disabled=${disabled}
|
||||
.disabled=${isUnavailableState(stateObj.state)}
|
||||
>
|
||||
</ha-date-input>
|
||||
<ha-time-input
|
||||
.value=${time}
|
||||
.disabled=${disabled}
|
||||
.disabled=${isUnavailableState(stateObj.state)}
|
||||
.locale=${this.hass.locale}
|
||||
></ha-time-input>
|
||||
</div>
|
||||
@@ -182,7 +187,7 @@ class EntityPreviewRow extends LitElement {
|
||||
if (domain === "event") {
|
||||
return html`
|
||||
<div class="when">
|
||||
${noValue
|
||||
${isUnavailableState(stateObj.state)
|
||||
? this.hass.formatEntityState(stateObj)
|
||||
: html`<hui-timestamp-display
|
||||
.hass=${this.hass}
|
||||
@@ -191,7 +196,7 @@ class EntityPreviewRow extends LitElement {
|
||||
></hui-timestamp-display>`}
|
||||
</div>
|
||||
<div class="what">
|
||||
${noValue
|
||||
${isUnavailableState(stateObj.state)
|
||||
? nothing
|
||||
: this.hass.formatEntityAttributeValue(stateObj, "event_type")}
|
||||
</div>
|
||||
@@ -201,7 +206,9 @@ class EntityPreviewRow extends LitElement {
|
||||
const toggleDomains = ["fan", "light", "remote", "siren", "switch"];
|
||||
if (toggleDomains.includes(domain)) {
|
||||
const showToggle =
|
||||
stateObj.state === "on" || stateObj.state === "off" || noValue;
|
||||
stateObj.state === "on" ||
|
||||
stateObj.state === "off" ||
|
||||
isUnavailableState(stateObj.state);
|
||||
return html`
|
||||
${showToggle
|
||||
? html`
|
||||
@@ -234,7 +241,7 @@ class EntityPreviewRow extends LitElement {
|
||||
if (domain === "lock") {
|
||||
return html`
|
||||
<ha-button
|
||||
.disabled=${disabled}
|
||||
.disabled=${isUnavailableState(stateObj.state)}
|
||||
class="text-content"
|
||||
appearance="plain"
|
||||
size="small"
|
||||
@@ -259,7 +266,7 @@ class EntityPreviewRow extends LitElement {
|
||||
<div class="numberflex">
|
||||
<ha-slider
|
||||
labeled
|
||||
.disabled=${disabled}
|
||||
.disabled=${stateObj.state === UNAVAILABLE}
|
||||
.step=${Number(stateObj.attributes.step)}
|
||||
.min=${Number(stateObj.attributes.min)}
|
||||
.max=${Number(stateObj.attributes.max)}
|
||||
@@ -273,7 +280,7 @@ class EntityPreviewRow extends LitElement {
|
||||
: html`<div class="numberflex numberstate">
|
||||
<ha-input
|
||||
auto-validate
|
||||
.disabled=${disabled}
|
||||
.disabled=${stateObj.state === UNAVAILABLE}
|
||||
pattern="[0-9]+([\\.][0-9]+)?"
|
||||
.step=${Number(stateObj.attributes.step)}
|
||||
.min=${Number(stateObj.attributes.min)}
|
||||
@@ -296,7 +303,7 @@ class EntityPreviewRow extends LitElement {
|
||||
<ha-select
|
||||
.label=${computeStateName(stateObj)}
|
||||
.value=${stateObj.state}
|
||||
.disabled=${disabled}
|
||||
.disabled=${stateObj.state === UNAVAILABLE}
|
||||
.options=${stateObj.attributes.options?.map((option) => ({
|
||||
value: option,
|
||||
label: this.hass!.formatEntityState(stateObj, option),
|
||||
@@ -310,7 +317,7 @@ class EntityPreviewRow extends LitElement {
|
||||
const showSensor =
|
||||
SENSOR_TIMESTAMP_DEVICE_CLASSES.includes(
|
||||
stateObj.attributes.device_class
|
||||
) && !noValue;
|
||||
) && !isUnavailableState(stateObj.state);
|
||||
return html`
|
||||
${showSensor
|
||||
? html`
|
||||
@@ -332,7 +339,7 @@ class EntityPreviewRow extends LitElement {
|
||||
return html`
|
||||
<ha-input
|
||||
.label=${computeStateName(stateObj)}
|
||||
.disabled=${disabled}
|
||||
.disabled=${isUnavailableState(stateObj.state)}
|
||||
.value=${stateObj.state}
|
||||
.minlength=${stateObj.attributes.min}
|
||||
.maxlength=${stateObj.attributes.max}
|
||||
@@ -347,9 +354,11 @@ class EntityPreviewRow extends LitElement {
|
||||
if (domain === "time") {
|
||||
return html`
|
||||
<ha-time-input
|
||||
.value=${noValue ? undefined : stateObj.state}
|
||||
.value=${isUnavailableState(stateObj.state)
|
||||
? undefined
|
||||
: stateObj.state}
|
||||
.locale=${this.hass.locale}
|
||||
.disabled=${disabled}
|
||||
.disabled=${isUnavailableState(stateObj.state)}
|
||||
></ha-time-input>
|
||||
`;
|
||||
}
|
||||
@@ -357,7 +366,7 @@ class EntityPreviewRow extends LitElement {
|
||||
if (domain === "weather") {
|
||||
return html`
|
||||
<div>
|
||||
${noValue ||
|
||||
${isUnavailableState(stateObj.state) ||
|
||||
stateObj.attributes.temperature === undefined ||
|
||||
stateObj.attributes.temperature === null
|
||||
? this.hass.formatEntityState(stateObj)
|
||||
|
||||
@@ -1,116 +0,0 @@
|
||||
import { navigate } from "../../common/navigate";
|
||||
import type { LocalizeFunc } from "../../common/translations/localize";
|
||||
import { createSearchParam } from "../../common/url/search-params";
|
||||
import {
|
||||
ADD_AUTOMATION_ELEMENT_QUERY_PARAM,
|
||||
ADD_AUTOMATION_ELEMENT_TARGET_PARAM,
|
||||
} from "../../panels/config/automation/show-add-automation-element-dialog";
|
||||
import type { HomeAssistant, TranslationDict } from "../../types";
|
||||
|
||||
type DefaultActionKey =
|
||||
TranslationDict["ui"]["dialogs"]["more_info_control"]["add_to"]["actions"] extends infer Actions
|
||||
? keyof Actions
|
||||
: never;
|
||||
|
||||
interface BaseEntityAddToAction {
|
||||
/** Whether the action is enabled and can be selected. */
|
||||
enabled: boolean;
|
||||
/** Translated name of the action */
|
||||
name: string;
|
||||
/** Optional translated description of the action */
|
||||
description?: string;
|
||||
/** MDI icon name (e.g., "mdi:car") */
|
||||
icon: string;
|
||||
}
|
||||
|
||||
export interface DefaultEntityAddToAction extends BaseEntityAddToAction {
|
||||
/** Type of action handled in the frontend */
|
||||
type: "default";
|
||||
/** Stable key used to resolve the action handler */
|
||||
key: DefaultActionKey;
|
||||
}
|
||||
|
||||
export interface ExternalEntityAddToAction extends BaseEntityAddToAction {
|
||||
/** Type of action. External is handled by external apps instead of in the frontend */
|
||||
type: "external";
|
||||
/** Opaque payload for external action handling */
|
||||
payload?: string;
|
||||
}
|
||||
|
||||
export type EntityAddToAction =
|
||||
| DefaultEntityAddToAction
|
||||
| ExternalEntityAddToAction;
|
||||
|
||||
export type EntityAddToActions = EntityAddToAction[];
|
||||
|
||||
interface ActionDefinition {
|
||||
translation_key: DefaultActionKey;
|
||||
icon: string;
|
||||
}
|
||||
|
||||
export const DEFAULT_ACTION_DEFS: ActionDefinition[] = [
|
||||
{
|
||||
translation_key: "automation_trigger",
|
||||
icon: "mdi:robot-outline",
|
||||
},
|
||||
{
|
||||
translation_key: "automation_condition",
|
||||
icon: "mdi:playlist-check",
|
||||
},
|
||||
{
|
||||
translation_key: "automation_action",
|
||||
icon: "mdi:play-circle-outline",
|
||||
},
|
||||
{
|
||||
translation_key: "script_action",
|
||||
icon: "mdi:script-text-outline",
|
||||
},
|
||||
];
|
||||
|
||||
export const getDefaultAddToActions = (
|
||||
states: HomeAssistant["states"],
|
||||
localize: LocalizeFunc,
|
||||
formatEntityName: HomeAssistant["formatEntityName"],
|
||||
entityId: string
|
||||
): EntityAddToActions =>
|
||||
DEFAULT_ACTION_DEFS.map(
|
||||
(def: ActionDefinition): EntityAddToAction => ({
|
||||
type: "default",
|
||||
key: def.translation_key,
|
||||
enabled: true,
|
||||
name: localize(
|
||||
`ui.dialogs.more_info_control.add_to.actions.${def.translation_key}`,
|
||||
{
|
||||
entity:
|
||||
states[entityId] !== undefined
|
||||
? formatEntityName(states[entityId], undefined)
|
||||
: entityId,
|
||||
}
|
||||
),
|
||||
icon: def.icon,
|
||||
})
|
||||
);
|
||||
|
||||
export function defaultActionHandler(
|
||||
key: (typeof DEFAULT_ACTION_DEFS)[number]["translation_key"],
|
||||
entityId: string
|
||||
): Promise<boolean> {
|
||||
const params = (addElement: string) =>
|
||||
`?${createSearchParam({
|
||||
[ADD_AUTOMATION_ELEMENT_QUERY_PARAM]: addElement,
|
||||
[ADD_AUTOMATION_ELEMENT_TARGET_PARAM]: entityId,
|
||||
})}`;
|
||||
|
||||
switch (key) {
|
||||
case "automation_trigger":
|
||||
return navigate(`/config/automation/edit/new${params("trigger")}`);
|
||||
case "automation_condition":
|
||||
return navigate(`/config/automation/edit/new${params("condition")}`);
|
||||
case "automation_action":
|
||||
return navigate(`/config/automation/edit/new${params("action")}`);
|
||||
case "script_action":
|
||||
return navigate(`/config/script/edit/new${params("action")}`);
|
||||
default:
|
||||
return Promise.reject(new Error(`Unknown action key ${key}`));
|
||||
}
|
||||
}
|
||||
@@ -3,7 +3,7 @@ import { css, html, LitElement } from "lit";
|
||||
import { customElement, property, state } from "lit/decorators";
|
||||
import "../../../components/ha-absolute-time";
|
||||
import "../../../components/ha-relative-time";
|
||||
import { UNAVAILABLE, UNKNOWN } from "../../../data/entity/entity";
|
||||
import { isUnavailableState } from "../../../data/entity/entity";
|
||||
import type { LightEntity } from "../../../data/light";
|
||||
import { SENSOR_DEVICE_CLASS_TIMESTAMP } from "../../../data/sensor";
|
||||
import "../../../panels/lovelace/components/hui-timestamp-display";
|
||||
@@ -24,8 +24,7 @@ export class HaMoreInfoStateHeader extends LitElement {
|
||||
private _localizeState(): TemplateResult | string {
|
||||
if (
|
||||
this.stateObj.attributes.device_class === SENSOR_DEVICE_CLASS_TIMESTAMP &&
|
||||
this.stateObj.state !== UNAVAILABLE &&
|
||||
this.stateObj.state !== UNKNOWN
|
||||
!isUnavailableState(this.stateObj.state)
|
||||
) {
|
||||
return html`
|
||||
<hui-timestamp-display
|
||||
|
||||
@@ -4,7 +4,7 @@ import { customElement, property } from "lit/decorators";
|
||||
import "../../../components/ha-button";
|
||||
import "../../../components/ha-relative-time";
|
||||
import { triggerAutomationActions } from "../../../data/automation";
|
||||
import { UNAVAILABLE } from "../../../data/entity/entity";
|
||||
import { isUnavailableState } from "../../../data/entity/entity";
|
||||
import type { HomeAssistant } from "../../../types";
|
||||
|
||||
@customElement("more-info-automation")
|
||||
@@ -34,7 +34,7 @@ class MoreInfoAutomation extends LitElement {
|
||||
appearance="plain"
|
||||
size="small"
|
||||
@click=${this._runActions}
|
||||
.disabled=${this.stateObj!.state === UNAVAILABLE}
|
||||
.disabled=${isUnavailableState(this.stateObj!.state)}
|
||||
>
|
||||
${this.hass.localize("ui.card.automation.trigger")}
|
||||
</ha-button>
|
||||
|
||||
@@ -2,7 +2,7 @@ import type { HassEntity } from "home-assistant-js-websocket";
|
||||
import { css, html, LitElement, nothing } from "lit";
|
||||
import { customElement, property } from "lit/decorators";
|
||||
import "../../../components/ha-button";
|
||||
import { UNAVAILABLE } from "../../../data/entity/entity";
|
||||
import { isUnavailableState } from "../../../data/entity/entity";
|
||||
import type { HomeAssistant } from "../../../types";
|
||||
|
||||
@customElement("more-info-counter")
|
||||
@@ -16,7 +16,7 @@ class MoreInfoCounter extends LitElement {
|
||||
return nothing;
|
||||
}
|
||||
|
||||
const disabled = this.stateObj.state === UNAVAILABLE;
|
||||
const disabled = isUnavailableState(this.stateObj.state);
|
||||
|
||||
return html`
|
||||
<div class="actions">
|
||||
|
||||
@@ -4,7 +4,7 @@ import { customElement, property } from "lit/decorators";
|
||||
import "../../../components/ha-date-input";
|
||||
import "../../../components/ha-time-input";
|
||||
import { setDateValue } from "../../../data/date";
|
||||
import { UNAVAILABLE, UNKNOWN } from "../../../data/entity/entity";
|
||||
import { isUnavailableState, UNAVAILABLE } from "../../../data/entity/entity";
|
||||
import type { HomeAssistant, ValueChangedEvent } from "../../../types";
|
||||
|
||||
@customElement("more-info-date")
|
||||
@@ -21,9 +21,10 @@ class MoreInfoDate extends LitElement {
|
||||
return html`
|
||||
<ha-date-input
|
||||
.locale=${this.hass.locale}
|
||||
.value=${this.stateObj.state === UNKNOWN
|
||||
.value=${isUnavailableState(this.stateObj.state)
|
||||
? undefined
|
||||
: this.stateObj.state}
|
||||
.disabled=${this.stateObj.state === UNAVAILABLE}
|
||||
@value-changed=${this._dateChanged}
|
||||
>
|
||||
</ha-date-input>
|
||||
|
||||
@@ -5,7 +5,7 @@ import { customElement, property } from "lit/decorators";
|
||||
import "../../../components/ha-date-input";
|
||||
import "../../../components/ha-time-input";
|
||||
import { setDateTimeValue } from "../../../data/datetime";
|
||||
import { UNAVAILABLE, UNKNOWN } from "../../../data/entity/entity";
|
||||
import { isUnavailableState, UNAVAILABLE } from "../../../data/entity/entity";
|
||||
import type { HomeAssistant, ValueChangedEvent } from "../../../types";
|
||||
|
||||
@customElement("more-info-datetime")
|
||||
@@ -19,22 +19,23 @@ class MoreInfoDatetime extends LitElement {
|
||||
return nothing;
|
||||
}
|
||||
|
||||
const dateObj =
|
||||
this.stateObj.state === UNKNOWN
|
||||
? undefined
|
||||
: new Date(this.stateObj.state);
|
||||
const dateObj = isUnavailableState(this.stateObj.state)
|
||||
? undefined
|
||||
: new Date(this.stateObj.state);
|
||||
const time = dateObj ? format(dateObj, "HH:mm:ss") : undefined;
|
||||
const date = dateObj ? format(dateObj, "yyyy-MM-dd") : undefined;
|
||||
|
||||
return html`<ha-date-input
|
||||
.locale=${this.hass.locale}
|
||||
.value=${date}
|
||||
.disabled=${this.stateObj.state === UNAVAILABLE}
|
||||
@value-changed=${this._dateChanged}
|
||||
>
|
||||
</ha-date-input>
|
||||
<ha-time-input
|
||||
.value=${time}
|
||||
.locale=${this.hass.locale}
|
||||
.disabled=${this.stateObj.state === UNAVAILABLE}
|
||||
@value-changed=${this._timeChanged}
|
||||
@click=${this._stopEventPropagation}
|
||||
></ha-time-input>`;
|
||||
|
||||
@@ -11,7 +11,7 @@ import "../../../components/ha-control-button-group";
|
||||
import "../../../components/ha-markdown";
|
||||
import "../../../components/ha-relative-time";
|
||||
import "../../../components/ha-service-control";
|
||||
import { UNAVAILABLE } from "../../../data/entity/entity";
|
||||
import { isUnavailableState } from "../../../data/entity/entity";
|
||||
import type { ExtEntityRegistryEntry } from "../../../data/entity/entity_registry";
|
||||
import type { ScriptEntity } from "../../../data/script";
|
||||
import {
|
||||
@@ -141,7 +141,7 @@ class MoreInfoScript extends LitElement {
|
||||
<ha-control-button
|
||||
class="run-button"
|
||||
@click=${this._runScript}
|
||||
.disabled=${stateObj.state === UNAVAILABLE || !this._canRun()}
|
||||
.disabled=${isUnavailableState(stateObj.state) || !this._canRun()}
|
||||
>
|
||||
<ha-svg-icon .path=${mdiPlay}></ha-svg-icon>
|
||||
${this.hass!.localize("ui.card.script.run")}
|
||||
|
||||
@@ -3,7 +3,7 @@ import { css, html, LitElement, nothing } from "lit";
|
||||
import { customElement, property } from "lit/decorators";
|
||||
import "../../../components/ha-date-input";
|
||||
import "../../../components/ha-time-input";
|
||||
import { UNAVAILABLE, UNKNOWN } from "../../../data/entity/entity";
|
||||
import { isUnavailableState, UNAVAILABLE } from "../../../data/entity/entity";
|
||||
import { setTimeValue } from "../../../data/time";
|
||||
import type { HomeAssistant, ValueChangedEvent } from "../../../types";
|
||||
|
||||
@@ -20,10 +20,11 @@ class MoreInfoTime extends LitElement {
|
||||
|
||||
return html`
|
||||
<ha-time-input
|
||||
.value=${this.stateObj.state === UNKNOWN
|
||||
.value=${isUnavailableState(this.stateObj.state)
|
||||
? undefined
|
||||
: this.stateObj.state}
|
||||
.locale=${this.hass.locale}
|
||||
.disabled=${this.stateObj.state === UNAVAILABLE}
|
||||
@value-changed=${this._timeChanged}
|
||||
@click=${this._stopEventPropagation}
|
||||
></ha-time-input>
|
||||
|
||||
@@ -15,7 +15,7 @@ import "../../../components/item/ha-row-item";
|
||||
import "../../../components/progress/ha-progress-bar";
|
||||
import type { BackupConfig } from "../../../data/backup";
|
||||
import { fetchBackupConfig } from "../../../data/backup";
|
||||
import { UNAVAILABLE, UNKNOWN } from "../../../data/entity/entity";
|
||||
import { isUnavailableState } from "../../../data/entity/entity";
|
||||
import type { EntitySources } from "../../../data/entity/entity_sources";
|
||||
import { fetchEntitySourcesWithCache } from "../../../data/entity/entity_sources";
|
||||
import { getSupervisorUpdateConfig } from "../../../data/supervisor/update";
|
||||
@@ -176,8 +176,7 @@ class MoreInfoUpdate extends LitElement {
|
||||
if (
|
||||
!this.hass ||
|
||||
!this.stateObj ||
|
||||
this.stateObj.state === UNAVAILABLE ||
|
||||
this.stateObj.state === UNKNOWN
|
||||
isUnavailableState(this.stateObj.state)
|
||||
) {
|
||||
return nothing;
|
||||
}
|
||||
|
||||
@@ -5,18 +5,14 @@ import "../../components/ha-icon";
|
||||
import "../../components/ha-spinner";
|
||||
import "../../components/item/ha-list-item-button";
|
||||
import "../../components/list/ha-list-base";
|
||||
import type { HaListItemButton } from "../../components/item/ha-list-item-button";
|
||||
import type {
|
||||
ExternalEntityAddToAction,
|
||||
ExternalEntityAddToActions,
|
||||
} from "../../external_app/external_messaging";
|
||||
import { showToast } from "../../util/toast";
|
||||
|
||||
import type { HASSDomCurrentTargetEvent } from "../../common/dom/fire_event";
|
||||
import { fireEvent } from "../../common/dom/fire_event";
|
||||
import type { HomeAssistant } from "../../types";
|
||||
import {
|
||||
type EntityAddToAction,
|
||||
type EntityAddToActions,
|
||||
defaultActionHandler,
|
||||
getDefaultAddToActions,
|
||||
} from "./add-to";
|
||||
|
||||
@customElement("ha-more-info-add-to")
|
||||
export class HaMoreInfoAddTo extends LitElement {
|
||||
@@ -24,112 +20,54 @@ export class HaMoreInfoAddTo extends LitElement {
|
||||
|
||||
@property({ attribute: false }) public entityId!: string;
|
||||
|
||||
@state() private _defaultActions: EntityAddToActions = [];
|
||||
|
||||
@state() private _externalActions: EntityAddToActions = [];
|
||||
@state() private _externalActions?: ExternalEntityAddToActions = {
|
||||
actions: [],
|
||||
};
|
||||
|
||||
@state() private _loading = true;
|
||||
|
||||
private async _loadActions() {
|
||||
this._defaultActions = getDefaultAddToActions(
|
||||
this.hass.states,
|
||||
this.hass.localize,
|
||||
this.hass.formatEntityName,
|
||||
this.entityId
|
||||
);
|
||||
this._externalActions = [];
|
||||
|
||||
private async _loadExternalActions() {
|
||||
if (this.hass.auth.external?.config.hasEntityAddTo) {
|
||||
try {
|
||||
const response =
|
||||
await this.hass.auth.external?.sendMessage<"entity/add_to/get_actions">(
|
||||
{
|
||||
type: "entity/add_to/get_actions",
|
||||
payload: { entity_id: this.entityId },
|
||||
}
|
||||
);
|
||||
if (response?.actions) {
|
||||
this._externalActions = response.actions.map((action) => ({
|
||||
type: "external",
|
||||
enabled: action.enabled,
|
||||
name: action.name,
|
||||
description: action.details,
|
||||
icon: action.mdi_icon,
|
||||
payload: action.app_payload,
|
||||
}));
|
||||
}
|
||||
} catch (err: unknown) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.warn("Failed to fetch add to actions", err);
|
||||
}
|
||||
this._externalActions =
|
||||
await this.hass.auth.external?.sendMessage<"entity/add_to/get_actions">(
|
||||
{
|
||||
type: "entity/add_to/get_actions",
|
||||
payload: { entity_id: this.entityId },
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
private async _actionSelected(
|
||||
ev: HASSDomCurrentTargetEvent<
|
||||
HaListItemButton & {
|
||||
action: EntityAddToAction;
|
||||
}
|
||||
>
|
||||
) {
|
||||
const action = ev.currentTarget.action;
|
||||
private async _actionSelected(ev: CustomEvent) {
|
||||
const action = (ev.currentTarget as any)
|
||||
.action as ExternalEntityAddToAction;
|
||||
if (!action.enabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (action.type === "external") {
|
||||
try {
|
||||
if (!action.payload) {
|
||||
throw new Error("Missing external action payload");
|
||||
}
|
||||
this.hass.auth.external!.fireMessage({
|
||||
type: "entity/add_to",
|
||||
payload: {
|
||||
entity_id: this.entityId,
|
||||
app_payload: action.payload,
|
||||
},
|
||||
});
|
||||
fireEvent(this, "add-to-action-selected");
|
||||
} catch (err: unknown) {
|
||||
showToast(this, {
|
||||
message: this.hass.localize(
|
||||
"ui.dialogs.more_info_control.add_to.action_failed",
|
||||
{
|
||||
error: err instanceof Error ? err.message : String(err),
|
||||
}
|
||||
),
|
||||
});
|
||||
}
|
||||
return;
|
||||
try {
|
||||
await this.hass.auth.external!.fireMessage({
|
||||
type: "entity/add_to",
|
||||
payload: {
|
||||
entity_id: this.entityId,
|
||||
app_payload: action.app_payload,
|
||||
},
|
||||
});
|
||||
fireEvent(this, "add-to-action-selected");
|
||||
} catch (err: any) {
|
||||
showToast(this, {
|
||||
message: this.hass.localize(
|
||||
"ui.dialogs.more_info_control.add_to.action_failed",
|
||||
{
|
||||
error: err.message || err,
|
||||
}
|
||||
),
|
||||
});
|
||||
}
|
||||
|
||||
if (action.type !== "default") {
|
||||
return;
|
||||
}
|
||||
|
||||
defaultActionHandler(action.key, this.entityId);
|
||||
}
|
||||
|
||||
private _renderActionItems(actions: EntityAddToActions) {
|
||||
return actions.map(
|
||||
(action) => html`
|
||||
<ha-list-item-button
|
||||
.disabled=${!action.enabled}
|
||||
.action=${action}
|
||||
@click=${this._actionSelected}
|
||||
>
|
||||
<ha-icon slot="start" .icon=${action.icon}></ha-icon>
|
||||
<span slot="headline">${action.name}</span>
|
||||
${action.description
|
||||
? html`<span slot="supporting-text">${action.description}</span>`
|
||||
: nothing}
|
||||
</ha-list-item-button>
|
||||
`
|
||||
);
|
||||
}
|
||||
|
||||
protected async firstUpdated() {
|
||||
await this._loadActions();
|
||||
await this._loadExternalActions();
|
||||
this._loading = false;
|
||||
}
|
||||
|
||||
@@ -142,7 +80,7 @@ export class HaMoreInfoAddTo extends LitElement {
|
||||
`;
|
||||
}
|
||||
|
||||
if (!this._defaultActions.length && !this._externalActions.length) {
|
||||
if (!this._externalActions?.actions.length) {
|
||||
return html`
|
||||
<ha-alert alert-type="info">
|
||||
${this.hass.localize(
|
||||
@@ -154,27 +92,30 @@ export class HaMoreInfoAddTo extends LitElement {
|
||||
|
||||
return html`
|
||||
<ha-list-base>
|
||||
${this._renderActionItems(this._defaultActions)}
|
||||
</ha-list-base>
|
||||
${this._externalActions.length
|
||||
? html`
|
||||
<h2 class="section-title">
|
||||
${this.hass.localize(
|
||||
"ui.dialogs.more_info_control.add_to.app_actions"
|
||||
)}
|
||||
</h2>
|
||||
<ha-list-base>
|
||||
${this._renderActionItems(this._externalActions)}
|
||||
</ha-list-base>
|
||||
${this._externalActions?.actions.map(
|
||||
(action) => html`
|
||||
<ha-list-item-button
|
||||
.disabled=${!action.enabled}
|
||||
.action=${action}
|
||||
@click=${this._actionSelected}
|
||||
>
|
||||
<ha-icon slot="start" .icon=${action.mdi_icon}></ha-icon>
|
||||
<span slot="headline">${action.name}</span>
|
||||
${action.details
|
||||
? html`<span slot="supporting-text">${action.details}</span>`
|
||||
: nothing}
|
||||
</ha-list-item-button>
|
||||
`
|
||||
: nothing}
|
||||
)}
|
||||
</ha-list-base>
|
||||
`;
|
||||
}
|
||||
|
||||
static styles = css`
|
||||
:host {
|
||||
display: block;
|
||||
padding: var(--ha-space-3) 0 var(--ha-space-4);
|
||||
padding: var(--ha-space-2) var(--ha-space-6) var(--ha-space-6)
|
||||
var(--ha-space-6);
|
||||
}
|
||||
|
||||
.loading {
|
||||
@@ -184,15 +125,6 @@ export class HaMoreInfoAddTo extends LitElement {
|
||||
padding: var(--ha-space-8);
|
||||
}
|
||||
|
||||
.section-title {
|
||||
padding: 0 var(--ha-space-6);
|
||||
margin: var(--ha-space-4) 0 var(--ha-space-1);
|
||||
font-size: var(--ha-font-size-m);
|
||||
font-weight: var(--ha-font-weight-medium);
|
||||
line-height: var(--ha-line-height-normal);
|
||||
color: var(--secondary-text-color);
|
||||
}
|
||||
|
||||
ha-icon {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import "@home-assistant/webawesome/dist/components/divider/divider";
|
||||
import {
|
||||
mdiBackupRestore,
|
||||
mdiChartBoxOutline,
|
||||
@@ -18,13 +17,13 @@ import {
|
||||
} from "@mdi/js";
|
||||
import type { HassEntity } from "home-assistant-js-websocket";
|
||||
import type { PropertyValues } from "lit";
|
||||
import { css, html, LitElement, nothing } from "lit";
|
||||
import { LitElement, css, html, nothing } from "lit";
|
||||
import { customElement, property, query, state } from "lit/decorators";
|
||||
import { cache } from "lit/directives/cache";
|
||||
import { classMap } from "lit/directives/class-map";
|
||||
import { keyed } from "lit/directives/keyed";
|
||||
import { dynamicElement } from "../../common/dom/dynamic-element-directive";
|
||||
import type { HASSDomEvent } from "../../common/dom/fire_event";
|
||||
import { dynamicElement } from "../../common/dom/dynamic-element-directive";
|
||||
import { fireEvent } from "../../common/dom/fire_event";
|
||||
import { stopPropagation } from "../../common/dom/stop_propagation";
|
||||
import { computeAreaName } from "../../common/entity/compute_area_name";
|
||||
@@ -58,12 +57,10 @@ import {
|
||||
getExtendedEntityRegistryEntry,
|
||||
updateEntityRegistryEntry,
|
||||
} from "../../data/entity/entity_registry";
|
||||
import { subscribeLabFeature } from "../../data/labs";
|
||||
import type { ItemType } from "../../data/search";
|
||||
import { SearchableDomains } from "../../data/search";
|
||||
import { getSensorNumericDeviceClasses } from "../../data/sensor";
|
||||
import { ScrollableFadeMixin } from "../../mixins/scrollable-fade-mixin";
|
||||
import { SubscribeMixin } from "../../mixins/subscribe-mixin";
|
||||
import {
|
||||
haStyleDialog,
|
||||
haStyleDialogFixedTop,
|
||||
@@ -73,12 +70,12 @@ import "../../state-summary/state-card-content";
|
||||
import type { HomeAssistant } from "../../types";
|
||||
import { showConfirmationDialog } from "../generic/show-dialog-box";
|
||||
import {
|
||||
computeShowHistoryComponent,
|
||||
computeShowLogBookComponent,
|
||||
DOMAINS_WITH_MORE_INFO,
|
||||
EDITABLE_DOMAINS_WITH_ID,
|
||||
EDITABLE_DOMAINS_WITH_UNIQUE_ID,
|
||||
type MoreInfoView,
|
||||
computeShowHistoryComponent,
|
||||
computeShowLogBookComponent,
|
||||
} from "./const";
|
||||
import "./controls/more-info-default";
|
||||
import type { FavoritesDialogContext } from "./favorites";
|
||||
@@ -120,9 +117,7 @@ declare global {
|
||||
const DEFAULT_VIEW: MoreInfoView = "info";
|
||||
|
||||
@customElement("ha-more-info-dialog")
|
||||
export class MoreInfoDialog extends SubscribeMixin(
|
||||
ScrollableFadeMixin(LitElement)
|
||||
) {
|
||||
export class MoreInfoDialog extends ScrollableFadeMixin(LitElement) {
|
||||
@property({ attribute: false }) public hass!: HomeAssistant;
|
||||
|
||||
@property({ type: Boolean, reflect: true }) public large = false;
|
||||
@@ -161,8 +156,6 @@ export class MoreInfoDialog extends SubscribeMixin(
|
||||
|
||||
@state() private _sensorNumericDeviceClasses?: string[] = [];
|
||||
|
||||
@state() private _newTriggersAndConditions = false;
|
||||
|
||||
protected scrollFadeThreshold = 24;
|
||||
|
||||
protected get scrollableElement(): HTMLElement | null {
|
||||
@@ -261,24 +254,7 @@ export class MoreInfoDialog extends SubscribeMixin(
|
||||
}
|
||||
|
||||
private _shouldShowAddEntityTo(): boolean {
|
||||
// When labs feature is promoted, this whole check can be removed.
|
||||
return (
|
||||
this._newTriggersAndConditions ||
|
||||
!!this.hass.auth.external?.config.hasEntityAddTo
|
||||
);
|
||||
}
|
||||
|
||||
protected hassSubscribe() {
|
||||
return [
|
||||
subscribeLabFeature(
|
||||
this.hass.connection,
|
||||
"automation",
|
||||
"new_triggers_conditions",
|
||||
(feature) => {
|
||||
this._newTriggersAndConditions = feature.enabled;
|
||||
}
|
||||
),
|
||||
];
|
||||
return !!this.hass.auth.external?.config.hasEntityAddTo;
|
||||
}
|
||||
|
||||
private _getDeviceId(): string | null {
|
||||
@@ -704,21 +680,6 @@ export class MoreInfoDialog extends SubscribeMixin(
|
||||
.path=${mdiDotsVertical}
|
||||
></ha-icon-button>
|
||||
|
||||
${this._shouldShowAddEntityTo()
|
||||
? html`
|
||||
<ha-dropdown-item value="add_to">
|
||||
<ha-svg-icon
|
||||
slot="icon"
|
||||
.path=${mdiPlusBoxMultipleOutline}
|
||||
></ha-svg-icon>
|
||||
${this.hass.localize(
|
||||
"ui.dialogs.more_info_control.add_entity_to"
|
||||
)}
|
||||
</ha-dropdown-item>
|
||||
|
||||
<wa-divider></wa-divider>
|
||||
`
|
||||
: nothing}
|
||||
${supportsFavorites
|
||||
? html`
|
||||
<ha-dropdown-item value="toggle_edit">
|
||||
@@ -808,6 +769,19 @@ export class MoreInfoDialog extends SubscribeMixin(
|
||||
"ui.dialogs.more_info_control.details"
|
||||
)}
|
||||
</ha-dropdown-item>
|
||||
${this._shouldShowAddEntityTo()
|
||||
? html`
|
||||
<ha-dropdown-item value="add_to">
|
||||
<ha-svg-icon
|
||||
slot="icon"
|
||||
.path=${mdiPlusBoxMultipleOutline}
|
||||
></ha-svg-icon>
|
||||
${this.hass.localize(
|
||||
"ui.dialogs.more_info_control.add_entity_to"
|
||||
)}
|
||||
</ha-dropdown-item>
|
||||
`
|
||||
: nothing}
|
||||
</ha-dropdown>
|
||||
`
|
||||
: !__DEMO__ && this._shouldShowAddEntityTo()
|
||||
|
||||
@@ -199,13 +199,13 @@ export class HaVoiceAssistantSetupStepLocal extends LitElement {
|
||||
this._detailState = this.hass.localize(
|
||||
`ui.panel.config.voice_assistants.satellite_wizard.local.state.installing_${this._ttsProviderName}`
|
||||
);
|
||||
await installHassioAddon(this.hass.callWS, this._ttsAddonName);
|
||||
await installHassioAddon(this.hass, this._ttsAddonName);
|
||||
}
|
||||
if (!ttsAddon || ttsAddon.state !== "started") {
|
||||
this._detailState = this.hass.localize(
|
||||
`ui.panel.config.voice_assistants.satellite_wizard.local.state.starting_${this._ttsProviderName}`
|
||||
);
|
||||
await startHassioAddon(this.hass.callWS, this._ttsAddonName);
|
||||
await startHassioAddon(this.hass, this._ttsAddonName);
|
||||
}
|
||||
this._detailState = this.hass.localize(
|
||||
`ui.panel.config.voice_assistants.satellite_wizard.local.state.setup_${this._ttsProviderName}`
|
||||
@@ -217,13 +217,13 @@ export class HaVoiceAssistantSetupStepLocal extends LitElement {
|
||||
this._detailState = this.hass.localize(
|
||||
`ui.panel.config.voice_assistants.satellite_wizard.local.state.installing_${this._sttProviderName}`
|
||||
);
|
||||
await installHassioAddon(this.hass.callWS, this._sttAddonName);
|
||||
await installHassioAddon(this.hass, this._sttAddonName);
|
||||
}
|
||||
if (!sttAddon || sttAddon.state !== "started") {
|
||||
this._detailState = this.hass.localize(
|
||||
`ui.panel.config.voice_assistants.satellite_wizard.local.state.starting_${this._sttProviderName}`
|
||||
);
|
||||
await startHassioAddon(this.hass.callWS, this._sttAddonName);
|
||||
await startHassioAddon(this.hass, this._sttAddonName);
|
||||
}
|
||||
this._detailState = this.hass.localize(
|
||||
`ui.panel.config.voice_assistants.satellite_wizard.local.state.setup_${this._sttProviderName}`
|
||||
|
||||
@@ -213,7 +213,7 @@ class HaPanelApp extends LitElement {
|
||||
let addon: HassioAddonDetails;
|
||||
|
||||
try {
|
||||
addon = await fetchHassioAddonInfo(this.hass.callWS, addonSlug);
|
||||
addon = await fetchHassioAddonInfo(this.hass, addonSlug);
|
||||
} catch (err: any) {
|
||||
await this._showErrorAndNavigateHome(
|
||||
addonSlug,
|
||||
@@ -253,7 +253,7 @@ class HaPanelApp extends LitElement {
|
||||
);
|
||||
// Set auto-retry window for after starting the app
|
||||
this._autoRetryUntil = Date.now() + START_WAIT_TIME;
|
||||
await startHassioAddon(this.hass.callWS, addonSlug);
|
||||
await startHassioAddon(this.hass, addonSlug);
|
||||
this._fetchData(addonSlug);
|
||||
return;
|
||||
} catch (_err) {
|
||||
|
||||
@@ -3,7 +3,7 @@ import { css, html, LitElement } from "lit";
|
||||
import { customElement, property } from "lit/decorators";
|
||||
import { classMap } from "lit/directives/class-map";
|
||||
import "../../../../../components/ha-bar";
|
||||
import "../../../../../components/item/ha-row-item";
|
||||
import "../../../../../components/ha-settings-row";
|
||||
import { roundWithOneDecimal } from "../../../../../util/calculate";
|
||||
|
||||
@customElement("supervisor-app-metric")
|
||||
@@ -16,9 +16,9 @@ class SupervisorAppMetric extends LitElement {
|
||||
|
||||
protected render(): TemplateResult {
|
||||
const roundedValue = roundWithOneDecimal(this.value);
|
||||
return html`<ha-row-item empty>
|
||||
<span slot="headline"> ${this.description} </span>
|
||||
<div slot="supporting-text" .title=${this.tooltip ?? ""}>
|
||||
return html`<ha-settings-row empty>
|
||||
<span slot="heading"> ${this.description} </span>
|
||||
<div slot="description" .title=${this.tooltip ?? ""}>
|
||||
<span class="value"> ${roundedValue} % </span>
|
||||
<ha-bar
|
||||
class=${classMap({
|
||||
@@ -28,14 +28,16 @@ class SupervisorAppMetric extends LitElement {
|
||||
.value=${this.value}
|
||||
></ha-bar>
|
||||
</div>
|
||||
</ha-row-item>`;
|
||||
</ha-settings-row>`;
|
||||
}
|
||||
|
||||
static styles = css`
|
||||
ha-row-item {
|
||||
ha-settings-row {
|
||||
padding: 0;
|
||||
height: 54px;
|
||||
width: 100%;
|
||||
}
|
||||
ha-row-item > div[slot="supporting-text"] {
|
||||
ha-settings-row > div[slot="description"] {
|
||||
white-space: normal;
|
||||
color: var(--secondary-text-color);
|
||||
display: flex;
|
||||
|
||||
@@ -0,0 +1,283 @@
|
||||
import {
|
||||
css,
|
||||
type CSSResultGroup,
|
||||
html,
|
||||
LitElement,
|
||||
nothing,
|
||||
type PropertyValues,
|
||||
} from "lit";
|
||||
import { customElement, property, state } from "lit/decorators";
|
||||
import { atLeastVersion } from "../../../../../common/config/version";
|
||||
import { fireEvent } from "../../../../../common/dom/fire_event";
|
||||
import "../../../../../components/buttons/ha-progress-button";
|
||||
import "../../../../../components/ha-alert";
|
||||
import "../../../../../components/ha-button";
|
||||
import "../../../../../components/ha-card";
|
||||
import "../../../../../components/ha-faded";
|
||||
import "../../../../../components/ha-markdown";
|
||||
import "../../../../../components/ha-spinner";
|
||||
import "../../../../../components/ha-switch";
|
||||
import type { HaSwitch } from "../../../../../components/ha-switch";
|
||||
import "../../../../../components/item/ha-row-item";
|
||||
import type { HassioAddonDetails } from "../../../../../data/hassio/addon";
|
||||
import {
|
||||
fetchHassioAddonChangelog,
|
||||
updateHassioAddon,
|
||||
} from "../../../../../data/hassio/addon";
|
||||
import {
|
||||
extractApiErrorMessage,
|
||||
ignoreSupervisorError,
|
||||
} from "../../../../../data/hassio/common";
|
||||
import { haStyle } from "../../../../../resources/styles";
|
||||
import type { HomeAssistant } from "../../../../../types";
|
||||
import { extractChangelog } from "../util/supervisor-app";
|
||||
|
||||
declare global {
|
||||
interface HASSDomEvents {
|
||||
"update-complete": undefined;
|
||||
}
|
||||
}
|
||||
|
||||
@customElement("supervisor-app-update-available-card")
|
||||
class SupervisorAppUpdateAvailableCard extends LitElement {
|
||||
@property({ attribute: false }) public hass!: HomeAssistant;
|
||||
|
||||
@property({ type: Boolean }) public narrow = false;
|
||||
|
||||
@property({ attribute: false }) public addon!: HassioAddonDetails;
|
||||
|
||||
@state() private _changelogContent?: string;
|
||||
|
||||
@state() private _updating = false;
|
||||
|
||||
@state() private _error?: string;
|
||||
|
||||
protected render() {
|
||||
if (!this.addon) {
|
||||
return nothing;
|
||||
}
|
||||
|
||||
const createBackupTexts = this._computeCreateBackupTexts();
|
||||
|
||||
return html`
|
||||
<ha-card
|
||||
outlined
|
||||
.header=${this.hass.localize(
|
||||
"ui.panel.config.apps.dashboard.update_available.update_name",
|
||||
{
|
||||
name: this.addon.name,
|
||||
}
|
||||
)}
|
||||
>
|
||||
<div class="card-content">
|
||||
${this._error
|
||||
? html`<ha-alert alert-type="error">${this._error}</ha-alert>`
|
||||
: ""}
|
||||
${this.addon.version === this.addon.version_latest
|
||||
? html`<p>
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.apps.dashboard.update_available.no_update",
|
||||
{
|
||||
name: this.addon.name,
|
||||
}
|
||||
)}
|
||||
</p>`
|
||||
: !this._updating
|
||||
? html`
|
||||
${this._changelogContent
|
||||
? html`
|
||||
<ha-faded>
|
||||
<ha-markdown .content=${this._changelogContent}>
|
||||
</ha-markdown>
|
||||
</ha-faded>
|
||||
`
|
||||
: nothing}
|
||||
<div class="versions">
|
||||
<p>
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.apps.dashboard.update_available.description",
|
||||
{
|
||||
name: this.addon.name,
|
||||
version: this.addon.version,
|
||||
newest_version: this.addon.version_latest,
|
||||
}
|
||||
)}
|
||||
</p>
|
||||
</div>
|
||||
${createBackupTexts
|
||||
? html`
|
||||
<hr />
|
||||
<ha-row-item>
|
||||
<span slot="headline">
|
||||
${createBackupTexts.title}
|
||||
</span>
|
||||
|
||||
${createBackupTexts.description
|
||||
? html`
|
||||
<span slot="supporting-text">
|
||||
${createBackupTexts.description}
|
||||
</span>
|
||||
`
|
||||
: nothing}
|
||||
<ha-switch slot="end" id="create-backup"></ha-switch>
|
||||
</ha-row-item>
|
||||
`
|
||||
: nothing}
|
||||
`
|
||||
: html`<ha-spinner
|
||||
aria-label="Updating"
|
||||
size="large"
|
||||
></ha-spinner>
|
||||
<p class="progress-text">
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.apps.dashboard.update_available.updating",
|
||||
{
|
||||
name: this.addon.name,
|
||||
version: this.addon.version_latest,
|
||||
}
|
||||
)}
|
||||
</p>`}
|
||||
</div>
|
||||
${this.addon.version !== this.addon.version_latest && !this._updating
|
||||
? html`
|
||||
<div class="card-actions">
|
||||
<span></span>
|
||||
<ha-progress-button @click=${this._update}>
|
||||
${this.hass.localize("ui.common.update")}
|
||||
</ha-progress-button>
|
||||
</div>
|
||||
`
|
||||
: nothing}
|
||||
</ha-card>
|
||||
`;
|
||||
}
|
||||
|
||||
protected firstUpdated(changedProps: PropertyValues<this>) {
|
||||
super.firstUpdated(changedProps);
|
||||
this._loadAddonData();
|
||||
}
|
||||
|
||||
private _computeCreateBackupTexts():
|
||||
| { title: string; description?: string }
|
||||
| undefined {
|
||||
if (atLeastVersion(this.hass.config.version, 2025, 2, 0)) {
|
||||
const version = this.addon.version;
|
||||
return {
|
||||
title: this.hass.localize(
|
||||
"ui.panel.config.apps.dashboard.update_available.create_backup.app"
|
||||
),
|
||||
description: this.hass.localize(
|
||||
"ui.panel.config.apps.dashboard.update_available.create_backup.app_description",
|
||||
{ version: version }
|
||||
),
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
title: this.hass.localize(
|
||||
"ui.panel.config.apps.dashboard.update_available.create_backup.generic"
|
||||
),
|
||||
};
|
||||
}
|
||||
|
||||
get _shouldCreateBackup(): boolean {
|
||||
const createBackupSwitch = this.shadowRoot?.getElementById(
|
||||
"create-backup"
|
||||
) as HaSwitch;
|
||||
if (createBackupSwitch) {
|
||||
return createBackupSwitch.checked;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private async _loadAddonData() {
|
||||
if (this.addon.changelog) {
|
||||
try {
|
||||
const content = await fetchHassioAddonChangelog(
|
||||
this.hass,
|
||||
this.addon.slug
|
||||
);
|
||||
this._changelogContent = extractChangelog(
|
||||
this.addon as HassioAddonDetails,
|
||||
content
|
||||
);
|
||||
} catch (err) {
|
||||
this._error = extractApiErrorMessage(err);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private async _update() {
|
||||
this._error = undefined;
|
||||
this._updating = true;
|
||||
|
||||
try {
|
||||
await updateHassioAddon(
|
||||
this.hass,
|
||||
this.addon.slug,
|
||||
this._shouldCreateBackup
|
||||
);
|
||||
} catch (err: any) {
|
||||
if (this.hass.connection.connected && !ignoreSupervisorError(err)) {
|
||||
this._error = extractApiErrorMessage(err);
|
||||
this._updating = false;
|
||||
return;
|
||||
}
|
||||
}
|
||||
fireEvent(this, "update-complete");
|
||||
this._updating = false;
|
||||
}
|
||||
|
||||
static get styles(): CSSResultGroup {
|
||||
return [
|
||||
haStyle,
|
||||
css`
|
||||
:host {
|
||||
display: block;
|
||||
}
|
||||
ha-card {
|
||||
margin: auto;
|
||||
}
|
||||
a {
|
||||
text-decoration: none;
|
||||
color: var(--primary-text-color);
|
||||
}
|
||||
.card-actions {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
ha-spinner {
|
||||
display: block;
|
||||
margin: 32px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.progress-text {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
ha-markdown {
|
||||
padding-bottom: var(--ha-space-2);
|
||||
}
|
||||
|
||||
hr {
|
||||
border-color: var(--divider-color);
|
||||
border-bottom: none;
|
||||
margin: var(--ha-space-4) 0 0 0;
|
||||
}
|
||||
|
||||
ha-row-item {
|
||||
--ha-row-item-padding-inline: 0;
|
||||
margin-bottom: calc(-1 * var(--ha-space-4));
|
||||
}
|
||||
`,
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
declare global {
|
||||
interface HTMLElementTagNameMap {
|
||||
"supervisor-app-update-available-card": SupervisorAppUpdateAvailableCard;
|
||||
}
|
||||
}
|
||||
@@ -183,7 +183,7 @@ class SupervisorAppAudio extends LitElement {
|
||||
this._selectedOutput === "default" ? null : this._selectedOutput,
|
||||
};
|
||||
try {
|
||||
await setHassioAddonOption(this.hass.callWS, this.addon.slug, data);
|
||||
await setHassioAddonOption(this.hass, this.addon.slug, data);
|
||||
if (this.addon?.state === "started") {
|
||||
await suggestSupervisorAppRestart(this, this.hass, this.addon);
|
||||
}
|
||||
|
||||
@@ -449,7 +449,7 @@ class SupervisorAppConfig extends LitElement {
|
||||
options: null,
|
||||
};
|
||||
try {
|
||||
await setHassioAddonOption(this.hass.callWS, this.addon.slug, data);
|
||||
await setHassioAddonOption(this.hass, this.addon.slug, data);
|
||||
this._configHasChanged = false;
|
||||
const eventdata = {
|
||||
success: true,
|
||||
@@ -488,14 +488,14 @@ class SupervisorAppConfig extends LitElement {
|
||||
|
||||
try {
|
||||
const validation = await validateHassioAddonOption(
|
||||
this.hass.callWS,
|
||||
this.hass,
|
||||
this.addon.slug,
|
||||
options
|
||||
);
|
||||
if (!validation.valid) {
|
||||
throw Error(validation.message);
|
||||
}
|
||||
await setHassioAddonOption(this.hass.callWS, this.addon.slug, {
|
||||
await setHassioAddonOption(this.hass, this.addon.slug, {
|
||||
options,
|
||||
});
|
||||
|
||||
|
||||
@@ -6,9 +6,9 @@ import { fireEvent } from "../../../../../common/dom/fire_event";
|
||||
import "../../../../../components/buttons/ha-progress-button";
|
||||
import "../../../../../components/ha-alert";
|
||||
import "../../../../../components/ha-card";
|
||||
import "../../../../../components/ha-formfield";
|
||||
import "../../../../../components/ha-form/ha-form";
|
||||
import type { HaFormSchema } from "../../../../../components/ha-form/types";
|
||||
import "../../../../../components/ha-formfield";
|
||||
import type {
|
||||
HassioAddonDetails,
|
||||
HassioAddonSetOptionParams,
|
||||
@@ -17,8 +17,8 @@ import { setHassioAddonOption } from "../../../../../data/hassio/addon";
|
||||
import { extractApiErrorMessage } from "../../../../../data/hassio/common";
|
||||
import { haStyle } from "../../../../../resources/styles";
|
||||
import type { HomeAssistant } from "../../../../../types";
|
||||
import { supervisorAppsStyle } from "../../resources/supervisor-apps-style";
|
||||
import { suggestSupervisorAppRestart } from "../dialogs/suggestSupervisorAppRestart";
|
||||
import { supervisorAppsStyle } from "../../resources/supervisor-apps-style";
|
||||
|
||||
@customElement("supervisor-app-network")
|
||||
class SupervisorAppNetwork extends LitElement {
|
||||
@@ -160,7 +160,7 @@ class SupervisorAppNetwork extends LitElement {
|
||||
};
|
||||
|
||||
try {
|
||||
await setHassioAddonOption(this.hass.callWS, this.addon.slug, data);
|
||||
await setHassioAddonOption(this.hass, this.addon.slug, data);
|
||||
this._configHasChanged = false;
|
||||
const eventdata = {
|
||||
success: true,
|
||||
@@ -205,7 +205,7 @@ class SupervisorAppNetwork extends LitElement {
|
||||
};
|
||||
|
||||
try {
|
||||
await setHassioAddonOption(this.hass.callWS, this.addon.slug, data);
|
||||
await setHassioAddonOption(this.hass, this.addon.slug, data);
|
||||
this._configHasChanged = false;
|
||||
const eventdata = {
|
||||
success: true,
|
||||
|
||||
@@ -28,7 +28,7 @@ export const suggestSupervisorAppRestart = async (
|
||||
});
|
||||
if (confirmed) {
|
||||
try {
|
||||
await restartHassioAddon(hass.callWS, addon.slug);
|
||||
await restartHassioAddon(hass, addon.slug);
|
||||
} catch (err: any) {
|
||||
showAlertDialog(element, {
|
||||
title: hass.localize(
|
||||
|
||||
@@ -46,8 +46,8 @@ class SupervisorAppInfoDashboard extends LitElement {
|
||||
css`
|
||||
.content {
|
||||
margin: auto;
|
||||
padding: var(--ha-space-4);
|
||||
max-width: 1200px;
|
||||
padding: var(--ha-space-2);
|
||||
max-width: 1024px;
|
||||
}
|
||||
`,
|
||||
];
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,19 +1,16 @@
|
||||
import { consume, type ContextType } from "@lit/context";
|
||||
import type { TemplateResult } from "lit";
|
||||
import { LitElement, css, html, nothing } from "lit";
|
||||
import { customElement, property, state } from "lit/decorators";
|
||||
import { customElement, property } from "lit/decorators";
|
||||
import { fireEvent } from "../../../../../common/dom/fire_event";
|
||||
import "../../../../../components/ha-alert";
|
||||
import "../../../../../components/ha-button";
|
||||
import { internationalizationContext } from "../../../../../data/context";
|
||||
import type { HomeAssistant } from "../../../../../types";
|
||||
|
||||
@customElement("supervisor-app-system-managed")
|
||||
class SupervisorAppSystemManaged extends LitElement {
|
||||
@property({ type: Boolean }) public narrow = false;
|
||||
|
||||
@state()
|
||||
@consume({ context: internationalizationContext, subscribe: true })
|
||||
private i18n!: ContextType<typeof internationalizationContext>;
|
||||
@property({ attribute: false }) public hass!: HomeAssistant;
|
||||
|
||||
@property({ type: Boolean, attribute: "hide-button" }) public hideButton =
|
||||
false;
|
||||
@@ -22,18 +19,18 @@ class SupervisorAppSystemManaged extends LitElement {
|
||||
return html`
|
||||
<ha-alert
|
||||
alert-type="warning"
|
||||
.title=${this.i18n.localize(
|
||||
.title=${this.hass.localize(
|
||||
"ui.panel.config.apps.dashboard.system_managed.title"
|
||||
)}
|
||||
.narrow=${this.narrow}
|
||||
>
|
||||
${this.i18n.localize(
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.apps.dashboard.system_managed.description"
|
||||
)}
|
||||
${!this.hideButton
|
||||
? html`
|
||||
<ha-button slot="action" @click=${this._takeControl}>
|
||||
${this.i18n.localize(
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.apps.dashboard.system_managed.take_control"
|
||||
)}
|
||||
</ha-button>
|
||||
|
||||
@@ -161,7 +161,7 @@ class HaConfigAppDashboard extends LitElement {
|
||||
}
|
||||
|
||||
try {
|
||||
this._addon = await fetchHassioAddonInfo(this.hass.callWS, slug);
|
||||
this._addon = await fetchHassioAddonInfo(this.hass, slug);
|
||||
} catch (err: any) {
|
||||
if (repositoryUrl) {
|
||||
try {
|
||||
@@ -210,7 +210,7 @@ class HaConfigAppDashboard extends LitElement {
|
||||
}
|
||||
|
||||
await addStoreRepository(this.hass, repositoryUrl);
|
||||
this._addon = await fetchHassioAddonInfo(this.hass.callWS, slug);
|
||||
this._addon = await fetchHassioAddonInfo(this.hass, slug);
|
||||
}
|
||||
|
||||
private async _apiCalled(ev): Promise<void> {
|
||||
|
||||
@@ -18,7 +18,6 @@ import { getValueFromDynamic, isDynamic } from "../../../../data/automation";
|
||||
import type { Action } from "../../../../data/script";
|
||||
import { EDITOR_SAVE_FAB_TOAST_BOTTOM_OFFSET } from "../editor-toast";
|
||||
import {
|
||||
getAddAutomationElementTargetFromQuery,
|
||||
PASTE_VALUE,
|
||||
showAddAutomationElementDialog,
|
||||
} from "../show-add-automation-element-dialog";
|
||||
@@ -42,8 +41,6 @@ export default class HaAutomationAction extends AutomationSortableListMixin<Acti
|
||||
@queryAll("ha-automation-action-row")
|
||||
private _actionRowElements?: HaAutomationActionRow[];
|
||||
|
||||
private _openedAddDialogFromQuery = false;
|
||||
|
||||
protected get items(): Action[] {
|
||||
return this.actions;
|
||||
}
|
||||
@@ -136,32 +133,6 @@ export default class HaAutomationAction extends AutomationSortableListMixin<Acti
|
||||
protected updated(changedProps: PropertyValues<this>) {
|
||||
super.updated(changedProps);
|
||||
|
||||
if (!this.hass) {
|
||||
return;
|
||||
}
|
||||
|
||||
const addActionTargetFromQuery = getAddAutomationElementTargetFromQuery(
|
||||
this.hass.states,
|
||||
"action"
|
||||
);
|
||||
|
||||
if (changedProps.has("actions") && addActionTargetFromQuery) {
|
||||
this._openedAddDialogFromQuery = false;
|
||||
}
|
||||
|
||||
if (
|
||||
!this._openedAddDialogFromQuery &&
|
||||
this.root &&
|
||||
!this.disabled &&
|
||||
this.actions.length === 0 &&
|
||||
addActionTargetFromQuery
|
||||
) {
|
||||
this._openedAddDialogFromQuery = true;
|
||||
queueMicrotask(() => this._addActionDialog());
|
||||
} else if (this._openedAddDialogFromQuery && !addActionTargetFromQuery) {
|
||||
this._openedAddDialogFromQuery = false;
|
||||
}
|
||||
|
||||
if (
|
||||
changedProps.has("actions") &&
|
||||
(this.focusLastItemOnChange || this.focusItemIndexOnChange !== undefined)
|
||||
|
||||
@@ -33,7 +33,6 @@ import type {
|
||||
import { computeRTL } from "../../../common/util/compute_rtl";
|
||||
import { debounce } from "../../../common/util/debounce";
|
||||
import { deepEqual } from "../../../common/util/deep-equal";
|
||||
import { constructUrlCurrentPath } from "../../../common/url/construct-url";
|
||||
import "../../../components/entity/state-badge";
|
||||
import "../../../components/ha-bottom-sheet";
|
||||
import "../../../components/ha-button";
|
||||
@@ -129,12 +128,7 @@ import "./add-automation-element/ha-automation-add-from-target";
|
||||
import "./add-automation-element/ha-automation-add-items";
|
||||
import "./add-automation-element/ha-automation-add-search";
|
||||
import type { AddAutomationElementDialogParams } from "./show-add-automation-element-dialog";
|
||||
import {
|
||||
ADD_AUTOMATION_ELEMENT_QUERY_PARAM,
|
||||
ADD_AUTOMATION_ELEMENT_TARGET_PARAM,
|
||||
getAddAutomationElementTargetFromQuery,
|
||||
PASTE_VALUE,
|
||||
} from "./show-add-automation-element-dialog";
|
||||
import { PASTE_VALUE } from "./show-add-automation-element-dialog";
|
||||
import { getTargetText } from "./target/get_target_text";
|
||||
|
||||
const TYPES = {
|
||||
@@ -236,8 +230,6 @@ class DialogAddAutomationElement
|
||||
|
||||
@state() private _newTriggersAndConditions = false;
|
||||
|
||||
@state() private _openedFromQuery = false;
|
||||
|
||||
@state() private _conditionDescriptions: ConditionDescriptions = {};
|
||||
|
||||
@state()
|
||||
@@ -303,27 +295,10 @@ class DialogAddAutomationElement
|
||||
}
|
||||
}
|
||||
|
||||
public showDialog(params: AddAutomationElementDialogParams): void {
|
||||
public showDialog(params): void {
|
||||
this._params = params;
|
||||
this._resetVariables();
|
||||
|
||||
const queryEntityId = getAddAutomationElementTargetFromQuery(
|
||||
this.hass.states,
|
||||
params.type
|
||||
);
|
||||
this._openedFromQuery = !!queryEntityId;
|
||||
|
||||
if (queryEntityId) {
|
||||
const searchParams = new URLSearchParams(mainWindow.location.search);
|
||||
searchParams.delete(ADD_AUTOMATION_ELEMENT_QUERY_PARAM);
|
||||
searchParams.delete(ADD_AUTOMATION_ELEMENT_TARGET_PARAM);
|
||||
mainWindow.history.replaceState(
|
||||
mainWindow.history.state,
|
||||
"",
|
||||
constructUrlCurrentPath(searchParams.toString())
|
||||
);
|
||||
}
|
||||
|
||||
this.addKeyboardShortcuts();
|
||||
|
||||
this._loadConfigEntries();
|
||||
@@ -339,26 +314,16 @@ class DialogAddAutomationElement
|
||||
(feature) => {
|
||||
this._newTriggersAndConditions = feature.enabled;
|
||||
this._tab = this._newTriggersAndConditions ? "targets" : "groups";
|
||||
if (
|
||||
queryEntityId &&
|
||||
this._newTriggersAndConditions &&
|
||||
!this._selectedTarget
|
||||
) {
|
||||
this._selectedTarget = { entity_id: queryEntityId };
|
||||
this._getItemsByTarget();
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
if (!queryEntityId) {
|
||||
// add initial dialog view state to history
|
||||
mainWindow.history.pushState(
|
||||
{
|
||||
dialogData: {},
|
||||
},
|
||||
""
|
||||
);
|
||||
}
|
||||
// add initial dialog view state to history
|
||||
mainWindow.history.pushState(
|
||||
{
|
||||
dialogData: {},
|
||||
},
|
||||
""
|
||||
);
|
||||
|
||||
if (this._params?.type === "action") {
|
||||
this.hass.loadBackendTranslation("services");
|
||||
@@ -378,16 +343,6 @@ class DialogAddAutomationElement
|
||||
|
||||
// prevent view mode switch when resizing window
|
||||
this._bottomSheetMode = this._narrow;
|
||||
|
||||
if (
|
||||
queryEntityId &&
|
||||
this._newTriggersAndConditions &&
|
||||
!this._selectedTarget
|
||||
) {
|
||||
this._selectedTarget = { entity_id: queryEntityId };
|
||||
this._tab = "targets";
|
||||
this._getItemsByTarget();
|
||||
}
|
||||
}
|
||||
|
||||
public closeDialog(historyState?: any) {
|
||||
@@ -452,7 +407,6 @@ class DialogAddAutomationElement
|
||||
this._narrow = false;
|
||||
this._targetItems = undefined;
|
||||
this._loadItemsError = false;
|
||||
this._openedFromQuery = false;
|
||||
}
|
||||
|
||||
private _updateNarrow = () => {
|
||||
@@ -937,9 +891,7 @@ class DialogAddAutomationElement
|
||||
></ha-icon-button>
|
||||
`
|
||||
: nothing}
|
||||
${this._narrow &&
|
||||
(this._selectedGroup || this._selectedTarget) &&
|
||||
!this._openedFromQuery
|
||||
${this._narrow && (this._selectedGroup || this._selectedTarget)
|
||||
? html`<ha-icon-button-prev
|
||||
slot="navigationIcon"
|
||||
@click=${this._back}
|
||||
|
||||
@@ -27,7 +27,6 @@ import { subscribeLabFeature } from "../../../../data/labs";
|
||||
import { SubscribeMixin } from "../../../../mixins/subscribe-mixin";
|
||||
import { EDITOR_SAVE_FAB_TOAST_BOTTOM_OFFSET } from "../editor-toast";
|
||||
import {
|
||||
getAddAutomationElementTargetFromQuery,
|
||||
PASTE_VALUE,
|
||||
showAddAutomationElementDialog,
|
||||
} from "../show-add-automation-element-dialog";
|
||||
@@ -58,8 +57,6 @@ export default class HaAutomationCondition extends AutomationSortableListMixin<C
|
||||
|
||||
private _unsub?: Promise<UnsubscribeFunc>;
|
||||
|
||||
private _openedAddDialogFromQuery = false;
|
||||
|
||||
protected get items(): Condition[] {
|
||||
return this.conditions;
|
||||
}
|
||||
@@ -121,32 +118,6 @@ export default class HaAutomationCondition extends AutomationSortableListMixin<C
|
||||
}
|
||||
|
||||
protected updated(changedProperties: PropertyValues<this>) {
|
||||
if (!this.hass) {
|
||||
return;
|
||||
}
|
||||
|
||||
const addConditionTargetFromQuery = getAddAutomationElementTargetFromQuery(
|
||||
this.hass.states,
|
||||
"condition"
|
||||
);
|
||||
|
||||
if (changedProperties.has("conditions") && addConditionTargetFromQuery) {
|
||||
this._openedAddDialogFromQuery = false;
|
||||
}
|
||||
|
||||
if (
|
||||
!this._openedAddDialogFromQuery &&
|
||||
this.root &&
|
||||
!this.disabled &&
|
||||
this.conditions.length === 0 &&
|
||||
addConditionTargetFromQuery
|
||||
) {
|
||||
this._openedAddDialogFromQuery = true;
|
||||
queueMicrotask(() => this._addConditionDialog());
|
||||
} else if (this._openedAddDialogFromQuery && !addConditionTargetFromQuery) {
|
||||
this._openedAddDialogFromQuery = false;
|
||||
}
|
||||
|
||||
if (!changedProperties.has("conditions")) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -77,7 +77,6 @@ import { showAssignCategoryDialog } from "../category/show-dialog-assign-categor
|
||||
import { showAutomationModeDialog } from "./automation-mode-dialog/show-dialog-automation-mode";
|
||||
import { showAutomationSaveDialog } from "./automation-save-dialog/show-dialog-automation-save";
|
||||
import { showAutomationSaveTimeoutDialog } from "./automation-save-timeout-dialog/show-dialog-automation-save-timeout";
|
||||
import { ADD_AUTOMATION_ELEMENT_QUERY_PARAM } from "./show-add-automation-element-dialog";
|
||||
import "./blueprint-automation-editor";
|
||||
import type { EditorDomainHooks } from "./ha-automation-script-editor-mixin";
|
||||
import {
|
||||
@@ -573,21 +572,11 @@ export class HaAutomationEditor extends AutomationScriptEditorMixin<AutomationCo
|
||||
protected updated(changedProps: PropertyValues): void {
|
||||
super.updated(changedProps);
|
||||
|
||||
if (!this.hass) {
|
||||
return;
|
||||
}
|
||||
|
||||
const shouldResetNewAutomationConfigFromQuery =
|
||||
changedProps.has("route") &&
|
||||
this.route?.path === "/new" &&
|
||||
new URLSearchParams(window.location.search).has(
|
||||
ADD_AUTOMATION_ELEMENT_QUERY_PARAM
|
||||
);
|
||||
|
||||
const oldAutomationId = changedProps.get("automationId");
|
||||
if (
|
||||
changedProps.has("automationId") &&
|
||||
this.automationId &&
|
||||
this.hass &&
|
||||
// Only refresh config if we picked a new automation. If same ID, don't fetch it.
|
||||
oldAutomationId !== this.automationId
|
||||
) {
|
||||
@@ -596,10 +585,10 @@ export class HaAutomationEditor extends AutomationScriptEditorMixin<AutomationCo
|
||||
}
|
||||
|
||||
if (
|
||||
(changedProps.has("automationId") ||
|
||||
shouldResetNewAutomationConfigFromQuery) &&
|
||||
changedProps.has("automationId") &&
|
||||
!this.automationId &&
|
||||
!this.entityId
|
||||
!this.entityId &&
|
||||
this.hass
|
||||
) {
|
||||
const initData = getAutomationEditorInitData();
|
||||
this.dirty = !!initData;
|
||||
|
||||
@@ -169,19 +169,15 @@ class HaAutomationPicker extends SubscribeMixin(LitElement) {
|
||||
private _filter = "";
|
||||
|
||||
@state()
|
||||
private _filters: DataTableFilters = {};
|
||||
|
||||
@storage({
|
||||
storage: "sessionStorage",
|
||||
key: "automation-table-filters-full",
|
||||
state: false,
|
||||
state: true,
|
||||
subscribe: false,
|
||||
serializer: serializeFilters,
|
||||
deserializer: deserializeFilters,
|
||||
})
|
||||
private _storageFilters: DataTableFilters = {};
|
||||
|
||||
private _fromUrl = false;
|
||||
private _filters: DataTableFilters = {};
|
||||
|
||||
@state() private _expandedFilter?: string;
|
||||
|
||||
@@ -764,23 +760,6 @@ class HaAutomationPicker extends SubscribeMixin(LitElement) {
|
||||
`;
|
||||
}
|
||||
|
||||
protected willUpdate(changedProps: PropertyValues) {
|
||||
super.willUpdate(changedProps);
|
||||
if (!this.hasUpdated) {
|
||||
const hasUrlFilter =
|
||||
this._searchParms.has("blueprint") || this._searchParms.has("label");
|
||||
if (!hasUrlFilter) {
|
||||
this._filters = this._storageFilters;
|
||||
}
|
||||
if (this._searchParms.has("blueprint")) {
|
||||
this._filterBlueprint();
|
||||
}
|
||||
if (this._searchParms.has("label")) {
|
||||
this._filterLabel();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected updated(changedProps: PropertyValues) {
|
||||
super.updated(changedProps);
|
||||
if (changedProps.has("_entityReg")) {
|
||||
@@ -788,6 +767,15 @@ class HaAutomationPicker extends SubscribeMixin(LitElement) {
|
||||
}
|
||||
}
|
||||
|
||||
firstUpdated() {
|
||||
if (this._searchParms.has("blueprint")) {
|
||||
this._filterBlueprint();
|
||||
}
|
||||
if (this._searchParms.has("label")) {
|
||||
this._filterLabel();
|
||||
}
|
||||
}
|
||||
|
||||
private _filterExpanded(ev) {
|
||||
if (ev.detail.expanded) {
|
||||
this._expandedFilter = ev.target.localName;
|
||||
@@ -805,9 +793,6 @@ class HaAutomationPicker extends SubscribeMixin(LitElement) {
|
||||
items: undefined,
|
||||
},
|
||||
};
|
||||
if (!this._fromUrl) {
|
||||
this._storageFilters = this._filters;
|
||||
}
|
||||
this._applyFilters();
|
||||
};
|
||||
|
||||
@@ -818,9 +803,6 @@ class HaAutomationPicker extends SubscribeMixin(LitElement) {
|
||||
private _filterChanged(ev) {
|
||||
const type = ev.target.localName;
|
||||
this._filters = { ...this._filters, [type]: ev.detail };
|
||||
if (!this._fromUrl) {
|
||||
this._storageFilters = this._filters;
|
||||
}
|
||||
this._applyFilters();
|
||||
}
|
||||
|
||||
@@ -876,7 +858,6 @@ class HaAutomationPicker extends SubscribeMixin(LitElement) {
|
||||
if (!label) {
|
||||
return;
|
||||
}
|
||||
this._fromUrl = true;
|
||||
this._filters = {
|
||||
...this._filters,
|
||||
"ha-filter-labels": {
|
||||
@@ -892,7 +873,6 @@ class HaAutomationPicker extends SubscribeMixin(LitElement) {
|
||||
if (!blueprint) {
|
||||
return;
|
||||
}
|
||||
this._fromUrl = true;
|
||||
const related = await findRelated(
|
||||
this.hass,
|
||||
"automation_blueprint",
|
||||
@@ -910,9 +890,6 @@ class HaAutomationPicker extends SubscribeMixin(LitElement) {
|
||||
|
||||
private _clearFilter() {
|
||||
this._filters = {};
|
||||
if (!this._fromUrl) {
|
||||
this._storageFilters = {};
|
||||
}
|
||||
this._applyFilters();
|
||||
}
|
||||
|
||||
|
||||
@@ -1,12 +1,8 @@
|
||||
import type { HassServiceTarget } from "home-assistant-js-websocket";
|
||||
import { fireEvent } from "../../../common/dom/fire_event";
|
||||
import type { HomeAssistant } from "../../../types";
|
||||
|
||||
export const PASTE_VALUE = "__paste__";
|
||||
|
||||
export const ADD_AUTOMATION_ELEMENT_QUERY_PARAM = "add_automation_element";
|
||||
export const ADD_AUTOMATION_ELEMENT_TARGET_PARAM = "target_entity_id";
|
||||
|
||||
export interface AddAutomationElementDialogParams {
|
||||
type: "trigger" | "condition" | "action";
|
||||
add: (key: string, target?: HassServiceTarget) => void;
|
||||
@@ -15,30 +11,13 @@ export interface AddAutomationElementDialogParams {
|
||||
}
|
||||
const loadDialog = () => import("./add-automation-element-dialog");
|
||||
|
||||
export const getAddAutomationElementTargetFromQuery = (
|
||||
states: HomeAssistant["states"],
|
||||
type: AddAutomationElementDialogParams["type"]
|
||||
): string | undefined => {
|
||||
const params = new URLSearchParams(window.location.search);
|
||||
const entityId = params.get(ADD_AUTOMATION_ELEMENT_TARGET_PARAM);
|
||||
|
||||
return params.get(ADD_AUTOMATION_ELEMENT_QUERY_PARAM) === type &&
|
||||
entityId &&
|
||||
states[entityId]
|
||||
? entityId
|
||||
: undefined;
|
||||
};
|
||||
|
||||
export const showAddAutomationElementDialog = (
|
||||
element: HTMLElement,
|
||||
dialogParams: AddAutomationElementDialogParams
|
||||
): void => {
|
||||
const params = new URLSearchParams(window.location.search);
|
||||
fireEvent(element, "show-dialog", {
|
||||
dialogTag: "add-automation-element-dialog",
|
||||
dialogImport: loadDialog,
|
||||
dialogParams,
|
||||
addHistory:
|
||||
params.get(ADD_AUTOMATION_ELEMENT_QUERY_PARAM) !== dialogParams.type,
|
||||
});
|
||||
};
|
||||
|
||||
@@ -25,7 +25,6 @@ import { isTriggerList, subscribeTriggers } from "../../../../data/trigger";
|
||||
import { SubscribeMixin } from "../../../../mixins/subscribe-mixin";
|
||||
import { EDITOR_SAVE_FAB_TOAST_BOTTOM_OFFSET } from "../editor-toast";
|
||||
import {
|
||||
getAddAutomationElementTargetFromQuery,
|
||||
PASTE_VALUE,
|
||||
showAddAutomationElementDialog,
|
||||
} from "../show-add-automation-element-dialog";
|
||||
@@ -53,8 +52,6 @@ export default class HaAutomationTrigger extends AutomationSortableListMixin<Tri
|
||||
|
||||
private _unsub?: Promise<UnsubscribeFunc>;
|
||||
|
||||
private _openedAddDialogFromQuery = false;
|
||||
|
||||
protected get items(): Trigger[] {
|
||||
return this.triggers;
|
||||
}
|
||||
@@ -238,32 +235,6 @@ export default class HaAutomationTrigger extends AutomationSortableListMixin<Tri
|
||||
protected updated(changedProps: PropertyValues<this>) {
|
||||
super.updated(changedProps);
|
||||
|
||||
if (!this.hass) {
|
||||
return;
|
||||
}
|
||||
|
||||
const addTriggerTargetFromQuery = getAddAutomationElementTargetFromQuery(
|
||||
this.hass.states,
|
||||
"trigger"
|
||||
);
|
||||
|
||||
if (changedProps.has("triggers") && addTriggerTargetFromQuery) {
|
||||
this._openedAddDialogFromQuery = false;
|
||||
}
|
||||
|
||||
if (
|
||||
!this._openedAddDialogFromQuery &&
|
||||
this.root &&
|
||||
!this.disabled &&
|
||||
this.triggers.length === 0 &&
|
||||
addTriggerTargetFromQuery
|
||||
) {
|
||||
this._openedAddDialogFromQuery = true;
|
||||
queueMicrotask(() => this._addTriggerDialog());
|
||||
} else if (this._openedAddDialogFromQuery && !addTriggerTargetFromQuery) {
|
||||
this._openedAddDialogFromQuery = false;
|
||||
}
|
||||
|
||||
if (
|
||||
changedProps.has("triggers") &&
|
||||
(this.focusLastItemOnChange || this.focusItemIndexOnChange !== undefined)
|
||||
|
||||
@@ -7,7 +7,7 @@ import {
|
||||
mdiPlus,
|
||||
mdiUpload,
|
||||
} from "@mdi/js";
|
||||
import type { CSSResultGroup, PropertyValues, TemplateResult } from "lit";
|
||||
import type { CSSResultGroup, TemplateResult } from "lit";
|
||||
import { css, html, LitElement, nothing } from "lit";
|
||||
import { customElement, property, query, state } from "lit/decorators";
|
||||
import memoizeOne from "memoize-one";
|
||||
@@ -104,17 +104,13 @@ class HaConfigBackupBackups extends SubscribeMixin(LitElement) {
|
||||
@state() private _selected: string[] = [];
|
||||
|
||||
@state()
|
||||
private _filters: DataTableFiltersValues = {};
|
||||
|
||||
@storage({
|
||||
storage: "sessionStorage",
|
||||
key: "backups-table-filters",
|
||||
state: false,
|
||||
state: true,
|
||||
subscribe: false,
|
||||
})
|
||||
private _storageFilters: DataTableFiltersValues = {};
|
||||
|
||||
private _fromUrl = false;
|
||||
private _filters: DataTableFiltersValues = {};
|
||||
|
||||
@storage({ key: "backups-table-grouping", state: false, subscribe: false })
|
||||
private _activeGrouping?: string = "formatted_type";
|
||||
@@ -135,18 +131,11 @@ class HaConfigBackupBackups extends SubscribeMixin(LitElement) {
|
||||
|
||||
private _overflowBackup?: BackupRow;
|
||||
|
||||
protected willUpdate(changedProps: PropertyValues) {
|
||||
super.willUpdate(changedProps);
|
||||
if (!this.hasUpdated) {
|
||||
this._filters = this._storageFilters;
|
||||
this._setFiltersFromUrl();
|
||||
}
|
||||
}
|
||||
|
||||
public connectedCallback() {
|
||||
super.connectedCallback();
|
||||
window.addEventListener("location-changed", this._locationChanged);
|
||||
window.addEventListener("popstate", this._popState);
|
||||
this._setFiltersFromUrl();
|
||||
}
|
||||
|
||||
disconnectedCallback(): void {
|
||||
@@ -579,23 +568,14 @@ class HaConfigBackupBackups extends SubscribeMixin(LitElement) {
|
||||
|
||||
private _typeFilterChanged(ev) {
|
||||
this._filters = { ...this._filters, [TYPE_FILTER]: ev.detail.value };
|
||||
if (!this._fromUrl) {
|
||||
this._storageFilters = this._filters;
|
||||
}
|
||||
}
|
||||
|
||||
private _locationsFilterChanged(ev) {
|
||||
this._filters = { ...this._filters, [LOCATIONS_FILTER]: ev.detail.value };
|
||||
if (!this._fromUrl) {
|
||||
this._storageFilters = this._filters;
|
||||
}
|
||||
}
|
||||
|
||||
private _clearFilter() {
|
||||
this._filters = {};
|
||||
if (!this._fromUrl) {
|
||||
this._storageFilters = {};
|
||||
}
|
||||
}
|
||||
|
||||
private _setFiltersFromUrl() {
|
||||
@@ -606,7 +586,6 @@ class HaConfigBackupBackups extends SubscribeMixin(LitElement) {
|
||||
return;
|
||||
}
|
||||
|
||||
this._fromUrl = true;
|
||||
this._filters = {
|
||||
[TYPE_FILTER]: type === "all" ? [] : [type],
|
||||
};
|
||||
|
||||
@@ -7,7 +7,7 @@ import type { DataTableColumnData } from "../../../components/data-table/ha-data
|
||||
import { slugify } from "../../../common/string/slugify";
|
||||
import { relativeTime } from "../../../common/datetime/relative_time";
|
||||
import { formatShortDateTimeWithConditionalYear } from "../../../common/datetime/format_date_time";
|
||||
import { UNAVAILABLE, UNKNOWN } from "../../../data/entity/entity";
|
||||
import { isUnavailableState } from "../../../data/entity/entity";
|
||||
import "../../../components/ha-tooltip";
|
||||
import "../../../components/ha-svg-icon";
|
||||
|
||||
@@ -146,11 +146,7 @@ export const renderRelativeTimeColumn = (
|
||||
localize: LocalizeFunc,
|
||||
hass: HomeAssistant
|
||||
) => {
|
||||
if (
|
||||
!valueRelativeTime ||
|
||||
valueRelativeTime === UNAVAILABLE ||
|
||||
valueRelativeTime === UNKNOWN
|
||||
) {
|
||||
if (!valueRelativeTime || isUnavailableState(valueRelativeTime)) {
|
||||
return localize("ui.components.relative_time.never");
|
||||
}
|
||||
const date = new Date(valueRelativeTime);
|
||||
|
||||
@@ -241,16 +241,13 @@ export class HaConfigHelpers extends SubscribeMixin(LitElement) {
|
||||
|
||||
@state() private _searchParms = new URLSearchParams(window.location.search);
|
||||
|
||||
@state()
|
||||
private _filters: DataTableFiltersValues = {};
|
||||
|
||||
@storage({
|
||||
storage: "sessionStorage",
|
||||
key: "helpers-table-filters",
|
||||
state: false,
|
||||
state: true,
|
||||
subscribe: false,
|
||||
})
|
||||
private _storageFilters: DataTableFiltersValues = {};
|
||||
private _filters: DataTableFiltersValues = {};
|
||||
|
||||
@state() private _filteredItems: DataTableFiltersItems = {};
|
||||
|
||||
@@ -822,9 +819,6 @@ export class HaConfigHelpers extends SubscribeMixin(LitElement) {
|
||||
|
||||
this._filters = { ...this._filters, [type]: ev.detail.value };
|
||||
this._filteredItems = { ...this._filteredItems, [type]: ev.detail.items };
|
||||
if (!this._fromUrl) {
|
||||
this._storageFilters = this._filters;
|
||||
}
|
||||
this._applyFilters();
|
||||
}
|
||||
|
||||
@@ -935,8 +929,6 @@ export class HaConfigHelpers extends SubscribeMixin(LitElement) {
|
||||
this._filteredHelperEntityIds = items ? [...items] : undefined;
|
||||
}
|
||||
|
||||
private _fromUrl = false;
|
||||
|
||||
public connectedCallback() {
|
||||
super.connectedCallback();
|
||||
window.addEventListener("location-changed", this._locationChanged);
|
||||
@@ -973,7 +965,6 @@ export class HaConfigHelpers extends SubscribeMixin(LitElement) {
|
||||
return;
|
||||
}
|
||||
|
||||
this._fromUrl = true;
|
||||
this._filter = history.state?.filter || "";
|
||||
|
||||
this._filters = {
|
||||
@@ -987,9 +978,6 @@ export class HaConfigHelpers extends SubscribeMixin(LitElement) {
|
||||
private _clearFilter() {
|
||||
this._filters = {};
|
||||
this._filteredItems = {};
|
||||
if (!this._fromUrl) {
|
||||
this._storageFilters = {};
|
||||
}
|
||||
this._applyFilters();
|
||||
}
|
||||
|
||||
@@ -1218,7 +1206,6 @@ ${rejected
|
||||
super.willUpdate(changedProps);
|
||||
|
||||
if (!this.hasUpdated) {
|
||||
this._filters = this._storageFilters;
|
||||
this._setFiltersFromUrl();
|
||||
}
|
||||
|
||||
@@ -1267,9 +1254,6 @@ ${rejected
|
||||
!this._helperEntities.every((val, idx) => newHelpers[idx] === val)
|
||||
) {
|
||||
this._helperEntities = newHelpers;
|
||||
if (Object.keys(this._filters).length > 0) {
|
||||
this._applyFilters();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -9,8 +9,8 @@ import { copyToClipboard } from "../../../common/util/copy-clipboard";
|
||||
import { subscribePollingCollection } from "../../../common/util/subscribe-polling";
|
||||
import "../../../components/ha-alert";
|
||||
import "../../../components/ha-button";
|
||||
import "../../../components/ha-dialog";
|
||||
import "../../../components/ha-dialog-footer";
|
||||
import "../../../components/ha-dialog";
|
||||
import "../../../components/ha-metric";
|
||||
import "../../../components/ha-spinner";
|
||||
import type { HassioStats } from "../../../data/hassio/common";
|
||||
@@ -103,10 +103,10 @@ class DialogSystemInformation extends LitElement {
|
||||
this.hass,
|
||||
async () => {
|
||||
this._supervisorStats = await fetchHassioStats(
|
||||
this.hass.callWS,
|
||||
this.hass,
|
||||
"supervisor"
|
||||
);
|
||||
this._coreStats = await fetchHassioStats(this.hass.callWS, "core");
|
||||
this._coreStats = await fetchHassioStats(this.hass, "core");
|
||||
},
|
||||
10000
|
||||
);
|
||||
|
||||
@@ -160,19 +160,15 @@ class HaSceneDashboard extends SubscribeMixin(LitElement) {
|
||||
private _filter = "";
|
||||
|
||||
@state()
|
||||
private _filters: DataTableFilters = {};
|
||||
|
||||
@storage({
|
||||
storage: "sessionStorage",
|
||||
key: "scene-table-filters-full",
|
||||
state: false,
|
||||
state: true,
|
||||
subscribe: false,
|
||||
serializer: serializeFilters,
|
||||
deserializer: deserializeFilters,
|
||||
})
|
||||
private _storageFilters: DataTableFilters = {};
|
||||
|
||||
private _fromUrl = false;
|
||||
private _filters: DataTableFilters = {};
|
||||
|
||||
@state() private _expandedFilter?: string;
|
||||
|
||||
@@ -407,16 +403,6 @@ class HaSceneDashboard extends SubscribeMixin(LitElement) {
|
||||
}
|
||||
);
|
||||
|
||||
protected willUpdate(changedProps: PropertyValues) {
|
||||
super.willUpdate(changedProps);
|
||||
if (!this.hasUpdated) {
|
||||
if (!this._searchParms.has("label")) {
|
||||
this._filters = this._storageFilters;
|
||||
}
|
||||
this._filterLabel();
|
||||
}
|
||||
}
|
||||
|
||||
protected updated(changedProps: PropertyValues) {
|
||||
super.updated(changedProps);
|
||||
if (changedProps.has("_entityReg")) {
|
||||
@@ -718,18 +704,12 @@ class HaSceneDashboard extends SubscribeMixin(LitElement) {
|
||||
items: undefined,
|
||||
},
|
||||
};
|
||||
if (!this._fromUrl) {
|
||||
this._storageFilters = this._filters;
|
||||
}
|
||||
this._applyFilters();
|
||||
};
|
||||
|
||||
private _filterChanged(ev) {
|
||||
const type = ev.target.localName;
|
||||
this._filters = { ...this._filters, [type]: ev.detail };
|
||||
if (!this._fromUrl) {
|
||||
this._storageFilters = this._filters;
|
||||
}
|
||||
this._applyFilters();
|
||||
}
|
||||
|
||||
@@ -779,18 +759,20 @@ class HaSceneDashboard extends SubscribeMixin(LitElement) {
|
||||
|
||||
private _clearFilter() {
|
||||
this._filters = {};
|
||||
if (!this._fromUrl) {
|
||||
this._storageFilters = {};
|
||||
}
|
||||
this._applyFilters();
|
||||
}
|
||||
|
||||
firstUpdated() {
|
||||
if (this._searchParms.has("label")) {
|
||||
this._filterLabel();
|
||||
}
|
||||
}
|
||||
|
||||
private _filterLabel() {
|
||||
const label = this._searchParms.get("label");
|
||||
if (!label) {
|
||||
return;
|
||||
}
|
||||
this._fromUrl = true;
|
||||
this._filters = {
|
||||
...this._filters,
|
||||
"ha-filter-labels": {
|
||||
|
||||
@@ -164,19 +164,15 @@ class HaScriptPicker extends SubscribeMixin(LitElement) {
|
||||
private _filter = "";
|
||||
|
||||
@state()
|
||||
private _filters: DataTableFilters = {};
|
||||
|
||||
@storage({
|
||||
storage: "sessionStorage",
|
||||
key: "script-table-filters-full",
|
||||
state: false,
|
||||
state: true,
|
||||
subscribe: false,
|
||||
serializer: serializeFilters,
|
||||
deserializer: deserializeFilters,
|
||||
})
|
||||
private _storageFilters: DataTableFilters = {};
|
||||
|
||||
private _fromUrl = false;
|
||||
private _filters: DataTableFilters = {};
|
||||
|
||||
@state() private _expandedFilter?: string;
|
||||
|
||||
@@ -711,26 +707,17 @@ class HaScriptPicker extends SubscribeMixin(LitElement) {
|
||||
items: undefined,
|
||||
},
|
||||
};
|
||||
if (!this._fromUrl) {
|
||||
this._storageFilters = this._filters;
|
||||
}
|
||||
this._applyFilters();
|
||||
};
|
||||
|
||||
private _filterChanged(ev) {
|
||||
const type = ev.target.localName;
|
||||
this._filters = { ...this._filters, [type]: ev.detail };
|
||||
if (!this._fromUrl) {
|
||||
this._storageFilters = this._filters;
|
||||
}
|
||||
this._applyFilters();
|
||||
}
|
||||
|
||||
private _clearFilter() {
|
||||
this._filters = {};
|
||||
if (!this._fromUrl) {
|
||||
this._storageFilters = {};
|
||||
}
|
||||
this._applyFilters();
|
||||
}
|
||||
|
||||
@@ -779,23 +766,6 @@ class HaScriptPicker extends SubscribeMixin(LitElement) {
|
||||
this._filteredEntityIds = filteredEntityIds;
|
||||
}
|
||||
|
||||
protected willUpdate(changedProps: PropertyValues) {
|
||||
super.willUpdate(changedProps);
|
||||
if (!this.hasUpdated) {
|
||||
const hasUrlFilter =
|
||||
this._searchParms.has("blueprint") || this._searchParms.has("label");
|
||||
if (!hasUrlFilter) {
|
||||
this._filters = this._storageFilters;
|
||||
}
|
||||
if (this._searchParms.has("blueprint")) {
|
||||
this._filterBlueprint();
|
||||
}
|
||||
if (this._searchParms.has("label")) {
|
||||
this._filterLabel();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected updated(changedProps: PropertyValues) {
|
||||
super.updated(changedProps);
|
||||
if (changedProps.has("_entityReg")) {
|
||||
@@ -803,12 +773,20 @@ class HaScriptPicker extends SubscribeMixin(LitElement) {
|
||||
}
|
||||
}
|
||||
|
||||
firstUpdated() {
|
||||
if (this._searchParms.has("blueprint")) {
|
||||
this._filterBlueprint();
|
||||
}
|
||||
if (this._searchParms.has("label")) {
|
||||
this._filterLabel();
|
||||
}
|
||||
}
|
||||
|
||||
private _filterLabel() {
|
||||
const label = this._searchParms.get("label");
|
||||
if (!label) {
|
||||
return;
|
||||
}
|
||||
this._fromUrl = true;
|
||||
this._filters = {
|
||||
...this._filters,
|
||||
"ha-filter-labels": {
|
||||
@@ -824,7 +802,6 @@ class HaScriptPicker extends SubscribeMixin(LitElement) {
|
||||
if (!blueprint) {
|
||||
return;
|
||||
}
|
||||
this._fromUrl = true;
|
||||
const related = await findRelated(this.hass, "script_blueprint", blueprint);
|
||||
this._filters = {
|
||||
...this._filters,
|
||||
|
||||
@@ -5,7 +5,6 @@ import { customElement, property, state } from "lit/decorators";
|
||||
import { styleMap } from "lit/directives/style-map";
|
||||
import memoizeOne from "memoize-one";
|
||||
import { computeDomain } from "../../../common/entity/compute_domain";
|
||||
import type { HASSDomEvent } from "../../../common/dom/fire_event";
|
||||
import { stateColorCss } from "../../../common/entity/state_color";
|
||||
import "../../../components/ha-control-button";
|
||||
import "../../../components/ha-control-button-group";
|
||||
@@ -102,11 +101,9 @@ class HuiAlarmModeCardFeature
|
||||
return supportedModes.find((mode) => mode === stateObj.state);
|
||||
});
|
||||
|
||||
private async _valueChanged(
|
||||
ev: HASSDomEvent<HASSDomEvents["value-changed"]>
|
||||
) {
|
||||
private async _valueChanged(ev: CustomEvent) {
|
||||
if (!this._stateObj) return;
|
||||
const mode = ev.detail.value as AlarmMode;
|
||||
const mode = (ev.detail as any).value as AlarmMode;
|
||||
|
||||
if (mode === this._stateObj.state) return;
|
||||
|
||||
|
||||
@@ -2,7 +2,6 @@ import { html, LitElement, nothing } from "lit";
|
||||
import { customElement, property, state } from "lit/decorators";
|
||||
import { styleMap } from "lit/directives/style-map";
|
||||
import { computeCssColor } from "../../../common/color/compute-color";
|
||||
import type { HASSDomEvent } from "../../../common/dom/fire_event";
|
||||
import { computeAttributeNameDisplay } from "../../../common/entity/compute_attribute_display";
|
||||
import { computeDomain } from "../../../common/entity/compute_domain";
|
||||
import { stateActive } from "../../../common/entity/state_active";
|
||||
@@ -116,9 +115,9 @@ class HuiCoverPositionCardFeature
|
||||
`;
|
||||
}
|
||||
|
||||
private _valueChanged(ev: HASSDomEvent<HASSDomEvents["value-changed"]>) {
|
||||
const { value } = ev.detail;
|
||||
if (typeof value !== "number" || isNaN(value)) return;
|
||||
private _valueChanged(ev: CustomEvent) {
|
||||
const value = (ev.detail as any).value;
|
||||
if (isNaN(value)) return;
|
||||
|
||||
this.hass!.callService("cover", "set_cover_position", {
|
||||
entity_id: this._stateObj!.entity_id,
|
||||
|
||||
@@ -2,7 +2,6 @@ import { css, html, LitElement, nothing } from "lit";
|
||||
import { customElement, property, state } from "lit/decorators";
|
||||
import { styleMap } from "lit/directives/style-map";
|
||||
import { computeCssColor } from "../../../common/color/compute-color";
|
||||
import type { HASSDomEvent } from "../../../common/dom/fire_event";
|
||||
import { computeAttributeNameDisplay } from "../../../common/entity/compute_attribute_display";
|
||||
import { computeDomain } from "../../../common/entity/compute_domain";
|
||||
import { stateColorCss } from "../../../common/entity/state_color";
|
||||
@@ -119,9 +118,9 @@ class HuiCoverTiltPositionCardFeature
|
||||
`;
|
||||
}
|
||||
|
||||
private _valueChanged(ev: HASSDomEvent<HASSDomEvents["value-changed"]>) {
|
||||
const { value } = ev.detail;
|
||||
if (typeof value !== "number" || isNaN(value)) return;
|
||||
private _valueChanged(ev: CustomEvent) {
|
||||
const value = (ev.detail as any).value;
|
||||
if (isNaN(value)) return;
|
||||
|
||||
this.hass!.callService("cover", "set_cover_tilt_position", {
|
||||
entity_id: this._stateObj!.entity_id,
|
||||
|
||||
@@ -4,7 +4,6 @@ import { LitElement, html } from "lit";
|
||||
import { customElement, property, state } from "lit/decorators";
|
||||
import { styleMap } from "lit/directives/style-map";
|
||||
import { computeDomain } from "../../../common/entity/compute_domain";
|
||||
import type { HASSDomEvent } from "../../../common/dom/fire_event";
|
||||
import { stateColorCss } from "../../../common/entity/state_color";
|
||||
import { supportsFeature } from "../../../common/entity/supports-feature";
|
||||
import "../../../components/ha-control-select";
|
||||
@@ -80,10 +79,8 @@ class HuiFanOscillateCardFeature
|
||||
}
|
||||
}
|
||||
|
||||
private async _valueChanged(
|
||||
ev: HASSDomEvent<HASSDomEvents["value-changed"]>
|
||||
) {
|
||||
const shouldOscillate = ev.detail.value === "yes";
|
||||
private async _valueChanged(ev: CustomEvent) {
|
||||
const shouldOscillate = (ev.detail as any).value === "yes";
|
||||
|
||||
if (shouldOscillate === this._stateObj!.attributes.oscillating) return;
|
||||
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import { css, html, LitElement, nothing } from "lit";
|
||||
import { customElement, property, state } from "lit/decorators";
|
||||
import { computeAttributeNameDisplay } from "../../../common/entity/compute_attribute_display";
|
||||
import type { HASSDomEvent } from "../../../common/dom/fire_event";
|
||||
import { computeDomain } from "../../../common/entity/compute_domain";
|
||||
import { stateActive } from "../../../common/entity/state_active";
|
||||
import { supportsFeature } from "../../../common/entity/supports-feature";
|
||||
@@ -145,8 +144,8 @@ class HuiFanSpeedCardFeature extends LitElement implements LovelaceCardFeature {
|
||||
`;
|
||||
}
|
||||
|
||||
private _speedValueChanged(ev: HASSDomEvent<HASSDomEvents["value-changed"]>) {
|
||||
const speed = ev.detail.value as FanSpeed;
|
||||
private _speedValueChanged(ev: CustomEvent) {
|
||||
const speed = (ev.detail as any).value as FanSpeed;
|
||||
|
||||
const percentage = fanSpeedToPercentage(this._stateObj!, speed);
|
||||
|
||||
@@ -156,9 +155,9 @@ class HuiFanSpeedCardFeature extends LitElement implements LovelaceCardFeature {
|
||||
});
|
||||
}
|
||||
|
||||
private _valueChanged(ev: HASSDomEvent<HASSDomEvents["value-changed"]>) {
|
||||
const { value } = ev.detail;
|
||||
if (typeof value !== "number" || isNaN(value)) return;
|
||||
private _valueChanged(ev: CustomEvent) {
|
||||
const value = (ev.detail as any).value;
|
||||
if (isNaN(value)) return;
|
||||
|
||||
this.hass!.callService("fan", "set_percentage", {
|
||||
entity_id: this._stateObj!.entity_id,
|
||||
|
||||
@@ -4,7 +4,6 @@ import { LitElement, html } from "lit";
|
||||
import { customElement, property, state } from "lit/decorators";
|
||||
import { styleMap } from "lit/directives/style-map";
|
||||
import { computeDomain } from "../../../common/entity/compute_domain";
|
||||
import type { HASSDomEvent } from "../../../common/dom/fire_event";
|
||||
import { stateColorCss } from "../../../common/entity/state_color";
|
||||
import "../../../components/ha-control-select";
|
||||
import type { ControlSelectOption } from "../../../components/ha-control-select";
|
||||
@@ -82,10 +81,8 @@ class HuiHumidifierToggleCardFeature
|
||||
}
|
||||
}
|
||||
|
||||
private async _valueChanged(
|
||||
ev: HASSDomEvent<HASSDomEvents["value-changed"]>
|
||||
) {
|
||||
const newState = ev.detail.value as HumidifierState;
|
||||
private async _valueChanged(ev: CustomEvent) {
|
||||
const newState = (ev.detail as any).value as HumidifierState;
|
||||
|
||||
if (newState === this._stateObj!.state) return;
|
||||
|
||||
|
||||
@@ -26,7 +26,7 @@ import { stateActive } from "../../../common/entity/state_active";
|
||||
import { supportsFeature } from "../../../common/entity/supports-feature";
|
||||
import "../../../components/ha-control-button";
|
||||
import "../../../components/ha-control-button-group";
|
||||
import { UNAVAILABLE } from "../../../data/entity/entity";
|
||||
import { isUnavailableState } from "../../../data/entity/entity";
|
||||
import type {
|
||||
ControlButton,
|
||||
MediaPlayerEntity,
|
||||
@@ -233,7 +233,7 @@ class HuiMediaPlayerPlaybackCardFeature
|
||||
case "turn_on":
|
||||
if (
|
||||
(!active || assumedState) &&
|
||||
stateObj.state !== UNAVAILABLE &&
|
||||
!isUnavailableState(stateObj.state) &&
|
||||
supportsFeature(stateObj, MediaPlayerEntityFeature.TURN_ON)
|
||||
) {
|
||||
buttons.push({
|
||||
|
||||
@@ -4,7 +4,7 @@ import { computeDomain } from "../../../common/entity/compute_domain";
|
||||
import { supportsFeature } from "../../../common/entity/supports-feature";
|
||||
import { clamp } from "../../../common/number/clamp";
|
||||
import "../../../components/ha-control-number-buttons";
|
||||
import { UNAVAILABLE } from "../../../data/entity/entity";
|
||||
import { isUnavailableState } from "../../../data/entity/entity";
|
||||
import {
|
||||
MediaPlayerEntityFeature,
|
||||
type MediaPlayerEntity,
|
||||
@@ -89,7 +89,7 @@ class HuiMediaPlayerVolumeButtonsCardFeature
|
||||
}
|
||||
|
||||
const stateObj = this._stateObj;
|
||||
const disabled = stateObj.state === UNAVAILABLE;
|
||||
const disabled = isUnavailableState(stateObj.state);
|
||||
|
||||
const position =
|
||||
stateObj.attributes.volume_level != null
|
||||
|
||||
@@ -4,7 +4,7 @@ import { computeDomain } from "../../../common/entity/compute_domain";
|
||||
import { stateActive } from "../../../common/entity/state_active";
|
||||
import { supportsFeature } from "../../../common/entity/supports-feature";
|
||||
import "../../../components/ha-control-slider";
|
||||
import { UNAVAILABLE } from "../../../data/entity/entity";
|
||||
import { isUnavailableState } from "../../../data/entity/entity";
|
||||
import {
|
||||
MediaPlayerEntityFeature,
|
||||
type MediaPlayerEntity,
|
||||
@@ -88,7 +88,7 @@ class HuiMediaPlayerVolumeSliderCardFeature
|
||||
}
|
||||
|
||||
const stateObj = this._stateObj;
|
||||
const disabled = stateObj.state === UNAVAILABLE;
|
||||
const disabled = isUnavailableState(stateObj.state);
|
||||
|
||||
const position =
|
||||
stateObj.attributes.volume_level != null
|
||||
|
||||
@@ -2,7 +2,6 @@ import type { PropertyValues } from "lit";
|
||||
import { html, LitElement, nothing } from "lit";
|
||||
import { customElement, property, state } from "lit/decorators";
|
||||
import { computeDomain } from "../../../common/entity/compute_domain";
|
||||
import type { HASSDomEvent } from "../../../common/dom/fire_event";
|
||||
import "../../../components/ha-control-slider";
|
||||
import { UNAVAILABLE } from "../../../data/entity/entity";
|
||||
import type { HumidifierEntity } from "../../../data/humidifier";
|
||||
@@ -85,9 +84,9 @@ class HuiTargetHumidityCardFeature
|
||||
return this._stateObj!.attributes.max_humidity ?? 100;
|
||||
}
|
||||
|
||||
private _valueChanged(ev: HASSDomEvent<HASSDomEvents["value-changed"]>) {
|
||||
const { value } = ev.detail;
|
||||
if (typeof value !== "number" || isNaN(value)) return;
|
||||
private _valueChanged(ev: CustomEvent) {
|
||||
const value = (ev.detail as any).value;
|
||||
if (isNaN(value)) return;
|
||||
this._targetHumidity = value;
|
||||
this._callService();
|
||||
}
|
||||
|
||||
@@ -3,7 +3,6 @@ import { html, LitElement, nothing } from "lit";
|
||||
import { customElement, property, state } from "lit/decorators";
|
||||
import { styleMap } from "lit/directives/style-map";
|
||||
import { UNIT_F } from "../../../common/const";
|
||||
import type { HASSDomEvent } from "../../../common/dom/fire_event";
|
||||
import { computeDomain } from "../../../common/entity/compute_domain";
|
||||
import { computeStateDomain } from "../../../common/entity/compute_state_domain";
|
||||
import { stateColorCss } from "../../../common/entity/state_color";
|
||||
@@ -122,13 +121,10 @@ class HuiTargetTemperatureCardFeature
|
||||
return this._stateObj!.attributes.max_temp;
|
||||
}
|
||||
|
||||
private async _valueChanged(
|
||||
ev: HASSDomEvent<HASSDomEvents["value-changed"]>
|
||||
) {
|
||||
const { value } = ev.detail;
|
||||
if (typeof value !== "number" || isNaN(value)) return;
|
||||
const target =
|
||||
(ev.currentTarget as HTMLElement & { target?: Target }).target ?? "value";
|
||||
private async _valueChanged(ev: CustomEvent) {
|
||||
const value = (ev.detail as any).value;
|
||||
if (isNaN(value)) return;
|
||||
const target = (ev.currentTarget as any).target ?? "value";
|
||||
|
||||
this._targetTemperature = {
|
||||
...this._targetTemperature,
|
||||
|
||||
@@ -2,7 +2,6 @@ import { html, LitElement, nothing } from "lit";
|
||||
import { customElement, property, state } from "lit/decorators";
|
||||
import { styleMap } from "lit/directives/style-map";
|
||||
import { computeCssColor } from "../../../common/color/compute-color";
|
||||
import type { HASSDomEvent } from "../../../common/dom/fire_event";
|
||||
import { computeAttributeNameDisplay } from "../../../common/entity/compute_attribute_display";
|
||||
import { computeDomain } from "../../../common/entity/compute_domain";
|
||||
import { stateActive } from "../../../common/entity/state_active";
|
||||
@@ -120,9 +119,9 @@ class HuiValvePositionCardFeature
|
||||
`;
|
||||
}
|
||||
|
||||
private _valueChanged(ev: HASSDomEvent<HASSDomEvents["value-changed"]>) {
|
||||
const { value } = ev.detail;
|
||||
if (typeof value !== "number" || isNaN(value)) return;
|
||||
private _valueChanged(ev: CustomEvent) {
|
||||
const value = (ev.detail as any).value;
|
||||
if (isNaN(value)) return;
|
||||
|
||||
this.hass!.callService("valve", "set_valve_position", {
|
||||
entity_id: this._stateObj!.entity_id,
|
||||
|
||||
@@ -32,7 +32,7 @@ import "../../../components/tile/ha-tile-badge";
|
||||
import "../../../components/tile/ha-tile-container";
|
||||
import "../../../components/tile/ha-tile-icon";
|
||||
import "../../../components/tile/ha-tile-info";
|
||||
import { UNAVAILABLE, UNKNOWN } from "../../../data/entity/entity";
|
||||
import { isUnavailableState } from "../../../data/entity/entity";
|
||||
import type { ActionHandlerEvent } from "../../../data/lovelace/action_handler";
|
||||
import type { HomeAssistant } from "../../../types";
|
||||
import "../card-features/hui-card-features";
|
||||
@@ -419,9 +419,7 @@ export class HuiAreaCard extends LitElement implements LovelaceCard {
|
||||
const stateObj = this.hass.states[area.temperature_entity_id] as
|
||||
| HassEntity
|
||||
| undefined;
|
||||
return !stateObj ||
|
||||
stateObj.state === UNAVAILABLE ||
|
||||
stateObj.state === UNKNOWN
|
||||
return !stateObj || isUnavailableState(stateObj.state)
|
||||
? ""
|
||||
: this.hass.formatEntityState(stateObj);
|
||||
}
|
||||
@@ -429,9 +427,7 @@ export class HuiAreaCard extends LitElement implements LovelaceCard {
|
||||
const stateObj = this.hass.states[area.humidity_entity_id] as
|
||||
| HassEntity
|
||||
| undefined;
|
||||
return !stateObj ||
|
||||
stateObj.state === UNAVAILABLE ||
|
||||
stateObj.state === UNKNOWN
|
||||
return !stateObj || isUnavailableState(stateObj.state)
|
||||
? ""
|
||||
: this.hass.formatEntityState(stateObj);
|
||||
}
|
||||
@@ -448,8 +444,7 @@ export class HuiAreaCard extends LitElement implements LovelaceCard {
|
||||
const stateObj = this.hass.states[entityId];
|
||||
if (
|
||||
stateObj &&
|
||||
stateObj.state !== UNAVAILABLE &&
|
||||
stateObj.state !== UNKNOWN &&
|
||||
!isUnavailableState(stateObj.state) &&
|
||||
isNumericState(stateObj) &&
|
||||
!isNaN(Number(stateObj.state))
|
||||
) {
|
||||
|
||||
@@ -4,13 +4,12 @@ import { customElement, property, state } from "lit/decorators";
|
||||
import { classMap } from "lit/directives/class-map";
|
||||
import { ifDefined } from "lit/directives/if-defined";
|
||||
import { applyThemesOnElement } from "../../../common/dom/apply_themes_on_element";
|
||||
import type { HASSDomCurrentTargetEvent } from "../../../common/dom/fire_event";
|
||||
import { computeDomain } from "../../../common/entity/compute_domain";
|
||||
import "../../../components/entity/state-badge";
|
||||
import "../../../components/ha-card";
|
||||
import "../../../components/ha-icon";
|
||||
import "../../../components/ha-relative-time";
|
||||
import { UNAVAILABLE, UNKNOWN } from "../../../data/entity/entity";
|
||||
import { isUnavailableState } from "../../../data/entity/entity";
|
||||
import type { ActionHandlerEvent } from "../../../data/lovelace/action_handler";
|
||||
import type {
|
||||
CallServiceActionConfig,
|
||||
@@ -294,8 +293,7 @@ export class HuiGlanceCard extends LitElement implements LovelaceCard {
|
||||
SENSOR_TIMESTAMP_DEVICE_CLASSES.includes(
|
||||
stateObj.attributes.device_class
|
||||
) &&
|
||||
stateObj.state !== UNAVAILABLE &&
|
||||
stateObj.state !== UNKNOWN
|
||||
!isUnavailableState(stateObj.state)
|
||||
? html`
|
||||
<hui-timestamp-display
|
||||
.hass=${this.hass}
|
||||
@@ -324,13 +322,8 @@ export class HuiGlanceCard extends LitElement implements LovelaceCard {
|
||||
`;
|
||||
}
|
||||
|
||||
private _handleAction(
|
||||
ev: HASSDomCurrentTargetEvent<
|
||||
HTMLElement & { config: GlanceConfigEntity }
|
||||
> &
|
||||
ActionHandlerEvent
|
||||
) {
|
||||
const { config } = ev.currentTarget;
|
||||
private _handleAction(ev: ActionHandlerEvent) {
|
||||
const config = (ev.currentTarget as any).config as GlanceConfigEntity;
|
||||
handleAction(this, this.hass!, config, ev.detail.action!);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@ import { stateColorBrightness } from "../../../common/entity/state_color";
|
||||
import "../../../components/ha-card";
|
||||
import "../../../components/ha-icon-button";
|
||||
import "../../../components/ha-state-icon";
|
||||
import { UNAVAILABLE, UNKNOWN } from "../../../data/entity/entity";
|
||||
import { UNAVAILABLE, isUnavailableState } from "../../../data/entity/entity";
|
||||
import type { LightEntity } from "../../../data/light";
|
||||
import { lightSupportsBrightness } from "../../../data/light";
|
||||
import type { ActionHandlerEvent } from "../../../data/lovelace/action_handler";
|
||||
@@ -113,7 +113,7 @@ export class HuiLightCard extends LitElement implements LovelaceCard {
|
||||
min="1"
|
||||
max="100"
|
||||
.value=${brightness}
|
||||
.disabled=${stateObj.state === UNAVAILABLE}
|
||||
.disabled=${isUnavailableState(stateObj.state)}
|
||||
@value-changing=${this._dragEvent}
|
||||
@value-changed=${this._setBrightness}
|
||||
style=${styleMap({
|
||||
@@ -128,7 +128,7 @@ export class HuiLightCard extends LitElement implements LovelaceCard {
|
||||
"state-on": stateObj.state === "on",
|
||||
"state-unavailable": stateObj.state === UNAVAILABLE,
|
||||
})}"
|
||||
.disabled=${stateObj.state === UNAVAILABLE}
|
||||
.disabled=${isUnavailableState(stateObj.state)}
|
||||
style=${styleMap({
|
||||
filter: this._computeBrightness(stateObj),
|
||||
color: this._computeColor(stateObj),
|
||||
@@ -149,7 +149,7 @@ export class HuiLightCard extends LitElement implements LovelaceCard {
|
||||
</div>
|
||||
|
||||
<div id="info" .title=${name}>
|
||||
${stateObj.state === UNAVAILABLE || stateObj.state === UNKNOWN
|
||||
${isUnavailableState(stateObj.state)
|
||||
? html` <div>${this.hass.formatEntityState(stateObj)}</div> `
|
||||
: html` <div class="brightness">%</div> `}
|
||||
${name}
|
||||
|
||||
@@ -21,7 +21,7 @@ import type { HaSlider } from "../../../components/ha-slider";
|
||||
import "../../../components/ha-state-icon";
|
||||
import { showJoinMediaPlayersDialog } from "../../../components/media-player/show-join-media-players-dialog";
|
||||
import { showMediaBrowserDialog } from "../../../components/media-player/show-media-browser-dialog";
|
||||
import { UNAVAILABLE, UNKNOWN } from "../../../data/entity/entity";
|
||||
import { isUnavailableState } from "../../../data/entity/entity";
|
||||
import type {
|
||||
MediaPickedEvent,
|
||||
MediaPlayerEntity,
|
||||
@@ -173,12 +173,9 @@ export class HuiMediaControlCard extends LitElement implements LovelaceCard {
|
||||
const entityState = stateObj.state;
|
||||
|
||||
const isOffState =
|
||||
!stateActive(stateObj) &&
|
||||
entityState !== UNAVAILABLE &&
|
||||
entityState !== UNKNOWN;
|
||||
!stateActive(stateObj) && !isUnavailableState(entityState);
|
||||
const isUnavailable =
|
||||
entityState === UNAVAILABLE ||
|
||||
entityState === UNKNOWN ||
|
||||
isUnavailableState(entityState) ||
|
||||
(isOffState &&
|
||||
!supportsFeature(stateObj, MediaPlayerEntityFeature.TURN_ON));
|
||||
const hasNoImage = !this._image;
|
||||
|
||||
@@ -45,7 +45,7 @@ import "../../../components/ha-sortable";
|
||||
import "../../../components/ha-svg-icon";
|
||||
import "../../../components/input/ha-input";
|
||||
import type { HaInput } from "../../../components/input/ha-input";
|
||||
import { UNAVAILABLE, UNKNOWN } from "../../../data/entity/entity";
|
||||
import { isUnavailableState } from "../../../data/entity/entity";
|
||||
import type { TodoItem } from "../../../data/todo";
|
||||
import {
|
||||
TodoItemStatus,
|
||||
@@ -383,8 +383,7 @@ export class HuiTodoListCard extends LitElement implements LovelaceCard {
|
||||
`;
|
||||
}
|
||||
|
||||
const unavailable =
|
||||
stateObj.state === UNAVAILABLE || stateObj.state === UNKNOWN;
|
||||
const unavailable = isUnavailableState(stateObj.state);
|
||||
|
||||
// Discard memoization when we rollover to a new day, so filters can be recalculated
|
||||
const memoTime = this._config.due_date_period
|
||||
|
||||
@@ -279,15 +279,14 @@ export class HuiActionEditor extends LitElement {
|
||||
});
|
||||
}
|
||||
|
||||
private _valueChanged(
|
||||
ev: InputEvent & { target: HaInput & { configValue?: string } }
|
||||
): void {
|
||||
private _valueChanged(ev: InputEvent): void {
|
||||
ev.stopPropagation();
|
||||
if (!this.hass) {
|
||||
return;
|
||||
}
|
||||
const { configValue } = ev.target;
|
||||
const value = ev.target.value ?? "";
|
||||
const target = ev.target! as HaInput;
|
||||
const configValue: string | undefined = (target as any).configValue;
|
||||
const value = target.value ?? "";
|
||||
if (this[`_${configValue}`] === value) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -8,7 +8,6 @@ import type { HomeAssistant } from "../../../types";
|
||||
import type { EntitiesCardEntityConfig } from "../cards/types";
|
||||
import { computeTooltip } from "../common/compute-tooltip";
|
||||
import { actionHandler } from "../common/directives/action-handler-directive";
|
||||
import type { HASSDomCurrentTargetEvent } from "../../../common/dom/fire_event";
|
||||
import { handleAction } from "../common/handle-action";
|
||||
import { hasAction } from "../common/has-action";
|
||||
import "../../../components/chips/ha-assist-chip";
|
||||
@@ -66,13 +65,9 @@ export class HuiButtonsBase extends LitElement {
|
||||
`;
|
||||
}
|
||||
|
||||
private _handleAction(
|
||||
ev: HASSDomCurrentTargetEvent<
|
||||
HTMLElement & { config: EntitiesCardEntityConfig }
|
||||
> &
|
||||
ActionHandlerEvent
|
||||
) {
|
||||
handleAction(this, this.hass, ev.currentTarget.config, ev.detail.action);
|
||||
private _handleAction(ev: ActionHandlerEvent) {
|
||||
const config = (ev.currentTarget as any).config as EntitiesCardEntityConfig;
|
||||
handleAction(this, this.hass, config, ev.detail.action!);
|
||||
}
|
||||
|
||||
static get styles(): CSSResultGroup {
|
||||
|
||||
@@ -13,7 +13,7 @@ import { stringCompare } from "../../../../common/string/compare";
|
||||
import "../../../../components/ha-spinner";
|
||||
import "../../../../components/input/ha-input-search";
|
||||
import type { HaInputSearch } from "../../../../components/input/ha-input-search";
|
||||
import { UNAVAILABLE, UNKNOWN } from "../../../../data/entity/entity";
|
||||
import { isUnavailableState } from "../../../../data/entity/entity";
|
||||
import type { LovelaceBadgeConfig } from "../../../../data/lovelace/config/badge";
|
||||
import type { LovelaceConfig } from "../../../../data/lovelace/config/types";
|
||||
import type { CustomBadgeEntry } from "../../../../data/lovelace_custom_cards";
|
||||
@@ -235,14 +235,12 @@ export class HuiBadgePicker extends LitElement {
|
||||
this._usedEntities = [...usedEntities].filter(
|
||||
(eid) =>
|
||||
this.hass!.states[eid] &&
|
||||
this.hass!.states[eid].state !== UNAVAILABLE &&
|
||||
this.hass!.states[eid].state !== UNKNOWN
|
||||
!isUnavailableState(this.hass!.states[eid].state)
|
||||
);
|
||||
this._unusedEntities = [...unusedEntities].filter(
|
||||
(eid) =>
|
||||
this.hass!.states[eid] &&
|
||||
this.hass!.states[eid].state !== UNAVAILABLE &&
|
||||
this.hass!.states[eid].state !== UNKNOWN
|
||||
!isUnavailableState(this.hass!.states[eid].state)
|
||||
);
|
||||
|
||||
this._loadBages();
|
||||
|
||||
@@ -13,7 +13,7 @@ import "../../../../components/ha-expansion-panel";
|
||||
import "../../../../components/ha-spinner";
|
||||
import "../../../../components/input/ha-input-search";
|
||||
import type { HaInputSearch } from "../../../../components/input/ha-input-search";
|
||||
import { UNAVAILABLE, UNKNOWN } from "../../../../data/entity/entity";
|
||||
import { isUnavailableState } from "../../../../data/entity/entity";
|
||||
import type { LovelaceCardConfig } from "../../../../data/lovelace/config/card";
|
||||
import type { LovelaceConfig } from "../../../../data/lovelace/config/types";
|
||||
import type { CustomCardEntry } from "../../../../data/lovelace_custom_cards";
|
||||
@@ -270,14 +270,12 @@ export class HuiCardPicker extends LitElement {
|
||||
this._usedEntities = [...usedEntities].filter(
|
||||
(eid) =>
|
||||
this.hass!.states[eid] &&
|
||||
this.hass!.states[eid].state !== UNAVAILABLE &&
|
||||
this.hass!.states[eid].state !== UNKNOWN
|
||||
!isUnavailableState(this.hass!.states[eid].state)
|
||||
);
|
||||
this._unusedEntities = [...unusedEntities].filter(
|
||||
(eid) =>
|
||||
this.hass!.states[eid] &&
|
||||
this.hass!.states[eid].state !== UNAVAILABLE &&
|
||||
this.hass!.states[eid].state !== UNKNOWN
|
||||
!isUnavailableState(this.hass!.states[eid].state)
|
||||
);
|
||||
|
||||
this._loadCards();
|
||||
|
||||
@@ -73,11 +73,11 @@ function computeBreakpointsKey(breakpoints) {
|
||||
}
|
||||
|
||||
// Compute all possible media queries from each breakpoints combination (2 ^ breakpoints = 16)
|
||||
const queries = getAllCombinations<Breakpoint>(BREAKPOINTS)
|
||||
const queries = getAllCombinations(BREAKPOINTS as unknown as Breakpoint[])
|
||||
.filter((arr) => arr.length !== 0)
|
||||
.map(
|
||||
(breakpoints) =>
|
||||
[breakpoints, computeBreakpointsSize(breakpoints)] satisfies [
|
||||
[breakpoints, computeBreakpointsSize(breakpoints)] as [
|
||||
Breakpoint[],
|
||||
string,
|
||||
]
|
||||
|
||||
@@ -69,7 +69,7 @@ export class HuiAreaControlsCardFeatureEditor
|
||||
return [];
|
||||
}
|
||||
const controlEntities = getAreaControlEntities(
|
||||
AREA_CONTROL_DOMAINS,
|
||||
AREA_CONTROL_DOMAINS as unknown as AreaControlDomain[],
|
||||
areaId,
|
||||
excludeEntities,
|
||||
this.hass!
|
||||
|
||||
@@ -111,7 +111,7 @@ export abstract class HuiElementEditor<
|
||||
|
||||
this.updateComplete.then(() => {
|
||||
fireEvent(this, "config-changed", {
|
||||
config: this.value!,
|
||||
config: this.value! as any,
|
||||
error: this._errors?.join(", "),
|
||||
guiModeAvailable: !(
|
||||
this.hasWarning ||
|
||||
|
||||
@@ -27,7 +27,7 @@ export class HuiViewBackgroundEditor extends LitElement {
|
||||
}
|
||||
|
||||
private _localizeValueCallback = (key: string) =>
|
||||
this.hass.localize(key as Parameters<LocalizeFunc>[0]);
|
||||
this.hass.localize(key as any);
|
||||
|
||||
private _schema = memoizeOne(
|
||||
(localize: LocalizeFunc, showSettings: boolean) =>
|
||||
|
||||
@@ -203,7 +203,8 @@ export class HuiViewEditor extends LitElement {
|
||||
}
|
||||
|
||||
private _computeError = (error: string) =>
|
||||
this.hass.localize(`ui.panel.lovelace.editor.edit_view.${error}`) || error;
|
||||
this.hass.localize(`ui.panel.lovelace.editor.edit_view.${error}` as any) ||
|
||||
error;
|
||||
|
||||
private _computeLabel = (
|
||||
schema: SchemaUnion<ReturnType<typeof this._schema>>
|
||||
|
||||
@@ -5,7 +5,7 @@ import { customElement, property, state } from "lit/decorators";
|
||||
import { ifDefined } from "lit/directives/if-defined";
|
||||
import { computeStateName } from "../../../common/entity/compute_state_name";
|
||||
import "../../../components/entity/ha-state-label-badge";
|
||||
import { UNAVAILABLE, UNKNOWN } from "../../../data/entity/entity";
|
||||
import { isUnavailableState } from "../../../data/entity/entity";
|
||||
import type { ActionHandlerEvent } from "../../../data/lovelace/action_handler";
|
||||
import type { HomeAssistant } from "../../../types";
|
||||
import { actionHandler } from "../common/directives/action-handler-directive";
|
||||
@@ -36,7 +36,7 @@ export class HuiStateBadgeElement
|
||||
const includeDomains = ["light", "switch", "sensor"];
|
||||
const maxEntities = 1;
|
||||
const entityFilter = (stateObj: HassEntity): boolean =>
|
||||
stateObj.state !== UNAVAILABLE && stateObj.state !== UNKNOWN;
|
||||
!isUnavailableState(stateObj.state);
|
||||
const foundEntities = findEntities(
|
||||
hass,
|
||||
maxEntities,
|
||||
|
||||
@@ -4,7 +4,7 @@ import { css, html, LitElement, nothing } from "lit";
|
||||
import { customElement, property, state } from "lit/decorators";
|
||||
import { ifDefined } from "lit/directives/if-defined";
|
||||
import "../../../components/entity/state-badge";
|
||||
import { UNAVAILABLE, UNKNOWN } from "../../../data/entity/entity";
|
||||
import { isUnavailableState } from "../../../data/entity/entity";
|
||||
import type { ActionHandlerEvent } from "../../../data/lovelace/action_handler";
|
||||
import type { HomeAssistant } from "../../../types";
|
||||
import { computeTooltip } from "../common/compute-tooltip";
|
||||
@@ -33,7 +33,7 @@ export class HuiStateIconElement extends LitElement implements LovelaceElement {
|
||||
const includeDomains = ["light", "switch", "sensor"];
|
||||
const maxEntities = 1;
|
||||
const entityFilter = (stateObj: HassEntity): boolean =>
|
||||
stateObj.state !== UNAVAILABLE && stateObj.state !== UNKNOWN;
|
||||
!isUnavailableState(stateObj.state);
|
||||
const foundEntities = findEntities(
|
||||
hass,
|
||||
maxEntities,
|
||||
|
||||
@@ -3,7 +3,7 @@ import type { PropertyValues } from "lit";
|
||||
import { LitElement, css, html, nothing } from "lit";
|
||||
import { customElement, property, state } from "lit/decorators";
|
||||
import { ifDefined } from "lit/directives/if-defined";
|
||||
import { UNAVAILABLE, UNKNOWN } from "../../../data/entity/entity";
|
||||
import { isUnavailableState } from "../../../data/entity/entity";
|
||||
import type { ActionHandlerEvent } from "../../../data/lovelace/action_handler";
|
||||
import type { HomeAssistant } from "../../../types";
|
||||
import { computeTooltip } from "../common/compute-tooltip";
|
||||
@@ -32,7 +32,7 @@ class HuiStateLabelElement extends LitElement implements LovelaceElement {
|
||||
const includeDomains = ["light", "switch", "sensor"];
|
||||
const maxEntities = 1;
|
||||
const entityFilter = (stateObj: HassEntity): boolean =>
|
||||
stateObj.state !== UNAVAILABLE && stateObj.state !== UNKNOWN;
|
||||
!isUnavailableState(stateObj.state);
|
||||
const foundEntities = findEntities(
|
||||
hass,
|
||||
maxEntities,
|
||||
|
||||
@@ -3,7 +3,7 @@ import { css, html, LitElement, nothing } from "lit";
|
||||
import { customElement, property, state } from "lit/decorators";
|
||||
import "../../../components/ha-date-input";
|
||||
import { setDateValue } from "../../../data/date";
|
||||
import { UNAVAILABLE, UNKNOWN } from "../../../data/entity/entity";
|
||||
import { isUnavailableState, UNAVAILABLE } from "../../../data/entity/entity";
|
||||
import type { HomeAssistant, ValueChangedEvent } from "../../../types";
|
||||
import { hasConfigOrEntityChanged } from "../common/has-changed";
|
||||
import "../components/hui-generic-entity-row";
|
||||
@@ -49,7 +49,7 @@ class HuiDateEntityRow extends LitElement implements LovelaceRow {
|
||||
<ha-date-input
|
||||
.locale=${this.hass.locale}
|
||||
.disabled=${unavailable}
|
||||
.value=${stateObj.state === UNAVAILABLE || stateObj.state === UNKNOWN
|
||||
.value=${isUnavailableState(stateObj.state)
|
||||
? undefined
|
||||
: stateObj.state}
|
||||
@value-changed=${this._dateChanged}
|
||||
|
||||
@@ -5,7 +5,7 @@ import { customElement, property, state } from "lit/decorators";
|
||||
import "../../../components/ha-date-input";
|
||||
import "../../../components/ha-time-input";
|
||||
import { setDateTimeValue } from "../../../data/datetime";
|
||||
import { UNAVAILABLE, UNKNOWN } from "../../../data/entity/entity";
|
||||
import { isUnavailableState, UNAVAILABLE } from "../../../data/entity/entity";
|
||||
import type { HomeAssistant, ValueChangedEvent } from "../../../types";
|
||||
import { hasConfigOrEntityChanged } from "../common/has-changed";
|
||||
import "../components/hui-generic-entity-row";
|
||||
@@ -46,10 +46,9 @@ class HuiInputDatetimeEntityRow extends LitElement implements LovelaceRow {
|
||||
|
||||
const unavailable = stateObj.state === UNAVAILABLE;
|
||||
|
||||
const dateObj =
|
||||
stateObj.state === UNAVAILABLE || stateObj.state === UNKNOWN
|
||||
? undefined
|
||||
: new Date(stateObj.state);
|
||||
const dateObj = isUnavailableState(stateObj.state)
|
||||
? undefined
|
||||
: new Date(stateObj.state);
|
||||
const time = dateObj ? format(dateObj, "HH:mm:ss") : undefined;
|
||||
const date = dateObj ? format(dateObj, "yyyy-MM-dd") : undefined;
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import type { PropertyValues } from "lit";
|
||||
import { LitElement, css, html, nothing } from "lit";
|
||||
import { customElement, property, state } from "lit/decorators";
|
||||
import { UNAVAILABLE, UNKNOWN } from "../../../data/entity/entity";
|
||||
import { isUnavailableState } from "../../../data/entity/entity";
|
||||
import type { ActionHandlerEvent } from "../../../data/lovelace/action_handler";
|
||||
import type { HomeAssistant } from "../../../types";
|
||||
import type { EntitiesCardEntityConfig } from "../cards/types";
|
||||
@@ -51,9 +51,6 @@ class HuiEventEntityRow extends LitElement implements LovelaceRow {
|
||||
`;
|
||||
}
|
||||
|
||||
const noValue =
|
||||
stateObj.state === UNAVAILABLE || stateObj.state === UNKNOWN;
|
||||
|
||||
return html`
|
||||
<hui-generic-entity-row
|
||||
.hass=${this.hass}
|
||||
@@ -68,7 +65,7 @@ class HuiEventEntityRow extends LitElement implements LovelaceRow {
|
||||
})}
|
||||
>
|
||||
<div class="when">
|
||||
${noValue
|
||||
${isUnavailableState(stateObj.state)
|
||||
? this.hass.formatEntityState(stateObj)
|
||||
: html`<hui-timestamp-display
|
||||
.hass=${this.hass}
|
||||
@@ -78,7 +75,7 @@ class HuiEventEntityRow extends LitElement implements LovelaceRow {
|
||||
></hui-timestamp-display>`}
|
||||
</div>
|
||||
<div class="what">
|
||||
${noValue
|
||||
${isUnavailableState(stateObj.state)
|
||||
? nothing
|
||||
: this.hass.formatEntityAttributeValue(stateObj, "event_type")}
|
||||
</div>
|
||||
|
||||
@@ -3,7 +3,7 @@ import { css, html, LitElement, nothing } from "lit";
|
||||
import { customElement, property, state } from "lit/decorators";
|
||||
import "../../../components/input/ha-input";
|
||||
import type { HaInput } from "../../../components/input/ha-input";
|
||||
import { UNAVAILABLE, UNKNOWN } from "../../../data/entity/entity";
|
||||
import { isUnavailableState, UNAVAILABLE } from "../../../data/entity/entity";
|
||||
import { setValue } from "../../../data/input_text";
|
||||
import type { HomeAssistant } from "../../../types";
|
||||
import { hasConfigOrEntityChanged } from "../common/has-changed";
|
||||
@@ -74,7 +74,7 @@ class HuiInputTextEntityRow extends LitElement implements LovelaceRow {
|
||||
const newValue = target.value ?? "";
|
||||
|
||||
// Filter out invalid text states
|
||||
if (newValue && (newValue === UNAVAILABLE || newValue === UNKNOWN)) {
|
||||
if (newValue && isUnavailableState(newValue)) {
|
||||
target.value = stateObj.state;
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@ import type { PropertyValues } from "lit";
|
||||
import { css, html, LitElement, nothing } from "lit";
|
||||
import { customElement, property, state } from "lit/decorators";
|
||||
import "../../../components/ha-button";
|
||||
import { UNAVAILABLE } from "../../../data/entity/entity";
|
||||
import { isUnavailableState } from "../../../data/entity/entity";
|
||||
import { callProtectedLockService } from "../../../data/lock";
|
||||
import type { HomeAssistant } from "../../../types";
|
||||
import { confirmAction } from "../common/confirm-action";
|
||||
@@ -49,7 +49,7 @@ class HuiLockEntityRow extends LitElement implements LovelaceRow {
|
||||
appearance="plain"
|
||||
size="small"
|
||||
@click=${this._callService}
|
||||
.disabled=${stateObj.state === UNAVAILABLE}
|
||||
.disabled=${isUnavailableState(stateObj.state)}
|
||||
class="text-content"
|
||||
>
|
||||
${stateObj.state === "locked"
|
||||
|
||||
@@ -2,7 +2,7 @@ import type { PropertyValues } from "lit";
|
||||
import { css, html, LitElement, nothing } from "lit";
|
||||
import { customElement, property, state } from "lit/decorators";
|
||||
import "../../../components/ha-button";
|
||||
import { UNAVAILABLE } from "../../../data/entity/entity";
|
||||
import { isUnavailableState } from "../../../data/entity/entity";
|
||||
import type { ScriptEntity } from "../../../data/script";
|
||||
import { canRun, hasScriptFields } from "../../../data/script";
|
||||
import { showMoreInfoDialog } from "../../../dialogs/more-info/show-ha-more-info-dialog";
|
||||
@@ -68,7 +68,8 @@ class HuiScriptEntityRow extends LitElement implements LovelaceRow {
|
||||
appearance="plain"
|
||||
size="small"
|
||||
@click=${this._runScript}
|
||||
.disabled=${stateObj.state === UNAVAILABLE || !canRun(stateObj)}
|
||||
.disabled=${isUnavailableState(stateObj.state) ||
|
||||
!canRun(stateObj)}
|
||||
>
|
||||
${this._config.action_name ||
|
||||
this.hass!.localize("ui.card.script.run")}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import type { PropertyValues } from "lit";
|
||||
import { LitElement, html, nothing } from "lit";
|
||||
import { customElement, property, state } from "lit/decorators";
|
||||
import { UNAVAILABLE, UNKNOWN } from "../../../data/entity/entity";
|
||||
import { isUnavailableState } from "../../../data/entity/entity";
|
||||
import {
|
||||
SENSOR_DEVICE_CLASS_UPTIME,
|
||||
SENSOR_TIMESTAMP_DEVICE_CLASSES,
|
||||
@@ -55,9 +55,7 @@ class HuiSensorEntityRow extends LitElement implements LovelaceRow {
|
||||
<hui-generic-entity-row .hass=${this.hass} .config=${this._config}>
|
||||
${SENSOR_TIMESTAMP_DEVICE_CLASSES.includes(
|
||||
stateObj.attributes.device_class
|
||||
) &&
|
||||
stateObj.state !== UNAVAILABLE &&
|
||||
stateObj.state !== UNKNOWN
|
||||
) && !isUnavailableState(stateObj.state)
|
||||
? html`
|
||||
<hui-timestamp-display
|
||||
.hass=${this.hass}
|
||||
|
||||
@@ -3,7 +3,7 @@ import { css, html, LitElement, nothing } from "lit";
|
||||
import { customElement, property, state } from "lit/decorators";
|
||||
import "../../../components/input/ha-input";
|
||||
import type { HaInput } from "../../../components/input/ha-input";
|
||||
import { UNAVAILABLE, UNKNOWN } from "../../../data/entity/entity";
|
||||
import { isUnavailableState, UNAVAILABLE } from "../../../data/entity/entity";
|
||||
import type { TextEntity } from "../../../data/text";
|
||||
import { setValue } from "../../../data/text";
|
||||
import type { HomeAssistant } from "../../../types";
|
||||
@@ -76,7 +76,7 @@ class HuiTextEntityRow extends LitElement implements LovelaceRow {
|
||||
const newValue = target.value ?? "";
|
||||
|
||||
// Filter out invalid text states
|
||||
if (newValue && (newValue === UNAVAILABLE || newValue === UNKNOWN)) {
|
||||
if (newValue && isUnavailableState(newValue)) {
|
||||
target.value = stateObj.state;
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@ import { html, LitElement, nothing } from "lit";
|
||||
import { customElement, property, state } from "lit/decorators";
|
||||
import "../../../components/ha-date-input";
|
||||
import "../../../components/ha-time-input";
|
||||
import { UNAVAILABLE, UNKNOWN } from "../../../data/entity/entity";
|
||||
import { isUnavailableState, UNAVAILABLE } from "../../../data/entity/entity";
|
||||
import { setTimeValue } from "../../../data/time";
|
||||
import type { HomeAssistant, ValueChangedEvent } from "../../../types";
|
||||
import { hasConfigOrEntityChanged } from "../common/has-changed";
|
||||
@@ -48,7 +48,7 @@ class HuiTimeEntityRow extends LitElement implements LovelaceRow {
|
||||
return html`
|
||||
<hui-generic-entity-row .hass=${this.hass} .config=${this._config}>
|
||||
<ha-time-input
|
||||
.value=${stateObj.state === UNAVAILABLE || stateObj.state === UNKNOWN
|
||||
.value=${isUnavailableState(stateObj.state)
|
||||
? undefined
|
||||
: stateObj.state}
|
||||
.locale=${this.hass.locale}
|
||||
|
||||
@@ -2,7 +2,7 @@ import type { PropertyValues } from "lit";
|
||||
import { LitElement, html, nothing } from "lit";
|
||||
import { customElement, property, state } from "lit/decorators";
|
||||
import "../../../components/entity/ha-entity-toggle";
|
||||
import { UNAVAILABLE, UNKNOWN } from "../../../data/entity/entity";
|
||||
import { isUnavailableState } from "../../../data/entity/entity";
|
||||
import type { HomeAssistant } from "../../../types";
|
||||
import { hasConfigOrEntityChanged } from "../common/has-changed";
|
||||
import "../components/hui-generic-entity-row";
|
||||
@@ -44,8 +44,7 @@ class HuiToggleEntityRow extends LitElement implements LovelaceRow {
|
||||
const showToggle =
|
||||
stateObj.state === "on" ||
|
||||
stateObj.state === "off" ||
|
||||
stateObj.state === UNAVAILABLE ||
|
||||
stateObj.state === UNKNOWN;
|
||||
isUnavailableState(stateObj.state);
|
||||
|
||||
return html`
|
||||
<hui-generic-entity-row
|
||||
|
||||
@@ -2,7 +2,7 @@ import type { PropertyValues } from "lit";
|
||||
import { LitElement, html, nothing } from "lit";
|
||||
import { customElement, property, state } from "lit/decorators";
|
||||
import "../../../components/entity/ha-entity-toggle";
|
||||
import { UNAVAILABLE, UNKNOWN } from "../../../data/entity/entity";
|
||||
import { isUnavailableState } from "../../../data/entity/entity";
|
||||
import type { HomeAssistant } from "../../../types";
|
||||
import { hasConfigOrEntityChanged } from "../common/has-changed";
|
||||
import "../components/hui-generic-entity-row";
|
||||
@@ -44,8 +44,7 @@ class HuiValveEntityRow extends LitElement implements LovelaceRow {
|
||||
const showToggle =
|
||||
stateObj.state === "open" ||
|
||||
stateObj.state === "closed" ||
|
||||
stateObj.state === UNAVAILABLE ||
|
||||
stateObj.state === UNKNOWN;
|
||||
isUnavailableState(stateObj.state);
|
||||
|
||||
return html`
|
||||
<hui-generic-entity-row
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user