mirror of
https://github.com/home-assistant/frontend.git
synced 2025-07-25 18:26:35 +00:00
20221002.0 (#13953)
This commit is contained in:
commit
e84b9b7c6f
@ -36,6 +36,7 @@ const conditions = [
|
|||||||
{ condition: "sun", after: "sunset" },
|
{ condition: "sun", after: "sunset" },
|
||||||
{ condition: "sun", after: "sunrise", offset: "-01:00" },
|
{ condition: "sun", after: "sunrise", offset: "-01:00" },
|
||||||
{ condition: "zone", entity_id: "device_tracker.person", zone: "zone.home" },
|
{ condition: "zone", entity_id: "device_tracker.person", zone: "zone.home" },
|
||||||
|
{ condition: "trigger", id: "motion" },
|
||||||
{ condition: "time" },
|
{ condition: "time" },
|
||||||
{ condition: "template" },
|
{ condition: "template" },
|
||||||
];
|
];
|
||||||
|
@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|||||||
|
|
||||||
[project]
|
[project]
|
||||||
name = "home-assistant-frontend"
|
name = "home-assistant-frontend"
|
||||||
version = "20220929.0"
|
version = "20221002.0"
|
||||||
license = {text = "Apache-2.0"}
|
license = {text = "Apache-2.0"}
|
||||||
description = "The Home Assistant frontend"
|
description = "The Home Assistant frontend"
|
||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
|
@ -21,6 +21,7 @@ import {
|
|||||||
numberFormatToLocale,
|
numberFormatToLocale,
|
||||||
} from "../../common/number/format_number";
|
} from "../../common/number/format_number";
|
||||||
import {
|
import {
|
||||||
|
getDisplayUnit,
|
||||||
getStatisticLabel,
|
getStatisticLabel,
|
||||||
getStatisticMetadata,
|
getStatisticMetadata,
|
||||||
Statistics,
|
Statistics,
|
||||||
@ -258,8 +259,11 @@ class StatisticsChart extends LitElement {
|
|||||||
|
|
||||||
if (!this.unit) {
|
if (!this.unit) {
|
||||||
if (unit === undefined) {
|
if (unit === undefined) {
|
||||||
unit = meta?.display_unit_of_measurement;
|
unit = getDisplayUnit(this.hass, firstStat.statistic_id, meta);
|
||||||
} else if (unit !== meta?.display_unit_of_measurement) {
|
} else if (
|
||||||
|
unit !== getDisplayUnit(this.hass, firstStat.statistic_id, meta)
|
||||||
|
) {
|
||||||
|
// Clear unit if not all statistics have same unit
|
||||||
unit = null;
|
unit = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,9 +5,12 @@ import { customElement, property, query, state } from "lit/decorators";
|
|||||||
import memoizeOne from "memoize-one";
|
import memoizeOne from "memoize-one";
|
||||||
import { ensureArray } from "../../common/ensure-array";
|
import { ensureArray } from "../../common/ensure-array";
|
||||||
import { fireEvent } from "../../common/dom/fire_event";
|
import { fireEvent } from "../../common/dom/fire_event";
|
||||||
import { computeStateName } from "../../common/entity/compute_state_name";
|
|
||||||
import { stringCompare } from "../../common/string/compare";
|
import { stringCompare } from "../../common/string/compare";
|
||||||
import { getStatisticIds, StatisticsMetaData } from "../../data/recorder";
|
import {
|
||||||
|
getStatisticIds,
|
||||||
|
getStatisticLabel,
|
||||||
|
StatisticsMetaData,
|
||||||
|
} from "../../data/recorder";
|
||||||
import { PolymerChangedEvent } from "../../polymer-types";
|
import { PolymerChangedEvent } from "../../polymer-types";
|
||||||
import { HomeAssistant } from "../../types";
|
import { HomeAssistant } from "../../types";
|
||||||
import { documentationUrl } from "../../util/documentation-url";
|
import { documentationUrl } from "../../util/documentation-url";
|
||||||
@ -43,18 +46,11 @@ export class HaStatisticPicker extends LitElement {
|
|||||||
public includeStatisticsUnitOfMeasurement?: string | string[];
|
public includeStatisticsUnitOfMeasurement?: string | string[];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Show only statistics displayed with these units of measurements.
|
* Show only statistics with these unit classes.
|
||||||
* @attr include-display-unit-of-measurement
|
* @attr include-unit-class
|
||||||
*/
|
*/
|
||||||
@property({ attribute: "include-display-unit-of-measurement" })
|
@property({ attribute: "include-unit-class" })
|
||||||
public includeDisplayUnitOfMeasurement?: string | string[];
|
public includeUnitClass?: string | string[];
|
||||||
|
|
||||||
/**
|
|
||||||
* Show only statistics with these device classes.
|
|
||||||
* @attr include-device-classes
|
|
||||||
*/
|
|
||||||
@property({ attribute: "include-device-classes" })
|
|
||||||
public includeDeviceClasses?: string[];
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Show only statistics on entities.
|
* Show only statistics on entities.
|
||||||
@ -97,8 +93,7 @@ export class HaStatisticPicker extends LitElement {
|
|||||||
(
|
(
|
||||||
statisticIds: StatisticsMetaData[],
|
statisticIds: StatisticsMetaData[],
|
||||||
includeStatisticsUnitOfMeasurement?: string | string[],
|
includeStatisticsUnitOfMeasurement?: string | string[],
|
||||||
includeDisplayUnitOfMeasurement?: string | string[],
|
includeUnitClass?: string | string[],
|
||||||
includeDeviceClasses?: string[],
|
|
||||||
entitiesOnly?: boolean
|
entitiesOnly?: boolean
|
||||||
): Array<{ id: string; name: string; state?: HassEntity }> => {
|
): Array<{ id: string; name: string; state?: HassEntity }> => {
|
||||||
if (!statisticIds.length) {
|
if (!statisticIds.length) {
|
||||||
@ -113,15 +108,18 @@ export class HaStatisticPicker extends LitElement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (includeStatisticsUnitOfMeasurement) {
|
if (includeStatisticsUnitOfMeasurement) {
|
||||||
const includeUnits = ensureArray(includeStatisticsUnitOfMeasurement);
|
const includeUnits: (string | null)[] = ensureArray(
|
||||||
|
includeStatisticsUnitOfMeasurement
|
||||||
|
);
|
||||||
statisticIds = statisticIds.filter((meta) =>
|
statisticIds = statisticIds.filter((meta) =>
|
||||||
includeUnits.includes(meta.statistics_unit_of_measurement)
|
includeUnits.includes(meta.statistics_unit_of_measurement)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
if (includeDisplayUnitOfMeasurement) {
|
if (includeUnitClass) {
|
||||||
const includeUnits = ensureArray(includeDisplayUnitOfMeasurement);
|
const includeUnitClasses: (string | null)[] =
|
||||||
|
ensureArray(includeUnitClass);
|
||||||
statisticIds = statisticIds.filter((meta) =>
|
statisticIds = statisticIds.filter((meta) =>
|
||||||
includeUnits.includes(meta.display_unit_of_measurement)
|
includeUnitClasses.includes(meta.unit_class)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -136,23 +134,16 @@ export class HaStatisticPicker extends LitElement {
|
|||||||
if (!entitiesOnly) {
|
if (!entitiesOnly) {
|
||||||
output.push({
|
output.push({
|
||||||
id: meta.statistic_id,
|
id: meta.statistic_id,
|
||||||
name: meta.name || meta.statistic_id,
|
name: getStatisticLabel(this.hass, meta.statistic_id, meta),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (
|
output.push({
|
||||||
!includeDeviceClasses ||
|
id: meta.statistic_id,
|
||||||
includeDeviceClasses.includes(
|
name: getStatisticLabel(this.hass, meta.statistic_id, meta),
|
||||||
entityState!.attributes.device_class || ""
|
state: entityState,
|
||||||
)
|
});
|
||||||
) {
|
|
||||||
output.push({
|
|
||||||
id: meta.statistic_id,
|
|
||||||
name: computeStateName(entityState),
|
|
||||||
state: entityState,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!output.length) {
|
if (!output.length) {
|
||||||
@ -203,8 +194,7 @@ export class HaStatisticPicker extends LitElement {
|
|||||||
(this.comboBox as any).items = this._getStatistics(
|
(this.comboBox as any).items = this._getStatistics(
|
||||||
this.statisticIds!,
|
this.statisticIds!,
|
||||||
this.includeStatisticsUnitOfMeasurement,
|
this.includeStatisticsUnitOfMeasurement,
|
||||||
this.includeDisplayUnitOfMeasurement,
|
this.includeUnitClass,
|
||||||
this.includeDeviceClasses,
|
|
||||||
this.entitiesOnly
|
this.entitiesOnly
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
@ -212,8 +202,7 @@ export class HaStatisticPicker extends LitElement {
|
|||||||
(this.comboBox as any).items = this._getStatistics(
|
(this.comboBox as any).items = this._getStatistics(
|
||||||
this.statisticIds!,
|
this.statisticIds!,
|
||||||
this.includeStatisticsUnitOfMeasurement,
|
this.includeStatisticsUnitOfMeasurement,
|
||||||
this.includeDisplayUnitOfMeasurement,
|
this.includeUnitClass,
|
||||||
this.includeDeviceClasses,
|
|
||||||
this.entitiesOnly
|
this.entitiesOnly
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
@ -32,11 +32,11 @@ class HaStatisticsPicker extends LitElement {
|
|||||||
public includeStatisticsUnitOfMeasurement?: string[] | string;
|
public includeStatisticsUnitOfMeasurement?: string[] | string;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Show only statistics displayed with these units of measurements.
|
* Show only statistics with these unit classes.
|
||||||
* @attr include-display-unit-of-measurement
|
* @attr include-unit-class
|
||||||
*/
|
*/
|
||||||
@property({ attribute: "include-display-unit-of-measurement" })
|
@property({ attribute: "include-unit-class" })
|
||||||
public includeDisplayUnitOfMeasurement?: string[] | string;
|
public includeUnitClass?: string | string[];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Ignore filtering of statistics type and units when only a single statistic is selected.
|
* Ignore filtering of statistics type and units when only a single statistic is selected.
|
||||||
@ -58,12 +58,12 @@ class HaStatisticsPicker extends LitElement {
|
|||||||
this.ignoreRestrictionsOnFirstStatistic &&
|
this.ignoreRestrictionsOnFirstStatistic &&
|
||||||
this._currentStatistics.length <= 1;
|
this._currentStatistics.length <= 1;
|
||||||
|
|
||||||
const includeDisplayUnitCurrent = ignoreRestriction
|
|
||||||
? undefined
|
|
||||||
: this.includeDisplayUnitOfMeasurement;
|
|
||||||
const includeStatisticsUnitCurrent = ignoreRestriction
|
const includeStatisticsUnitCurrent = ignoreRestriction
|
||||||
? undefined
|
? undefined
|
||||||
: this.includeStatisticsUnitOfMeasurement;
|
: this.includeStatisticsUnitOfMeasurement;
|
||||||
|
const includeUnitClassCurrent = ignoreRestriction
|
||||||
|
? undefined
|
||||||
|
: this.includeUnitClass;
|
||||||
const includeStatisticTypesCurrent = ignoreRestriction
|
const includeStatisticTypesCurrent = ignoreRestriction
|
||||||
? undefined
|
? undefined
|
||||||
: this.statisticTypes;
|
: this.statisticTypes;
|
||||||
@ -75,8 +75,8 @@ class HaStatisticsPicker extends LitElement {
|
|||||||
<ha-statistic-picker
|
<ha-statistic-picker
|
||||||
.curValue=${statisticId}
|
.curValue=${statisticId}
|
||||||
.hass=${this.hass}
|
.hass=${this.hass}
|
||||||
.includeDisplayUnitOfMeasurement=${includeDisplayUnitCurrent}
|
|
||||||
.includeStatisticsUnitOfMeasurement=${includeStatisticsUnitCurrent}
|
.includeStatisticsUnitOfMeasurement=${includeStatisticsUnitCurrent}
|
||||||
|
.includeUnitClass=${includeUnitClassCurrent}
|
||||||
.value=${statisticId}
|
.value=${statisticId}
|
||||||
.statisticTypes=${includeStatisticTypesCurrent}
|
.statisticTypes=${includeStatisticTypesCurrent}
|
||||||
.statisticIds=${this.statisticIds}
|
.statisticIds=${this.statisticIds}
|
||||||
@ -89,10 +89,9 @@ class HaStatisticsPicker extends LitElement {
|
|||||||
<div>
|
<div>
|
||||||
<ha-statistic-picker
|
<ha-statistic-picker
|
||||||
.hass=${this.hass}
|
.hass=${this.hass}
|
||||||
.includeDisplayUnitOfMeasurement=${this
|
|
||||||
.includeDisplayUnitOfMeasurement}
|
|
||||||
.includeStatisticsUnitOfMeasurement=${this
|
.includeStatisticsUnitOfMeasurement=${this
|
||||||
.includeStatisticsUnitOfMeasurement}
|
.includeStatisticsUnitOfMeasurement}
|
||||||
|
.includeUnitClass=${this.includeUnitClass}
|
||||||
.statisticTypes=${this.statisticTypes}
|
.statisticTypes=${this.statisticTypes}
|
||||||
.statisticIds=${this.statisticIds}
|
.statisticIds=${this.statisticIds}
|
||||||
.label=${this.pickStatisticLabel}
|
.label=${this.pickStatisticLabel}
|
||||||
|
@ -8,7 +8,14 @@ import type {
|
|||||||
ComboBoxLightValueChangedEvent,
|
ComboBoxLightValueChangedEvent,
|
||||||
} from "@vaadin/combo-box/vaadin-combo-box-light";
|
} from "@vaadin/combo-box/vaadin-combo-box-light";
|
||||||
import { registerStyles } from "@vaadin/vaadin-themable-mixin/register-styles";
|
import { registerStyles } from "@vaadin/vaadin-themable-mixin/register-styles";
|
||||||
import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit";
|
import {
|
||||||
|
css,
|
||||||
|
CSSResultGroup,
|
||||||
|
html,
|
||||||
|
LitElement,
|
||||||
|
PropertyValues,
|
||||||
|
TemplateResult,
|
||||||
|
} from "lit";
|
||||||
import { ComboBoxLitRenderer, comboBoxRenderer } from "@vaadin/combo-box/lit";
|
import { ComboBoxLitRenderer, comboBoxRenderer } from "@vaadin/combo-box/lit";
|
||||||
import { customElement, property, query } from "lit/decorators";
|
import { customElement, property, query } from "lit/decorators";
|
||||||
import { ifDefined } from "lit/directives/if-defined";
|
import { ifDefined } from "lit/directives/if-defined";
|
||||||
@ -225,11 +232,13 @@ export class HaComboBox extends LitElement {
|
|||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
fireEvent(this, ev.type, ev.detail);
|
fireEvent(this, ev.type, ev.detail);
|
||||||
|
|
||||||
if (
|
if (opened) {
|
||||||
opened &&
|
this.removeInertOnOverlay();
|
||||||
"MutationObserver" in window &&
|
}
|
||||||
!this._overlayMutationObserver
|
}
|
||||||
) {
|
|
||||||
|
private removeInertOnOverlay() {
|
||||||
|
if ("MutationObserver" in window && !this._overlayMutationObserver) {
|
||||||
const overlay = document.querySelector<HTMLElement>(
|
const overlay = document.querySelector<HTMLElement>(
|
||||||
"vaadin-combo-box-overlay"
|
"vaadin-combo-box-overlay"
|
||||||
);
|
);
|
||||||
@ -268,6 +277,16 @@ export class HaComboBox extends LitElement {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
updated(changedProps: PropertyValues) {
|
||||||
|
super.updated(changedProps);
|
||||||
|
if (
|
||||||
|
changedProps.has("filteredItems") ||
|
||||||
|
(changedProps.has("items") && this.opened)
|
||||||
|
) {
|
||||||
|
this.removeInertOnOverlay();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private _filterChanged(ev: ComboBoxLightFilterChangedEvent) {
|
private _filterChanged(ev: ComboBoxLightFilterChangedEvent) {
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
fireEvent(this, ev.type, ev.detail, { composed: false });
|
fireEvent(this, ev.type, ev.detail, { composed: false });
|
||||||
|
@ -13,7 +13,7 @@ type IconItem = {
|
|||||||
icon: string;
|
icon: string;
|
||||||
keywords: string[];
|
keywords: string[];
|
||||||
};
|
};
|
||||||
let iconItems: IconItem[] = [{ icon: "", keywords: [] }];
|
let iconItems: IconItem[] = [];
|
||||||
let iconLoaded = false;
|
let iconLoaded = false;
|
||||||
|
|
||||||
// eslint-disable-next-line lit/prefer-static-styles
|
// eslint-disable-next-line lit/prefer-static-styles
|
||||||
|
@ -20,7 +20,7 @@ type NavigationItem = {
|
|||||||
title: string;
|
title: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
const DEFAULT_ITEMS: NavigationItem[] = [{ path: "", icon: "", title: "" }];
|
const DEFAULT_ITEMS: NavigationItem[] = [];
|
||||||
|
|
||||||
// eslint-disable-next-line lit/prefer-static-styles
|
// eslint-disable-next-line lit/prefer-static-styles
|
||||||
const rowRenderer: ComboBoxLitRenderer<NavigationItem> = (item) => html`
|
const rowRenderer: ComboBoxLitRenderer<NavigationItem> = (item) => html`
|
||||||
|
@ -189,7 +189,11 @@ export const describeTrigger = (
|
|||||||
// Time Trigger
|
// Time Trigger
|
||||||
if (trigger.platform === "time" && trigger.at) {
|
if (trigger.platform === "time" && trigger.at) {
|
||||||
const at = trigger.at.includes(".")
|
const at = trigger.at.includes(".")
|
||||||
? `entity ${computeStateName(hass.states[trigger.at]) || trigger.at}`
|
? `entity ${
|
||||||
|
hass.states[trigger.at]
|
||||||
|
? computeStateName(hass.states[trigger.at])
|
||||||
|
: trigger.at
|
||||||
|
}`
|
||||||
: trigger.at;
|
: trigger.at;
|
||||||
|
|
||||||
return `When the time is equal to ${at}`;
|
return `When the time is equal to ${at}`;
|
||||||
@ -568,6 +572,13 @@ export const describeCondition = (
|
|||||||
}`;
|
}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (condition.condition === "trigger") {
|
||||||
|
if (!condition.id) {
|
||||||
|
return "Trigger condition";
|
||||||
|
}
|
||||||
|
return `When triggered by ${condition.id}`;
|
||||||
|
}
|
||||||
|
|
||||||
return `${
|
return `${
|
||||||
condition.condition ? condition.condition.replace(/_/g, " ") : "Unknown"
|
condition.condition ? condition.condition.replace(/_/g, " ") : "Unknown"
|
||||||
} condition`;
|
} condition`;
|
||||||
|
@ -600,20 +600,14 @@ export const getEnergySolarForecasts = (hass: HomeAssistant) =>
|
|||||||
type: "energy/solar_forecast",
|
type: "energy/solar_forecast",
|
||||||
});
|
});
|
||||||
|
|
||||||
export const ENERGY_GAS_VOLUME_UNITS = ["m³"];
|
const energyGasUnitClass = ["volume", "energy"] as const;
|
||||||
export const ENERGY_GAS_ENERGY_UNITS = ["kWh"];
|
export type EnergyGasUnitClass = typeof energyGasUnitClass[number];
|
||||||
export const ENERGY_GAS_UNITS = [
|
|
||||||
...ENERGY_GAS_VOLUME_UNITS,
|
|
||||||
...ENERGY_GAS_ENERGY_UNITS,
|
|
||||||
];
|
|
||||||
|
|
||||||
export type EnergyGasUnit = "volume" | "energy";
|
export const getEnergyGasUnitClass = (
|
||||||
|
|
||||||
export const getEnergyGasUnitCategory = (
|
|
||||||
prefs: EnergyPreferences,
|
prefs: EnergyPreferences,
|
||||||
statisticsMetaData: Record<string, StatisticsMetaData> = {},
|
statisticsMetaData: Record<string, StatisticsMetaData> = {},
|
||||||
excludeSource?: string
|
excludeSource?: string
|
||||||
): EnergyGasUnit | undefined => {
|
): EnergyGasUnitClass | undefined => {
|
||||||
for (const source of prefs.energy_sources) {
|
for (const source of prefs.energy_sources) {
|
||||||
if (source.type !== "gas") {
|
if (source.type !== "gas") {
|
||||||
continue;
|
continue;
|
||||||
@ -622,29 +616,29 @@ export const getEnergyGasUnitCategory = (
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
const statisticIdWithMeta = statisticsMetaData[source.stat_energy_from];
|
const statisticIdWithMeta = statisticsMetaData[source.stat_energy_from];
|
||||||
if (statisticIdWithMeta) {
|
if (
|
||||||
return ENERGY_GAS_VOLUME_UNITS.includes(
|
energyGasUnitClass.includes(
|
||||||
statisticIdWithMeta.statistics_unit_of_measurement
|
statisticIdWithMeta.unit_class as EnergyGasUnitClass
|
||||||
)
|
)
|
||||||
? "volume"
|
) {
|
||||||
: "energy";
|
return statisticIdWithMeta.unit_class as EnergyGasUnitClass;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return undefined;
|
return undefined;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const getEnergyGasUnit = (
|
export const getEnergyGasUnit = (
|
||||||
|
hass: HomeAssistant,
|
||||||
prefs: EnergyPreferences,
|
prefs: EnergyPreferences,
|
||||||
statisticsMetaData: Record<string, StatisticsMetaData> = {}
|
statisticsMetaData: Record<string, StatisticsMetaData> = {}
|
||||||
): string | undefined => {
|
): string | undefined => {
|
||||||
for (const source of prefs.energy_sources) {
|
const unitClass = getEnergyGasUnitClass(prefs, statisticsMetaData);
|
||||||
if (source.type !== "gas") {
|
if (unitClass === undefined) {
|
||||||
continue;
|
return undefined;
|
||||||
}
|
|
||||||
const statisticIdWithMeta = statisticsMetaData[source.stat_energy_from];
|
|
||||||
if (statisticIdWithMeta?.display_unit_of_measurement) {
|
|
||||||
return statisticIdWithMeta.display_unit_of_measurement;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return undefined;
|
return unitClass === "energy"
|
||||||
|
? "kWh"
|
||||||
|
: hass.config.unit_system.length === "km"
|
||||||
|
? "m³"
|
||||||
|
: "ft³";
|
||||||
};
|
};
|
||||||
|
@ -20,13 +20,13 @@ export interface StatisticValue {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export interface StatisticsMetaData {
|
export interface StatisticsMetaData {
|
||||||
display_unit_of_measurement: string;
|
statistics_unit_of_measurement: string | null;
|
||||||
statistics_unit_of_measurement: string;
|
|
||||||
statistic_id: string;
|
statistic_id: string;
|
||||||
source: string;
|
source: string;
|
||||||
name?: string | null;
|
name?: string | null;
|
||||||
has_sum: boolean;
|
has_sum: boolean;
|
||||||
has_mean: boolean;
|
has_mean: boolean;
|
||||||
|
unit_class: string | null;
|
||||||
}
|
}
|
||||||
|
|
||||||
export type StatisticsValidationResult =
|
export type StatisticsValidationResult =
|
||||||
@ -254,14 +254,14 @@ export const adjustStatisticsSum = (
|
|||||||
statistic_id: string,
|
statistic_id: string,
|
||||||
start_time: string,
|
start_time: string,
|
||||||
adjustment: number,
|
adjustment: number,
|
||||||
display_unit: string
|
adjustment_unit_of_measurement: string | null
|
||||||
): Promise<void> =>
|
): Promise<void> =>
|
||||||
hass.callWS({
|
hass.callWS({
|
||||||
type: "recorder/adjust_sum_statistics",
|
type: "recorder/adjust_sum_statistics",
|
||||||
statistic_id,
|
statistic_id,
|
||||||
start_time,
|
start_time,
|
||||||
adjustment,
|
adjustment,
|
||||||
display_unit,
|
adjustment_unit_of_measurement,
|
||||||
});
|
});
|
||||||
|
|
||||||
export const getStatisticLabel = (
|
export const getStatisticLabel = (
|
||||||
@ -275,3 +275,17 @@ export const getStatisticLabel = (
|
|||||||
}
|
}
|
||||||
return statisticsMetaData?.name || statisticsId;
|
return statisticsMetaData?.name || statisticsId;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const getDisplayUnit = (
|
||||||
|
hass: HomeAssistant,
|
||||||
|
statisticsId: string | undefined,
|
||||||
|
statisticsMetaData: StatisticsMetaData | undefined
|
||||||
|
): string | null | undefined => {
|
||||||
|
let unit: string | undefined;
|
||||||
|
if (statisticsId) {
|
||||||
|
unit = hass.states[statisticsId]?.attributes.unit_of_measurement;
|
||||||
|
}
|
||||||
|
return unit === undefined
|
||||||
|
? statisticsMetaData?.statistics_unit_of_measurement
|
||||||
|
: unit;
|
||||||
|
};
|
||||||
|
@ -14,8 +14,6 @@ import { showAddApplicationCredentialDialog } from "../../panels/config/applicat
|
|||||||
import { configFlowContentStyles } from "./styles";
|
import { configFlowContentStyles } from "./styles";
|
||||||
import { DataEntryFlowDialogParams } from "./show-dialog-data-entry-flow";
|
import { DataEntryFlowDialogParams } from "./show-dialog-data-entry-flow";
|
||||||
import { showConfigFlowDialog } from "./show-dialog-config-flow";
|
import { showConfigFlowDialog } from "./show-dialog-config-flow";
|
||||||
import { domainToName } from "../../data/integration";
|
|
||||||
import { showConfirmationDialog } from "../generic/show-dialog-box";
|
|
||||||
|
|
||||||
@customElement("step-flow-abort")
|
@customElement("step-flow-abort")
|
||||||
class StepFlowAbort extends LitElement {
|
class StepFlowAbort extends LitElement {
|
||||||
@ -54,26 +52,11 @@ class StepFlowAbort extends LitElement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private async _handleMissingCreds() {
|
private async _handleMissingCreds() {
|
||||||
const confirm = await showConfirmationDialog(this, {
|
|
||||||
title: this.hass.localize(
|
|
||||||
"ui.panel.config.integrations.config_flow.missing_credentials_title"
|
|
||||||
),
|
|
||||||
text: this.hass.localize(
|
|
||||||
"ui.panel.config.integrations.config_flow.missing_credentials",
|
|
||||||
{
|
|
||||||
integration: domainToName(this.hass.localize, this.domain),
|
|
||||||
}
|
|
||||||
),
|
|
||||||
confirmText: this.hass.localize("ui.common.yes"),
|
|
||||||
dismissText: this.hass.localize("ui.common.no"),
|
|
||||||
});
|
|
||||||
this._flowDone();
|
this._flowDone();
|
||||||
if (!confirm) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// Prompt to enter credentials and restart integration setup
|
// Prompt to enter credentials and restart integration setup
|
||||||
showAddApplicationCredentialDialog(this.params.dialogParentElement!, {
|
showAddApplicationCredentialDialog(this.params.dialogParentElement!, {
|
||||||
selectedDomain: this.domain,
|
selectedDomain: this.domain,
|
||||||
|
manifest: this.params.manifest,
|
||||||
applicationCredentialAddedCallback: () => {
|
applicationCredentialAddedCallback: () => {
|
||||||
showConfigFlowDialog(this.params.dialogParentElement!, {
|
showConfigFlowDialog(this.params.dialogParentElement!, {
|
||||||
dialogClosedCallback: this.params.dialogClosedCallback,
|
dialogClosedCallback: this.params.dialogClosedCallback,
|
||||||
|
@ -5,6 +5,7 @@ import { ComboBoxLitRenderer } from "@vaadin/combo-box/lit";
|
|||||||
import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit";
|
import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit";
|
||||||
import { customElement, property, state } from "lit/decorators";
|
import { customElement, property, state } from "lit/decorators";
|
||||||
import { fireEvent } from "../../../common/dom/fire_event";
|
import { fireEvent } from "../../../common/dom/fire_event";
|
||||||
|
import "../../../components/ha-alert";
|
||||||
import "../../../components/ha-circular-progress";
|
import "../../../components/ha-circular-progress";
|
||||||
import "../../../components/ha-combo-box";
|
import "../../../components/ha-combo-box";
|
||||||
import { createCloseHeading } from "../../../components/ha-dialog";
|
import { createCloseHeading } from "../../../components/ha-dialog";
|
||||||
@ -16,7 +17,7 @@ import {
|
|||||||
createApplicationCredential,
|
createApplicationCredential,
|
||||||
fetchApplicationCredentialsConfig,
|
fetchApplicationCredentialsConfig,
|
||||||
} from "../../../data/application_credential";
|
} from "../../../data/application_credential";
|
||||||
import { domainToName } from "../../../data/integration";
|
import { domainToName, IntegrationManifest } from "../../../data/integration";
|
||||||
import { haStyleDialog } from "../../../resources/styles";
|
import { haStyleDialog } from "../../../resources/styles";
|
||||||
import { HomeAssistant } from "../../../types";
|
import { HomeAssistant } from "../../../types";
|
||||||
import { documentationUrl } from "../../../util/documentation-url";
|
import { documentationUrl } from "../../../util/documentation-url";
|
||||||
@ -44,6 +45,8 @@ export class DialogAddApplicationCredential extends LitElement {
|
|||||||
|
|
||||||
@state() private _domain?: string;
|
@state() private _domain?: string;
|
||||||
|
|
||||||
|
@state() private _manifest?: IntegrationManifest | null;
|
||||||
|
|
||||||
@state() private _name?: string;
|
@state() private _name?: string;
|
||||||
|
|
||||||
@state() private _description?: string;
|
@state() private _description?: string;
|
||||||
@ -58,8 +61,8 @@ export class DialogAddApplicationCredential extends LitElement {
|
|||||||
|
|
||||||
public showDialog(params: AddApplicationCredentialDialogParams) {
|
public showDialog(params: AddApplicationCredentialDialogParams) {
|
||||||
this._params = params;
|
this._params = params;
|
||||||
this._domain =
|
this._domain = params.selectedDomain;
|
||||||
params.selectedDomain !== undefined ? params.selectedDomain : "";
|
this._manifest = params.manifest;
|
||||||
this._name = "";
|
this._name = "";
|
||||||
this._description = "";
|
this._description = "";
|
||||||
this._clientId = "";
|
this._clientId = "";
|
||||||
@ -76,7 +79,7 @@ export class DialogAddApplicationCredential extends LitElement {
|
|||||||
name: domainToName(this.hass.localize, domain),
|
name: domainToName(this.hass.localize, domain),
|
||||||
}));
|
}));
|
||||||
await this.hass.loadBackendTranslation("application_credentials");
|
await this.hass.loadBackendTranslation("application_credentials");
|
||||||
if (this._domain !== "") {
|
if (this._domain) {
|
||||||
this._updateDescription();
|
this._updateDescription();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -85,6 +88,9 @@ export class DialogAddApplicationCredential extends LitElement {
|
|||||||
if (!this._params || !this._domains) {
|
if (!this._params || !this._domains) {
|
||||||
return html``;
|
return html``;
|
||||||
}
|
}
|
||||||
|
const selectedDomainName = this._params.selectedDomain
|
||||||
|
? domainToName(this.hass.localize, this._domain!)
|
||||||
|
: "";
|
||||||
return html`
|
return html`
|
||||||
<ha-dialog
|
<ha-dialog
|
||||||
open
|
open
|
||||||
@ -99,42 +105,76 @@ export class DialogAddApplicationCredential extends LitElement {
|
|||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
<div>
|
<div>
|
||||||
${this._error ? html` <div class="error">${this._error}</div> ` : ""}
|
${this._error
|
||||||
<p>
|
? html`<ha-alert alert-type="error">${this._error}</ha-alert> `
|
||||||
${this.hass.localize(
|
: ""}
|
||||||
"ui.panel.config.application_credentials.editor.description"
|
${this._params.selectedDomain && !this._description
|
||||||
)}
|
? html`<p>
|
||||||
<br />
|
${this.hass.localize(
|
||||||
<a
|
"ui.panel.config.application_credentials.editor.missing_credentials",
|
||||||
href=${documentationUrl(
|
{
|
||||||
this.hass!,
|
integration: selectedDomainName,
|
||||||
"/integrations/application_credentials"
|
}
|
||||||
)}
|
)}
|
||||||
target="_blank"
|
${this._manifest?.is_built_in || this._manifest?.documentation
|
||||||
rel="noreferrer"
|
? html`<a
|
||||||
>
|
href=${this._manifest.is_built_in
|
||||||
${this.hass!.localize(
|
? documentationUrl(
|
||||||
"ui.panel.config.application_credentials.editor.view_documentation"
|
this.hass,
|
||||||
)}
|
`/integrations/${this._domain}`
|
||||||
<ha-svg-icon .path=${mdiOpenInNew}></ha-svg-icon>
|
)
|
||||||
</a>
|
: this._manifest.documentation}
|
||||||
</p>
|
target="_blank"
|
||||||
<ha-combo-box
|
rel="noreferrer"
|
||||||
name="domain"
|
>
|
||||||
.hass=${this.hass}
|
${this.hass.localize(
|
||||||
.disabled=${!!this._params.selectedDomain}
|
"ui.panel.config.application_credentials.editor.missing_credentials_domain_link",
|
||||||
.label=${this.hass.localize(
|
{
|
||||||
"ui.panel.config.application_credentials.editor.domain"
|
integration: selectedDomainName,
|
||||||
)}
|
}
|
||||||
.value=${this._domain}
|
)}
|
||||||
.renderer=${rowRenderer}
|
<ha-svg-icon .path=${mdiOpenInNew}></ha-svg-icon>
|
||||||
.items=${this._domains}
|
</a>`
|
||||||
item-id-path="id"
|
: ""}
|
||||||
item-value-path="id"
|
</p>`
|
||||||
item-label-path="name"
|
: ""}
|
||||||
required
|
${!this._params.selectedDomain || !this._description
|
||||||
@value-changed=${this._handleDomainPicked}
|
? html`<p>
|
||||||
></ha-combo-box>
|
${this.hass.localize(
|
||||||
|
"ui.panel.config.application_credentials.editor.description"
|
||||||
|
)}
|
||||||
|
<a
|
||||||
|
href=${documentationUrl(
|
||||||
|
this.hass!,
|
||||||
|
"/integrations/application_credentials"
|
||||||
|
)}
|
||||||
|
target="_blank"
|
||||||
|
rel="noreferrer"
|
||||||
|
>
|
||||||
|
${this.hass!.localize(
|
||||||
|
"ui.panel.config.application_credentials.editor.view_documentation"
|
||||||
|
)}
|
||||||
|
<ha-svg-icon .path=${mdiOpenInNew}></ha-svg-icon>
|
||||||
|
</a>
|
||||||
|
</p>`
|
||||||
|
: ""}
|
||||||
|
${this._params.selectedDomain
|
||||||
|
? ""
|
||||||
|
: html`<ha-combo-box
|
||||||
|
name="domain"
|
||||||
|
.hass=${this.hass}
|
||||||
|
.label=${this.hass.localize(
|
||||||
|
"ui.panel.config.application_credentials.editor.domain"
|
||||||
|
)}
|
||||||
|
.value=${this._domain}
|
||||||
|
.renderer=${rowRenderer}
|
||||||
|
.items=${this._domains}
|
||||||
|
item-id-path="id"
|
||||||
|
item-value-path="id"
|
||||||
|
item-label-path="name"
|
||||||
|
required
|
||||||
|
@value-changed=${this._handleDomainPicked}
|
||||||
|
></ha-combo-box>`}
|
||||||
${this._description
|
${this._description
|
||||||
? html`<ha-markdown
|
? html`<ha-markdown
|
||||||
breaks
|
breaks
|
||||||
@ -223,7 +263,11 @@ export class DialogAddApplicationCredential extends LitElement {
|
|||||||
this._updateDescription();
|
this._updateDescription();
|
||||||
}
|
}
|
||||||
|
|
||||||
private _updateDescription() {
|
private async _updateDescription() {
|
||||||
|
await this.hass.loadBackendTranslation(
|
||||||
|
"application_credentials",
|
||||||
|
this._domain
|
||||||
|
);
|
||||||
const info = this._config!.integrations[this._domain!];
|
const info = this._config!.integrations[this._domain!];
|
||||||
this._description = this.hass.localize(
|
this._description = this.hass.localize(
|
||||||
`component.${this._domain}.application_credentials.description`,
|
`component.${this._domain}.application_credentials.description`,
|
||||||
@ -298,6 +342,9 @@ export class DialogAddApplicationCredential extends LitElement {
|
|||||||
a ha-svg-icon {
|
a ha-svg-icon {
|
||||||
--mdc-icon-size: 16px;
|
--mdc-icon-size: 16px;
|
||||||
}
|
}
|
||||||
|
ha-markdown {
|
||||||
|
margin-bottom: 16px;
|
||||||
|
}
|
||||||
`,
|
`,
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
import { fireEvent } from "../../../common/dom/fire_event";
|
import { fireEvent } from "../../../common/dom/fire_event";
|
||||||
import { ApplicationCredential } from "../../../data/application_credential";
|
import { ApplicationCredential } from "../../../data/application_credential";
|
||||||
|
import { IntegrationManifest } from "../../../data/integration";
|
||||||
|
|
||||||
export interface AddApplicationCredentialDialogParams {
|
export interface AddApplicationCredentialDialogParams {
|
||||||
applicationCredentialAddedCallback: (
|
applicationCredentialAddedCallback: (
|
||||||
@ -7,6 +8,7 @@ export interface AddApplicationCredentialDialogParams {
|
|||||||
) => void;
|
) => void;
|
||||||
dialogAbortedCallback?: () => void;
|
dialogAbortedCallback?: () => void;
|
||||||
selectedDomain?: string;
|
selectedDomain?: string;
|
||||||
|
manifest?: IntegrationManifest | null;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const loadAddApplicationCredentialDialog = () =>
|
export const loadAddApplicationCredentialDialog = () =>
|
||||||
|
@ -55,7 +55,7 @@ export class HaChooseAction extends LitElement implements ActionElement {
|
|||||||
)}:
|
)}:
|
||||||
</h3>
|
</h3>
|
||||||
<ha-automation-condition
|
<ha-automation-condition
|
||||||
.conditions=${option.conditions}
|
.conditions=${ensureArray<string | Condition>(option.conditions)}
|
||||||
.reOrderMode=${this.reOrderMode}
|
.reOrderMode=${this.reOrderMode}
|
||||||
.disabled=${this.disabled}
|
.disabled=${this.disabled}
|
||||||
.hass=${this.hass}
|
.hass=${this.hass}
|
||||||
@ -68,7 +68,7 @@ export class HaChooseAction extends LitElement implements ActionElement {
|
|||||||
)}:
|
)}:
|
||||||
</h3>
|
</h3>
|
||||||
<ha-automation-action
|
<ha-automation-action
|
||||||
.actions=${option.sequence || []}
|
.actions=${ensureArray(option.sequence) || []}
|
||||||
.reOrderMode=${this.reOrderMode}
|
.reOrderMode=${this.reOrderMode}
|
||||||
.disabled=${this.disabled}
|
.disabled=${this.disabled}
|
||||||
.hass=${this.hass}
|
.hass=${this.hass}
|
||||||
@ -96,7 +96,7 @@ export class HaChooseAction extends LitElement implements ActionElement {
|
|||||||
)}:
|
)}:
|
||||||
</h2>
|
</h2>
|
||||||
<ha-automation-action
|
<ha-automation-action
|
||||||
.actions=${action.default || []}
|
.actions=${ensureArray(action.default) || []}
|
||||||
.reOrderMode=${this.reOrderMode}
|
.reOrderMode=${this.reOrderMode}
|
||||||
.disabled=${this.disabled}
|
.disabled=${this.disabled}
|
||||||
@value-changed=${this._defaultChanged}
|
@value-changed=${this._defaultChanged}
|
||||||
|
@ -444,7 +444,7 @@ export class HaAutomationEditor extends KeyboardShortcutMixin(LitElement) {
|
|||||||
|
|
||||||
if (changedProps.has("entityId") && this.entityId) {
|
if (changedProps.has("entityId") && this.entityId) {
|
||||||
getAutomationStateConfig(this.hass, this.entityId).then((c) => {
|
getAutomationStateConfig(this.hass, this.entityId).then((c) => {
|
||||||
this._config = c.config;
|
this._config = this._normalizeConfig(c.config);
|
||||||
});
|
});
|
||||||
this._entityId = this.entityId;
|
this._entityId = this.entityId;
|
||||||
this._dirty = false;
|
this._dirty = false;
|
||||||
@ -473,24 +473,27 @@ export class HaAutomationEditor extends KeyboardShortcutMixin(LitElement) {
|
|||||||
this._entityId = automation?.entity_id;
|
this._entityId = automation?.entity_id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private _normalizeConfig(config: AutomationConfig): AutomationConfig {
|
||||||
|
// Normalize data: ensure trigger, action and condition are lists
|
||||||
|
// Happens when people copy paste their automations into the config
|
||||||
|
for (const key of ["trigger", "condition", "action"]) {
|
||||||
|
const value = config[key];
|
||||||
|
if (value && !Array.isArray(value)) {
|
||||||
|
config[key] = [value];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return config;
|
||||||
|
}
|
||||||
|
|
||||||
private async _loadConfig() {
|
private async _loadConfig() {
|
||||||
try {
|
try {
|
||||||
const config = await fetchAutomationFileConfig(
|
const config = await fetchAutomationFileConfig(
|
||||||
this.hass,
|
this.hass,
|
||||||
this.automationId as string
|
this.automationId as string
|
||||||
);
|
);
|
||||||
|
|
||||||
// Normalize data: ensure trigger, action and condition are lists
|
|
||||||
// Happens when people copy paste their automations into the config
|
|
||||||
for (const key of ["trigger", "condition", "action"]) {
|
|
||||||
const value = config[key];
|
|
||||||
if (value && !Array.isArray(value)) {
|
|
||||||
config[key] = [value];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
this._dirty = false;
|
this._dirty = false;
|
||||||
this._readOnly = false;
|
this._readOnly = false;
|
||||||
this._config = config;
|
this._config = this._normalizeConfig(config);
|
||||||
} catch (err: any) {
|
} catch (err: any) {
|
||||||
const entity = Object.values(this.hass.entities).find(
|
const entity = Object.values(this.hass.entities).find(
|
||||||
(ent) =>
|
(ent) =>
|
||||||
|
@ -35,6 +35,8 @@ import {
|
|||||||
deleteAutomation,
|
deleteAutomation,
|
||||||
duplicateAutomation,
|
duplicateAutomation,
|
||||||
fetchAutomationFileConfig,
|
fetchAutomationFileConfig,
|
||||||
|
getAutomationStateConfig,
|
||||||
|
showAutomationEditor,
|
||||||
triggerAutomationActions,
|
triggerAutomationActions,
|
||||||
} from "../../../data/automation";
|
} from "../../../data/automation";
|
||||||
import {
|
import {
|
||||||
@ -329,6 +331,14 @@ class HaAutomationPicker extends LitElement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private _showTrace(automation: any) {
|
private _showTrace(automation: any) {
|
||||||
|
if (!automation.attributes.id) {
|
||||||
|
showAlertDialog(this, {
|
||||||
|
text: this.hass.localize(
|
||||||
|
"ui.panel.config.automation.picker.traces_not_available"
|
||||||
|
),
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
navigate(`/config/automation/trace/${automation.attributes.id}`);
|
navigate(`/config/automation/trace/${automation.attributes.id}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -382,17 +392,20 @@ class HaAutomationPicker extends LitElement {
|
|||||||
);
|
);
|
||||||
duplicateAutomation(config);
|
duplicateAutomation(config);
|
||||||
} catch (err: any) {
|
} catch (err: any) {
|
||||||
|
if (err.status_code === 404) {
|
||||||
|
const response = await getAutomationStateConfig(
|
||||||
|
this.hass,
|
||||||
|
automation.entity_id
|
||||||
|
);
|
||||||
|
showAutomationEditor({ ...response.config, id: undefined });
|
||||||
|
return;
|
||||||
|
}
|
||||||
await showAlertDialog(this, {
|
await showAlertDialog(this, {
|
||||||
text:
|
text: this.hass.localize(
|
||||||
err.status_code === 404
|
"ui.panel.config.automation.editor.load_error_unknown",
|
||||||
? this.hass.localize(
|
"err_no",
|
||||||
"ui.panel.config.automation.editor.load_error_not_duplicable"
|
err.status_code
|
||||||
)
|
),
|
||||||
: this.hass.localize(
|
|
||||||
"ui.panel.config.automation.editor.load_error_unknown",
|
|
||||||
"err_no",
|
|
||||||
err.status_code
|
|
||||||
),
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -38,6 +38,7 @@ import { HomeAssistant, Route } from "../../../types";
|
|||||||
import { configSections } from "../ha-panel-config";
|
import { configSections } from "../ha-panel-config";
|
||||||
import "../integrations/ha-integration-overflow-menu";
|
import "../integrations/ha-integration-overflow-menu";
|
||||||
import { showZWaveJSAddNodeDialog } from "../integrations/integration-panels/zwave_js/show-dialog-zwave_js-add-node";
|
import { showZWaveJSAddNodeDialog } from "../integrations/integration-panels/zwave_js/show-dialog-zwave_js-add-node";
|
||||||
|
import { showAddIntegrationDialog } from "../integrations/show-add-integration-dialog";
|
||||||
|
|
||||||
interface DeviceRowData extends DeviceRegistryEntry {
|
interface DeviceRowData extends DeviceRegistryEntry {
|
||||||
device?: DeviceRowData;
|
device?: DeviceRowData;
|
||||||
@ -363,16 +364,15 @@ export class HaConfigDeviceDashboard extends LitElement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected render(): TemplateResult {
|
protected render(): TemplateResult {
|
||||||
const { devicesOutput, filteredConfigEntry } =
|
const { devicesOutput } = this._devicesAndFilterDomains(
|
||||||
this._devicesAndFilterDomains(
|
this.devices,
|
||||||
this.devices,
|
this.entries,
|
||||||
this.entries,
|
this.entities,
|
||||||
this.entities,
|
this.areas,
|
||||||
this.areas,
|
this._searchParms,
|
||||||
this._searchParms,
|
this._showDisabled,
|
||||||
this._showDisabled,
|
this.hass.localize
|
||||||
this.hass.localize
|
);
|
||||||
);
|
|
||||||
const activeFilters = this._activeFilters(
|
const activeFilters = this._activeFilters(
|
||||||
this.entries,
|
this.entries,
|
||||||
this._searchParms,
|
this._searchParms,
|
||||||
@ -405,39 +405,21 @@ export class HaConfigDeviceDashboard extends LitElement {
|
|||||||
@search-changed=${this._handleSearchChange}
|
@search-changed=${this._handleSearchChange}
|
||||||
@row-click=${this._handleRowClicked}
|
@row-click=${this._handleRowClicked}
|
||||||
clickable
|
clickable
|
||||||
.hasFab=${filteredConfigEntry &&
|
hasFab
|
||||||
(filteredConfigEntry.domain === "zha" ||
|
|
||||||
filteredConfigEntry.domain === "zwave_js")}
|
|
||||||
>
|
>
|
||||||
<ha-integration-overflow-menu
|
<ha-integration-overflow-menu
|
||||||
.hass=${this.hass}
|
.hass=${this.hass}
|
||||||
slot="toolbar-icon"
|
slot="toolbar-icon"
|
||||||
></ha-integration-overflow-menu>
|
></ha-integration-overflow-menu>
|
||||||
${!filteredConfigEntry
|
<ha-fab
|
||||||
? ""
|
slot="fab"
|
||||||
: filteredConfigEntry.domain === "zwave_js"
|
.label=${this.hass.localize("ui.panel.config.devices.add_device")}
|
||||||
? html`
|
extended
|
||||||
<ha-fab
|
@click=${this._addDevice}
|
||||||
slot="fab"
|
?rtl=${computeRTL(this.hass)}
|
||||||
.label=${this.hass.localize("ui.panel.config.zha.add_device")}
|
>
|
||||||
extended
|
<ha-svg-icon slot="icon" .path=${mdiPlus}></ha-svg-icon>
|
||||||
?rtl=${computeRTL(this.hass)}
|
</ha-fab>
|
||||||
@click=${this._showZJSAddDeviceDialog}
|
|
||||||
>
|
|
||||||
<ha-svg-icon slot="icon" .path=${mdiPlus}></ha-svg-icon>
|
|
||||||
</ha-fab>
|
|
||||||
`
|
|
||||||
: filteredConfigEntry.domain === "zha"
|
|
||||||
? html`<a href="/config/zha/add" slot="fab">
|
|
||||||
<ha-fab
|
|
||||||
.label=${this.hass.localize("ui.panel.config.zha.add_device")}
|
|
||||||
extended
|
|
||||||
?rtl=${computeRTL(this.hass)}
|
|
||||||
>
|
|
||||||
<ha-svg-icon slot="icon" .path=${mdiPlus}></ha-svg-icon>
|
|
||||||
</ha-fab>
|
|
||||||
</a>`
|
|
||||||
: html``}
|
|
||||||
<ha-button-menu slot="filter-menu" corner="BOTTOM_START" multi>
|
<ha-button-menu slot="filter-menu" corner="BOTTOM_START" multi>
|
||||||
<ha-icon-button
|
<ha-icon-button
|
||||||
slot="trigger"
|
slot="trigger"
|
||||||
@ -516,7 +498,7 @@ export class HaConfigDeviceDashboard extends LitElement {
|
|||||||
this._showDisabled = true;
|
this._showDisabled = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private _showZJSAddDeviceDialog() {
|
private _addDevice() {
|
||||||
const { filteredConfigEntry } = this._devicesAndFilterDomains(
|
const { filteredConfigEntry } = this._devicesAndFilterDomains(
|
||||||
this.devices,
|
this.devices,
|
||||||
this.entries,
|
this.entries,
|
||||||
@ -526,7 +508,18 @@ export class HaConfigDeviceDashboard extends LitElement {
|
|||||||
this._showDisabled,
|
this._showDisabled,
|
||||||
this.hass.localize
|
this.hass.localize
|
||||||
);
|
);
|
||||||
|
if (filteredConfigEntry?.domain === "zha") {
|
||||||
|
navigate(`/config/zha/add`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (filteredConfigEntry?.domain === "zwave_js") {
|
||||||
|
this._showZJSAddDeviceDialog(filteredConfigEntry);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
showAddIntegrationDialog(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
private _showZJSAddDeviceDialog(filteredConfigEntry: ConfigEntry) {
|
||||||
showZWaveJSAddNodeDialog(this, {
|
showZWaveJSAddNodeDialog(this, {
|
||||||
entry_id: filteredConfigEntry!.entry_id,
|
entry_id: filteredConfigEntry!.entry_id,
|
||||||
});
|
});
|
||||||
|
@ -10,7 +10,7 @@ import {
|
|||||||
EnergyPreferencesValidation,
|
EnergyPreferencesValidation,
|
||||||
EnergyValidationIssue,
|
EnergyValidationIssue,
|
||||||
GasSourceTypeEnergyPreference,
|
GasSourceTypeEnergyPreference,
|
||||||
getEnergyGasUnitCategory,
|
getEnergyGasUnitClass,
|
||||||
saveEnergyPreferences,
|
saveEnergyPreferences,
|
||||||
} from "../../../../data/energy";
|
} from "../../../../data/energy";
|
||||||
import {
|
import {
|
||||||
@ -133,7 +133,7 @@ export class EnergyGasSettings extends LitElement {
|
|||||||
|
|
||||||
private _addSource() {
|
private _addSource() {
|
||||||
showEnergySettingsGasDialog(this, {
|
showEnergySettingsGasDialog(this, {
|
||||||
allowedGasUnitCategory: getEnergyGasUnitCategory(
|
allowedGasUnitClass: getEnergyGasUnitClass(
|
||||||
this.preferences,
|
this.preferences,
|
||||||
this.statsMetadata
|
this.statsMetadata
|
||||||
),
|
),
|
||||||
@ -152,7 +152,7 @@ export class EnergyGasSettings extends LitElement {
|
|||||||
ev.currentTarget.closest(".row").source;
|
ev.currentTarget.closest(".row").source;
|
||||||
showEnergySettingsGasDialog(this, {
|
showEnergySettingsGasDialog(this, {
|
||||||
source: { ...origSource },
|
source: { ...origSource },
|
||||||
allowedGasUnitCategory: getEnergyGasUnitCategory(
|
allowedGasUnitClass: getEnergyGasUnitClass(
|
||||||
this.preferences,
|
this.preferences,
|
||||||
this.statsMetadata,
|
this.statsMetadata,
|
||||||
origSource.stat_energy_from
|
origSource.stat_energy_from
|
||||||
|
@ -14,8 +14,7 @@ import { EnergySettingsBatteryDialogParams } from "./show-dialogs-energy";
|
|||||||
import "@material/mwc-button/mwc-button";
|
import "@material/mwc-button/mwc-button";
|
||||||
import "../../../../components/entity/ha-statistic-picker";
|
import "../../../../components/entity/ha-statistic-picker";
|
||||||
|
|
||||||
const energyUnits = ["kWh"];
|
const energyUnitClasses = ["energy"];
|
||||||
const energyDeviceClasses = ["energy"];
|
|
||||||
|
|
||||||
@customElement("dialog-energy-battery-settings")
|
@customElement("dialog-energy-battery-settings")
|
||||||
export class DialogEnergyBatterySettings
|
export class DialogEnergyBatterySettings
|
||||||
@ -67,8 +66,7 @@ export class DialogEnergyBatterySettings
|
|||||||
|
|
||||||
<ha-statistic-picker
|
<ha-statistic-picker
|
||||||
.hass=${this.hass}
|
.hass=${this.hass}
|
||||||
.includeStatisticsUnitOfMeasurement=${energyUnits}
|
.includeUnitClass=${energyUnitClasses}
|
||||||
.includeDeviceClasses=${energyDeviceClasses}
|
|
||||||
.value=${this._source.stat_energy_to}
|
.value=${this._source.stat_energy_to}
|
||||||
.label=${this.hass.localize(
|
.label=${this.hass.localize(
|
||||||
"ui.panel.config.energy.battery.dialog.energy_into_battery"
|
"ui.panel.config.energy.battery.dialog.energy_into_battery"
|
||||||
@ -79,8 +77,7 @@ export class DialogEnergyBatterySettings
|
|||||||
|
|
||||||
<ha-statistic-picker
|
<ha-statistic-picker
|
||||||
.hass=${this.hass}
|
.hass=${this.hass}
|
||||||
.includeStatisticsUnitOfMeasurement=${energyUnits}
|
.includeUnitClass=${energyUnitClasses}
|
||||||
.includeDeviceClasses=${energyDeviceClasses}
|
|
||||||
.value=${this._source.stat_energy_from}
|
.value=${this._source.stat_energy_from}
|
||||||
.label=${this.hass.localize(
|
.label=${this.hass.localize(
|
||||||
"ui.panel.config.energy.battery.dialog.energy_out_of_battery"
|
"ui.panel.config.energy.battery.dialog.energy_out_of_battery"
|
||||||
|
@ -14,8 +14,7 @@ import "../../../../components/ha-radio";
|
|||||||
import "../../../../components/ha-formfield";
|
import "../../../../components/ha-formfield";
|
||||||
import "../../../../components/entity/ha-entity-picker";
|
import "../../../../components/entity/ha-entity-picker";
|
||||||
|
|
||||||
const energyUnits = ["kWh"];
|
const energyUnitClasses = ["energy"];
|
||||||
const energyDeviceClasses = ["energy"];
|
|
||||||
|
|
||||||
@customElement("dialog-energy-device-settings")
|
@customElement("dialog-energy-device-settings")
|
||||||
export class DialogEnergyDeviceSettings
|
export class DialogEnergyDeviceSettings
|
||||||
@ -69,8 +68,7 @@ export class DialogEnergyDeviceSettings
|
|||||||
|
|
||||||
<ha-statistic-picker
|
<ha-statistic-picker
|
||||||
.hass=${this.hass}
|
.hass=${this.hass}
|
||||||
.includeStatisticsUnitOfMeasurement=${energyUnits}
|
.includeUnitClass=${energyUnitClasses}
|
||||||
.includeDeviceClasses=${energyDeviceClasses}
|
|
||||||
.label=${this.hass.localize(
|
.label=${this.hass.localize(
|
||||||
"ui.panel.config.energy.device_consumption.dialog.device_consumption_energy"
|
"ui.panel.config.energy.device_consumption.dialog.device_consumption_energy"
|
||||||
)}
|
)}
|
||||||
|
@ -5,9 +5,6 @@ import { fireEvent } from "../../../../common/dom/fire_event";
|
|||||||
import "../../../../components/ha-dialog";
|
import "../../../../components/ha-dialog";
|
||||||
import {
|
import {
|
||||||
emptyGasEnergyPreference,
|
emptyGasEnergyPreference,
|
||||||
ENERGY_GAS_ENERGY_UNITS,
|
|
||||||
ENERGY_GAS_UNITS,
|
|
||||||
ENERGY_GAS_VOLUME_UNITS,
|
|
||||||
GasSourceTypeEnergyPreference,
|
GasSourceTypeEnergyPreference,
|
||||||
} from "../../../../data/energy";
|
} from "../../../../data/energy";
|
||||||
import { HassDialog } from "../../../../dialogs/make-dialog-manager";
|
import { HassDialog } from "../../../../dialogs/make-dialog-manager";
|
||||||
@ -21,7 +18,10 @@ import "../../../../components/ha-radio";
|
|||||||
import "../../../../components/ha-formfield";
|
import "../../../../components/ha-formfield";
|
||||||
import "../../../../components/ha-textfield";
|
import "../../../../components/ha-textfield";
|
||||||
import type { HaRadio } from "../../../../components/ha-radio";
|
import type { HaRadio } from "../../../../components/ha-radio";
|
||||||
import { getStatisticMetadata } from "../../../../data/recorder";
|
import {
|
||||||
|
getStatisticMetadata,
|
||||||
|
getDisplayUnit,
|
||||||
|
} from "../../../../data/recorder";
|
||||||
|
|
||||||
@customElement("dialog-energy-gas-settings")
|
@customElement("dialog-energy-gas-settings")
|
||||||
export class DialogEnergyGasSettings
|
export class DialogEnergyGasSettings
|
||||||
@ -38,7 +38,7 @@ export class DialogEnergyGasSettings
|
|||||||
|
|
||||||
@state() private _pickableUnit?: string;
|
@state() private _pickableUnit?: string;
|
||||||
|
|
||||||
@state() private _pickedDisplayUnit?: string;
|
@state() private _pickedDisplayUnit?: string | null;
|
||||||
|
|
||||||
@state() private _error?: string;
|
@state() private _error?: string;
|
||||||
|
|
||||||
@ -49,7 +49,11 @@ export class DialogEnergyGasSettings
|
|||||||
this._source = params.source
|
this._source = params.source
|
||||||
? { ...params.source }
|
? { ...params.source }
|
||||||
: emptyGasEnergyPreference();
|
: emptyGasEnergyPreference();
|
||||||
this._pickedDisplayUnit = params.metadata?.display_unit_of_measurement;
|
this._pickedDisplayUnit = getDisplayUnit(
|
||||||
|
this.hass,
|
||||||
|
params.source?.stat_energy_from,
|
||||||
|
params.metadata
|
||||||
|
);
|
||||||
this._costs = this._source.entity_energy_price
|
this._costs = this._source.entity_energy_price
|
||||||
? "entity"
|
? "entity"
|
||||||
: this._source.number_energy_price
|
: this._source.number_energy_price
|
||||||
@ -75,9 +79,9 @@ export class DialogEnergyGasSettings
|
|||||||
|
|
||||||
const pickableUnit =
|
const pickableUnit =
|
||||||
this._pickableUnit ||
|
this._pickableUnit ||
|
||||||
(this._params.allowedGasUnitCategory === undefined
|
(this._params.allowedGasUnitClass === undefined
|
||||||
? "ft³, m³, Wh, kWh or MWh"
|
? "ft³, m³, Wh, kWh or MWh"
|
||||||
: this._params.allowedGasUnitCategory === "energy"
|
: this._params.allowedGasUnitClass === "energy"
|
||||||
? "Wh, kWh or MWh"
|
? "Wh, kWh or MWh"
|
||||||
: "ft³ or m³");
|
: "ft³ or m³");
|
||||||
|
|
||||||
@ -98,17 +102,12 @@ export class DialogEnergyGasSettings
|
|||||||
|
|
||||||
<ha-statistic-picker
|
<ha-statistic-picker
|
||||||
.hass=${this.hass}
|
.hass=${this.hass}
|
||||||
.includeStatisticsUnitOfMeasurement=${this._params
|
.includeUnitClass=${this._params.allowedGasUnitClass}
|
||||||
.allowedGasUnitCategory === undefined
|
|
||||||
? ENERGY_GAS_UNITS
|
|
||||||
: this._params.allowedGasUnitCategory === "energy"
|
|
||||||
? ENERGY_GAS_ENERGY_UNITS
|
|
||||||
: ENERGY_GAS_VOLUME_UNITS}
|
|
||||||
.value=${this._source.stat_energy_from}
|
.value=${this._source.stat_energy_from}
|
||||||
.label=${`${this.hass.localize(
|
.label=${`${this.hass.localize(
|
||||||
"ui.panel.config.energy.gas.dialog.gas_usage"
|
"ui.panel.config.energy.gas.dialog.gas_usage"
|
||||||
)} (${
|
)} (${
|
||||||
this._params.allowedGasUnitCategory === undefined
|
this._params.allowedGasUnitClass === undefined
|
||||||
? this.hass.localize(
|
? this.hass.localize(
|
||||||
"ui.panel.config.energy.gas.dialog.m3_or_kWh"
|
"ui.panel.config.energy.gas.dialog.m3_or_kWh"
|
||||||
)
|
)
|
||||||
@ -263,14 +262,12 @@ export class DialogEnergyGasSettings
|
|||||||
|
|
||||||
private async _statisticChanged(ev: CustomEvent<{ value: string }>) {
|
private async _statisticChanged(ev: CustomEvent<{ value: string }>) {
|
||||||
if (ev.detail.value) {
|
if (ev.detail.value) {
|
||||||
const entity = this.hass.states[ev.detail.value];
|
const metadata = await getStatisticMetadata(this.hass, [ev.detail.value]);
|
||||||
if (entity?.attributes.unit_of_measurement) {
|
this._pickedDisplayUnit = getDisplayUnit(
|
||||||
this._pickedDisplayUnit = entity.attributes.unit_of_measurement;
|
this.hass,
|
||||||
} else {
|
ev.detail.value,
|
||||||
this._pickedDisplayUnit = (
|
metadata[0]
|
||||||
await getStatisticMetadata(this.hass, [ev.detail.value])
|
);
|
||||||
)[0]?.display_unit_of_measurement;
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
this._pickedDisplayUnit = undefined;
|
this._pickedDisplayUnit = undefined;
|
||||||
}
|
}
|
||||||
|
@ -20,8 +20,7 @@ import "../../../../components/ha-formfield";
|
|||||||
import type { HaRadio } from "../../../../components/ha-radio";
|
import type { HaRadio } from "../../../../components/ha-radio";
|
||||||
import "../../../../components/entity/ha-entity-picker";
|
import "../../../../components/entity/ha-entity-picker";
|
||||||
|
|
||||||
const energyUnits = ["kWh"];
|
const energyUnitClasses = ["energy"];
|
||||||
const energyDeviceClasses = ["energy"];
|
|
||||||
|
|
||||||
@customElement("dialog-energy-grid-flow-settings")
|
@customElement("dialog-energy-grid-flow-settings")
|
||||||
export class DialogEnergyGridFlowSettings
|
export class DialogEnergyGridFlowSettings
|
||||||
@ -93,8 +92,7 @@ export class DialogEnergyGridFlowSettings
|
|||||||
|
|
||||||
<ha-statistic-picker
|
<ha-statistic-picker
|
||||||
.hass=${this.hass}
|
.hass=${this.hass}
|
||||||
.includeStatisticsUnitOfMeasurement=${energyUnits}
|
.includeUnitClass=${energyUnitClasses}
|
||||||
.includeDeviceClasses=${energyDeviceClasses}
|
|
||||||
.value=${this._source[
|
.value=${this._source[
|
||||||
this._params.direction === "from"
|
this._params.direction === "from"
|
||||||
? "stat_energy_from"
|
? "stat_energy_from"
|
||||||
|
@ -22,8 +22,7 @@ import { showConfigFlowDialog } from "../../../../dialogs/config-flow/show-dialo
|
|||||||
import { ConfigEntry, getConfigEntries } from "../../../../data/config_entries";
|
import { ConfigEntry, getConfigEntries } from "../../../../data/config_entries";
|
||||||
import { brandsUrl } from "../../../../util/brands-url";
|
import { brandsUrl } from "../../../../util/brands-url";
|
||||||
|
|
||||||
const energyUnits = ["kWh"];
|
const energyUnitClasses = ["energy"];
|
||||||
const energyDeviceClasses = ["energy"];
|
|
||||||
|
|
||||||
@customElement("dialog-energy-solar-settings")
|
@customElement("dialog-energy-solar-settings")
|
||||||
export class DialogEnergySolarSettings
|
export class DialogEnergySolarSettings
|
||||||
@ -79,8 +78,7 @@ export class DialogEnergySolarSettings
|
|||||||
|
|
||||||
<ha-statistic-picker
|
<ha-statistic-picker
|
||||||
.hass=${this.hass}
|
.hass=${this.hass}
|
||||||
.includeStatisticsUnitOfMeasurement=${energyUnits}
|
.includeUnitClass=${energyUnitClasses}
|
||||||
.includeDeviceClasses=${energyDeviceClasses}
|
|
||||||
.value=${this._source.stat_energy_from}
|
.value=${this._source.stat_energy_from}
|
||||||
.label=${this.hass.localize(
|
.label=${this.hass.localize(
|
||||||
"ui.panel.config.energy.solar.dialog.solar_production_energy"
|
"ui.panel.config.energy.solar.dialog.solar_production_energy"
|
||||||
|
@ -2,7 +2,7 @@ import { fireEvent } from "../../../../common/dom/fire_event";
|
|||||||
import {
|
import {
|
||||||
BatterySourceTypeEnergyPreference,
|
BatterySourceTypeEnergyPreference,
|
||||||
DeviceConsumptionEnergyPreference,
|
DeviceConsumptionEnergyPreference,
|
||||||
EnergyGasUnit,
|
EnergyGasUnitClass,
|
||||||
EnergyInfo,
|
EnergyInfo,
|
||||||
FlowFromGridSourceEnergyPreference,
|
FlowFromGridSourceEnergyPreference,
|
||||||
FlowToGridSourceEnergyPreference,
|
FlowToGridSourceEnergyPreference,
|
||||||
@ -46,7 +46,7 @@ export interface EnergySettingsBatteryDialogParams {
|
|||||||
|
|
||||||
export interface EnergySettingsGasDialogParams {
|
export interface EnergySettingsGasDialogParams {
|
||||||
source?: GasSourceTypeEnergyPreference;
|
source?: GasSourceTypeEnergyPreference;
|
||||||
allowedGasUnitCategory?: EnergyGasUnit;
|
allowedGasUnitClass?: EnergyGasUnitClass;
|
||||||
metadata?: StatisticsMetaData;
|
metadata?: StatisticsMetaData;
|
||||||
saveCallback: (source: GasSourceTypeEnergyPreference) => Promise<void>;
|
saveCallback: (source: GasSourceTypeEnergyPreference) => Promise<void>;
|
||||||
}
|
}
|
||||||
|
@ -219,19 +219,18 @@ class HaScheduleForm extends LitElement {
|
|||||||
|
|
||||||
const start = new Date();
|
const start = new Date();
|
||||||
start.setDate(start.getDate() + distance);
|
start.setDate(start.getDate() + distance);
|
||||||
|
const start_tokens = item.from.split(":");
|
||||||
start.setHours(
|
start.setHours(
|
||||||
parseInt(item.from.slice(0, 2)),
|
parseInt(start_tokens[0]),
|
||||||
parseInt(item.from.slice(-2))
|
parseInt(start_tokens[1]),
|
||||||
|
0,
|
||||||
|
0
|
||||||
);
|
);
|
||||||
|
|
||||||
const end = new Date();
|
const end = new Date();
|
||||||
end.setDate(end.getDate() + distance);
|
end.setDate(end.getDate() + distance);
|
||||||
end.setHours(
|
const end_tokens = item.to.split(":");
|
||||||
parseInt(item.to.slice(0, 2)),
|
end.setHours(parseInt(end_tokens[0]), parseInt(end_tokens[1]), 0, 0);
|
||||||
parseInt(item.to.slice(-2)),
|
|
||||||
0,
|
|
||||||
0
|
|
||||||
);
|
|
||||||
|
|
||||||
events.push({
|
events.push({
|
||||||
id: `${day}-${index}`,
|
id: `${day}-${index}`,
|
||||||
|
@ -80,10 +80,10 @@ class AddIntegrationDialog extends LitElement {
|
|||||||
|
|
||||||
private _height?: number;
|
private _height?: number;
|
||||||
|
|
||||||
public showDialog(params: AddIntegrationDialogParams): void {
|
public showDialog(params?: AddIntegrationDialogParams): void {
|
||||||
this._open = true;
|
this._open = true;
|
||||||
this._pickedBrand = params.brand;
|
this._pickedBrand = params?.brand;
|
||||||
this._initialFilter = params.initialFilter;
|
this._initialFilter = params?.initialFilter;
|
||||||
this._narrow = matchMedia(
|
this._narrow = matchMedia(
|
||||||
"all and (max-width: 450px), all and (max-height: 500px)"
|
"all and (max-width: 450px), all and (max-height: 500px)"
|
||||||
).matches;
|
).matches;
|
||||||
@ -296,14 +296,13 @@ class AddIntegrationDialog extends LitElement {
|
|||||||
scrimClickAction
|
scrimClickAction
|
||||||
escapeKeyAction
|
escapeKeyAction
|
||||||
hideActions
|
hideActions
|
||||||
.heading=${this._pickedBrand
|
.heading=${createCloseHeading(
|
||||||
? true
|
this.hass,
|
||||||
: createCloseHeading(
|
this.hass.localize("ui.panel.config.integrations.new")
|
||||||
this.hass,
|
)}
|
||||||
this.hass.localize("ui.panel.config.integrations.new")
|
|
||||||
)}
|
|
||||||
>
|
>
|
||||||
${this._pickedBrand
|
${this._pickedBrand &&
|
||||||
|
(!this._integrations || this._pickedBrand in this._integrations)
|
||||||
? html`<div slot="heading">
|
? html`<div slot="heading">
|
||||||
<ha-icon-button-prev
|
<ha-icon-button-prev
|
||||||
@click=${this._prevClicked}
|
@click=${this._prevClicked}
|
||||||
@ -385,7 +384,11 @@ class AddIntegrationDialog extends LitElement {
|
|||||||
return html``;
|
return html``;
|
||||||
}
|
}
|
||||||
return html`
|
return html`
|
||||||
<ha-integration-list-item .hass=${this.hass} .integration=${integration}>
|
<ha-integration-list-item
|
||||||
|
brand
|
||||||
|
.hass=${this.hass}
|
||||||
|
.integration=${integration}
|
||||||
|
>
|
||||||
</ha-integration-list-item>
|
</ha-integration-list-item>
|
||||||
`;
|
`;
|
||||||
};
|
};
|
||||||
@ -506,7 +509,16 @@ class AddIntegrationDialog extends LitElement {
|
|||||||
if (integration.integrations) {
|
if (integration.integrations) {
|
||||||
const integrations =
|
const integrations =
|
||||||
this._integrations![integration.domain].integrations!;
|
this._integrations![integration.domain].integrations!;
|
||||||
this._fetchFlowsInProgress(Object.keys(integrations));
|
let domains = Object.keys(integrations);
|
||||||
|
if (integration.iot_standards?.includes("homekit")) {
|
||||||
|
// if homekit is supported, also fetch the discovered homekit devices
|
||||||
|
domains.push("homekit_controller");
|
||||||
|
}
|
||||||
|
if (integration.domain === "apple") {
|
||||||
|
// we show discoverd homekit devices in their own brand section, dont show them at apple
|
||||||
|
domains = domains.filter((domain) => domain !== "homekit_controller");
|
||||||
|
}
|
||||||
|
this._fetchFlowsInProgress(domains);
|
||||||
this._pickedBrand = integration.domain;
|
this._pickedBrand = integration.domain;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -529,6 +541,15 @@ class AddIntegrationDialog extends LitElement {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
["cloud", "google_assistant", "alexa"].includes(integration.domain) &&
|
||||||
|
isComponentLoaded(this.hass, "cloud")
|
||||||
|
) {
|
||||||
|
this.closeDialog();
|
||||||
|
navigate("/config/cloud");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const manifest = await fetchIntegrationManifest(
|
const manifest = await fetchIntegrationManifest(
|
||||||
this.hass,
|
this.hass,
|
||||||
integration.domain
|
integration.domain
|
||||||
@ -591,7 +612,14 @@ class AddIntegrationDialog extends LitElement {
|
|||||||
private async _fetchFlowsInProgress(domains: string[]) {
|
private async _fetchFlowsInProgress(domains: string[]) {
|
||||||
const flowsInProgress = (
|
const flowsInProgress = (
|
||||||
await fetchConfigFlowInProgress(this.hass.connection)
|
await fetchConfigFlowInProgress(this.hass.connection)
|
||||||
).filter((flow) => domains.includes(flow.handler));
|
).filter(
|
||||||
|
(flow) =>
|
||||||
|
// filter config flows that are not for the integration we are looking for
|
||||||
|
domains.includes(flow.handler) ||
|
||||||
|
// filter config flows of other domains (like homekit) that are for the domains we are looking for
|
||||||
|
("alternative_domain" in flow.context &&
|
||||||
|
domains.includes(flow.context.alternative_domain))
|
||||||
|
);
|
||||||
|
|
||||||
if (flowsInProgress.length) {
|
if (flowsInProgress.length) {
|
||||||
this._flowsInProgress = flowsInProgress;
|
this._flowsInProgress = flowsInProgress;
|
||||||
|
@ -1,7 +1,9 @@
|
|||||||
import { css, html, LitElement } from "lit";
|
import { css, html, LitElement } from "lit";
|
||||||
import { customElement, property } from "lit/decorators";
|
import { customElement, property } from "lit/decorators";
|
||||||
|
import { isComponentLoaded } from "../../../common/config/is_component_loaded";
|
||||||
import { fireEvent } from "../../../common/dom/fire_event";
|
import { fireEvent } from "../../../common/dom/fire_event";
|
||||||
import { protocolIntegrationPicked } from "../../../common/integrations/protocolIntegrationPicked";
|
import { protocolIntegrationPicked } from "../../../common/integrations/protocolIntegrationPicked";
|
||||||
|
import { navigate } from "../../../common/navigate";
|
||||||
import { caseInsensitiveStringCompare } from "../../../common/string/compare";
|
import { caseInsensitiveStringCompare } from "../../../common/string/compare";
|
||||||
import { localizeConfigFlowTitle } from "../../../data/config_flow";
|
import { localizeConfigFlowTitle } from "../../../data/config_flow";
|
||||||
import { DataEntryFlowProgress } from "../../../data/data_entry_flow";
|
import { DataEntryFlowProgress } from "../../../data/data_entry_flow";
|
||||||
@ -26,7 +28,7 @@ class HaDomainIntegrations extends LitElement {
|
|||||||
|
|
||||||
@property() public domain!: string;
|
@property() public domain!: string;
|
||||||
|
|
||||||
@property({ attribute: false }) public integration!: Integration;
|
@property({ attribute: false }) public integration?: Integration;
|
||||||
|
|
||||||
@property({ attribute: false })
|
@property({ attribute: false })
|
||||||
public flowsInProgress?: DataEntryFlowProgress[];
|
public flowsInProgress?: DataEntryFlowProgress[];
|
||||||
@ -179,9 +181,22 @@ class HaDomainIntegrations extends LitElement {
|
|||||||
|
|
||||||
private async _integrationPicked(ev) {
|
private async _integrationPicked(ev) {
|
||||||
const domain = ev.currentTarget.domain;
|
const domain = ev.currentTarget.domain;
|
||||||
|
|
||||||
if (
|
if (
|
||||||
(domain === this.domain && !this.integration.config_flow) ||
|
["cloud", "google_assistant", "alexa"].includes(domain) &&
|
||||||
!this.integration.integrations?.[domain]?.config_flow
|
isComponentLoaded(this.hass, "cloud")
|
||||||
|
) {
|
||||||
|
fireEvent(this, "close-dialog");
|
||||||
|
navigate("/config/cloud");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
(domain === this.domain &&
|
||||||
|
!this.integration!.config_flow &&
|
||||||
|
(!this.integration!.integrations?.[domain] ||
|
||||||
|
!this.integration!.integrations[domain].config_flow)) ||
|
||||||
|
!this.integration!.integrations?.[domain]?.config_flow
|
||||||
) {
|
) {
|
||||||
const manifest = await fetchIntegrationManifest(this.hass, domain);
|
const manifest = await fetchIntegrationManifest(this.hass, domain);
|
||||||
showAlertDialog(this, {
|
showAlertDialog(this, {
|
||||||
|
@ -22,6 +22,8 @@ export class HaIntegrationListItem extends ListItemBase {
|
|||||||
|
|
||||||
@property({ type: Boolean }) hasMeta = true;
|
@property({ type: Boolean }) hasMeta = true;
|
||||||
|
|
||||||
|
@property({ type: Boolean }) brand = false;
|
||||||
|
|
||||||
renderSingleLine() {
|
renderSingleLine() {
|
||||||
if (!this.integration) {
|
if (!this.integration) {
|
||||||
return html``;
|
return html``;
|
||||||
@ -51,6 +53,7 @@ export class HaIntegrationListItem extends ListItemBase {
|
|||||||
type: "icon",
|
type: "icon",
|
||||||
useFallback: true,
|
useFallback: true,
|
||||||
darkOptimized: this.hass.themes?.darkMode,
|
darkOptimized: this.hass.themes?.darkMode,
|
||||||
|
brand: this.brand,
|
||||||
})}
|
})}
|
||||||
referrerpolicy="no-referrer"
|
referrerpolicy="no-referrer"
|
||||||
/>
|
/>
|
||||||
|
@ -469,15 +469,9 @@ export class HaScriptEditor extends KeyboardShortcutMixin(LitElement) {
|
|||||||
) {
|
) {
|
||||||
fetchScriptFileConfig(this.hass, this.scriptId).then(
|
fetchScriptFileConfig(this.hass, this.scriptId).then(
|
||||||
(config) => {
|
(config) => {
|
||||||
// Normalize data: ensure sequence is a list
|
|
||||||
// Happens when people copy paste their scripts into the config
|
|
||||||
const value = config.sequence;
|
|
||||||
if (value && !Array.isArray(value)) {
|
|
||||||
config.sequence = [value];
|
|
||||||
}
|
|
||||||
this._dirty = false;
|
this._dirty = false;
|
||||||
this._readOnly = false;
|
this._readOnly = false;
|
||||||
this._config = config;
|
this._config = this._normalizeConfig(config);
|
||||||
},
|
},
|
||||||
(resp) => {
|
(resp) => {
|
||||||
const entity = Object.values(this.hass.entities).find(
|
const entity = Object.values(this.hass.entities).find(
|
||||||
@ -524,7 +518,7 @@ export class HaScriptEditor extends KeyboardShortcutMixin(LitElement) {
|
|||||||
|
|
||||||
if (changedProps.has("entityId") && this.entityId) {
|
if (changedProps.has("entityId") && this.entityId) {
|
||||||
getScriptStateConfig(this.hass, this.entityId).then((c) => {
|
getScriptStateConfig(this.hass, this.entityId).then((c) => {
|
||||||
this._config = c.config;
|
this._config = this._normalizeConfig(c.config);
|
||||||
});
|
});
|
||||||
const regEntry = this.hass.entities[this.entityId];
|
const regEntry = this.hass.entities[this.entityId];
|
||||||
if (regEntry?.unique_id) {
|
if (regEntry?.unique_id) {
|
||||||
@ -536,6 +530,16 @@ export class HaScriptEditor extends KeyboardShortcutMixin(LitElement) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private _normalizeConfig(config: ScriptConfig): ScriptConfig {
|
||||||
|
// Normalize data: ensure sequence is a list
|
||||||
|
// Happens when people copy paste their scripts into the config
|
||||||
|
const value = config.sequence;
|
||||||
|
if (value && !Array.isArray(value)) {
|
||||||
|
config.sequence = [value];
|
||||||
|
}
|
||||||
|
return config;
|
||||||
|
}
|
||||||
|
|
||||||
private _computeLabelCallback = (
|
private _computeLabelCallback = (
|
||||||
schema: SchemaUnion<ReturnType<typeof this._schema>>,
|
schema: SchemaUnion<ReturnType<typeof this._schema>>,
|
||||||
data: HaFormDataContainer
|
data: HaFormDataContainer
|
||||||
|
@ -28,6 +28,7 @@ import "../../../components/ha-svg-icon";
|
|||||||
import {
|
import {
|
||||||
deleteScript,
|
deleteScript,
|
||||||
fetchScriptFileConfig,
|
fetchScriptFileConfig,
|
||||||
|
getScriptStateConfig,
|
||||||
showScriptEditor,
|
showScriptEditor,
|
||||||
triggerScript,
|
triggerScript,
|
||||||
} from "../../../data/script";
|
} from "../../../data/script";
|
||||||
@ -311,17 +312,20 @@ class HaScriptPicker extends LitElement {
|
|||||||
)})`,
|
)})`,
|
||||||
});
|
});
|
||||||
} catch (err: any) {
|
} catch (err: any) {
|
||||||
|
if (err.status_code === 404) {
|
||||||
|
const response = await getScriptStateConfig(
|
||||||
|
this.hass,
|
||||||
|
script.entity_id
|
||||||
|
);
|
||||||
|
showScriptEditor(response.config);
|
||||||
|
return;
|
||||||
|
}
|
||||||
await showAlertDialog(this, {
|
await showAlertDialog(this, {
|
||||||
text:
|
text: this.hass.localize(
|
||||||
err.status_code === 404
|
"ui.panel.config.script.editor.load_error_unknown",
|
||||||
? this.hass.localize(
|
"err_no",
|
||||||
"ui.panel.config.script.editor.load_error_not_duplicable"
|
err.status_code
|
||||||
)
|
),
|
||||||
: this.hass.localize(
|
|
||||||
"ui.panel.config.script.editor.load_error_unknown",
|
|
||||||
"err_no",
|
|
||||||
err.status_code
|
|
||||||
),
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -138,10 +138,6 @@ class MoveDatadiskDialog extends LitElement {
|
|||||||
${device}
|
${device}
|
||||||
</mwc-list-item>`
|
</mwc-list-item>`
|
||||||
)}
|
)}
|
||||||
<mwc-list-item>Test</mwc-list-item>
|
|
||||||
<mwc-list-item>Test</mwc-list-item>
|
|
||||||
<mwc-list-item>Test</mwc-list-item>
|
|
||||||
<mwc-list-item>Test</mwc-list-item>
|
|
||||||
</ha-select>
|
</ha-select>
|
||||||
|
|
||||||
<mwc-button
|
<mwc-button
|
||||||
|
@ -74,12 +74,6 @@ class HaPanelDevStatistics extends SubscribeMixin(LitElement) {
|
|||||||
hidden: this.narrow,
|
hidden: this.narrow,
|
||||||
width: "20%",
|
width: "20%",
|
||||||
},
|
},
|
||||||
display_unit_of_measurement: {
|
|
||||||
title: "Display unit",
|
|
||||||
sortable: true,
|
|
||||||
filterable: true,
|
|
||||||
width: "10%",
|
|
||||||
},
|
|
||||||
statistics_unit_of_measurement: {
|
statistics_unit_of_measurement: {
|
||||||
title: "Statistics unit",
|
title: "Statistics unit",
|
||||||
sortable: true,
|
sortable: true,
|
||||||
@ -220,12 +214,12 @@ class HaPanelDevStatistics extends SubscribeMixin(LitElement) {
|
|||||||
this._data.push({
|
this._data.push({
|
||||||
statistic_id: statisticId,
|
statistic_id: statisticId,
|
||||||
statistics_unit_of_measurement: "",
|
statistics_unit_of_measurement: "",
|
||||||
display_unit_of_measurement: "",
|
|
||||||
source: "",
|
source: "",
|
||||||
state: this.hass.states[statisticId],
|
state: this.hass.states[statisticId],
|
||||||
issues: issues[statisticId],
|
issues: issues[statisticId],
|
||||||
has_mean: false,
|
has_mean: false,
|
||||||
has_sum: false,
|
has_sum: false,
|
||||||
|
unit_class: null,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -23,6 +23,7 @@ import "../../../components/ha-svg-icon";
|
|||||||
import {
|
import {
|
||||||
adjustStatisticsSum,
|
adjustStatisticsSum,
|
||||||
fetchStatistics,
|
fetchStatistics,
|
||||||
|
getDisplayUnit,
|
||||||
StatisticValue,
|
StatisticValue,
|
||||||
} from "../../../data/recorder";
|
} from "../../../data/recorder";
|
||||||
import type { DateTimeSelector, NumberSelector } from "../../../data/selector";
|
import type { DateTimeSelector, NumberSelector } from "../../../data/selector";
|
||||||
@ -59,7 +60,7 @@ export class DialogStatisticsFixUnsupportedUnitMetadata extends LitElement {
|
|||||||
};
|
};
|
||||||
|
|
||||||
private _amountSelector = memoizeOne(
|
private _amountSelector = memoizeOne(
|
||||||
(unit_of_measurement: string): NumberSelector => ({
|
(unit_of_measurement: string | undefined): NumberSelector => ({
|
||||||
number: {
|
number: {
|
||||||
step: 0.01,
|
step: 0.01,
|
||||||
unit_of_measurement,
|
unit_of_measurement,
|
||||||
@ -135,7 +136,11 @@ export class DialogStatisticsFixUnsupportedUnitMetadata extends LitElement {
|
|||||||
} else {
|
} else {
|
||||||
const data =
|
const data =
|
||||||
this._stats5min.length >= 2 ? this._stats5min : this._statsHour;
|
this._stats5min.length >= 2 ? this._stats5min : this._statsHour;
|
||||||
const unit = this._params!.statistic.display_unit_of_measurement;
|
const unit = getDisplayUnit(
|
||||||
|
this.hass,
|
||||||
|
this._params!.statistic.statistic_id,
|
||||||
|
this._params!.statistic
|
||||||
|
);
|
||||||
const rows: TemplateResult[] = [];
|
const rows: TemplateResult[] = [];
|
||||||
for (let i = 1; i < data.length; i++) {
|
for (let i = 1; i < data.length; i++) {
|
||||||
const stat = data[i];
|
const stat = data[i];
|
||||||
@ -192,6 +197,11 @@ export class DialogStatisticsFixUnsupportedUnitMetadata extends LitElement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private _renderAdjustStat() {
|
private _renderAdjustStat() {
|
||||||
|
const unit = getDisplayUnit(
|
||||||
|
this.hass,
|
||||||
|
this._params!.statistic.statistic_id,
|
||||||
|
this._params!.statistic
|
||||||
|
);
|
||||||
return html`
|
return html`
|
||||||
<div class="text-content">
|
<div class="text-content">
|
||||||
<b>Statistic:</b> ${this._params!.statistic.statistic_id}
|
<b>Statistic:</b> ${this._params!.statistic.statistic_id}
|
||||||
@ -220,9 +230,7 @@ export class DialogStatisticsFixUnsupportedUnitMetadata extends LitElement {
|
|||||||
<ha-selector-number
|
<ha-selector-number
|
||||||
label="New Value"
|
label="New Value"
|
||||||
.hass=${this.hass}
|
.hass=${this.hass}
|
||||||
.selector=${this._amountSelector(
|
.selector=${this._amountSelector(unit || undefined)}
|
||||||
this._params!.statistic.display_unit_of_measurement
|
|
||||||
)}
|
|
||||||
.value=${this._amount}
|
.value=${this._amount}
|
||||||
.disabled=${this._busy}
|
.disabled=${this._busy}
|
||||||
@value-changed=${(ev) => {
|
@value-changed=${(ev) => {
|
||||||
@ -299,6 +307,11 @@ export class DialogStatisticsFixUnsupportedUnitMetadata extends LitElement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private async _fixIssue(): Promise<void> {
|
private async _fixIssue(): Promise<void> {
|
||||||
|
const unit = getDisplayUnit(
|
||||||
|
this.hass,
|
||||||
|
this._params!.statistic.statistic_id,
|
||||||
|
this._params!.statistic
|
||||||
|
);
|
||||||
this._busy = true;
|
this._busy = true;
|
||||||
try {
|
try {
|
||||||
await adjustStatisticsSum(
|
await adjustStatisticsSum(
|
||||||
@ -306,7 +319,7 @@ export class DialogStatisticsFixUnsupportedUnitMetadata extends LitElement {
|
|||||||
this._params!.statistic.statistic_id,
|
this._params!.statistic.statistic_id,
|
||||||
this._chosenStat!.start,
|
this._chosenStat!.start,
|
||||||
this._amount! - this._origAmount!,
|
this._amount! - this._origAmount!,
|
||||||
this._params!.statistic.display_unit_of_measurement
|
unit || null
|
||||||
);
|
);
|
||||||
} catch (err: any) {
|
} catch (err: any) {
|
||||||
this._busy = false;
|
this._busy = false;
|
||||||
|
@ -315,8 +315,11 @@ class HuiEnergyDistrubutionCard
|
|||||||
${formatNumber(gasUsage || 0, this.hass.locale, {
|
${formatNumber(gasUsage || 0, this.hass.locale, {
|
||||||
maximumFractionDigits: 1,
|
maximumFractionDigits: 1,
|
||||||
})}
|
})}
|
||||||
${getEnergyGasUnit(prefs, this._data.statsMetadata) ||
|
${getEnergyGasUnit(
|
||||||
"m³"}
|
this.hass,
|
||||||
|
prefs,
|
||||||
|
this._data.statsMetadata
|
||||||
|
) || "m³"}
|
||||||
</div>
|
</div>
|
||||||
<svg width="80" height="30">
|
<svg width="80" height="30">
|
||||||
<path d="M40 0 v30" id="gas" />
|
<path d="M40 0 v30" id="gas" />
|
||||||
|
@ -274,7 +274,8 @@ export class HuiEnergyGasGraphCard
|
|||||||
) as GasSourceTypeEnergyPreference[];
|
) as GasSourceTypeEnergyPreference[];
|
||||||
|
|
||||||
this._unit =
|
this._unit =
|
||||||
getEnergyGasUnit(energyData.prefs, energyData.statsMetadata) || "m³";
|
getEnergyGasUnit(this.hass, energyData.prefs, energyData.statsMetadata) ||
|
||||||
|
"m³";
|
||||||
|
|
||||||
const datasets: ChartDataset<"bar", ScatterDataPoint[]>[] = [];
|
const datasets: ChartDataset<"bar", ScatterDataPoint[]>[] = [];
|
||||||
|
|
||||||
|
@ -130,7 +130,8 @@ export class HuiEnergySourcesTableCard
|
|||||||
);
|
);
|
||||||
|
|
||||||
const gasUnit =
|
const gasUnit =
|
||||||
getEnergyGasUnit(this._data.prefs, this._data.statsMetadata) || "";
|
getEnergyGasUnit(this.hass, this._data.prefs, this._data.statsMetadata) ||
|
||||||
|
"";
|
||||||
|
|
||||||
const compare = this._data.statsCompare !== undefined;
|
const compare = this._data.statsCompare !== undefined;
|
||||||
|
|
||||||
|
@ -205,7 +205,7 @@ export class HuiStatisticsGraphCardEditor
|
|||||||
...this._config,
|
...this._config,
|
||||||
stat_types: configured_stat_types,
|
stat_types: configured_stat_types,
|
||||||
};
|
};
|
||||||
const displayUnit = this._metaDatas?.[0]?.display_unit_of_measurement;
|
const unitClass = this._metaDatas?.[0]?.unit_class;
|
||||||
|
|
||||||
return html`
|
return html`
|
||||||
<ha-form
|
<ha-form
|
||||||
@ -223,7 +223,7 @@ export class HuiStatisticsGraphCardEditor
|
|||||||
.pickedStatisticLabel=${this.hass!.localize(
|
.pickedStatisticLabel=${this.hass!.localize(
|
||||||
"ui.panel.lovelace.editor.card.statistics-graph.picked_statistic"
|
"ui.panel.lovelace.editor.card.statistics-graph.picked_statistic"
|
||||||
)}
|
)}
|
||||||
.includeDisplayUnitOfMeasurement=${displayUnit}
|
.includeUnitClass=${unitClass}
|
||||||
.ignoreRestrictionsOnFirstStatistic=${true}
|
.ignoreRestrictionsOnFirstStatistic=${true}
|
||||||
.value=${this._configEntities}
|
.value=${this._configEntities}
|
||||||
.configValue=${"entities"}
|
.configValue=${"entities"}
|
||||||
|
@ -1,13 +1,26 @@
|
|||||||
import "@material/mwc-button";
|
import "@material/mwc-button";
|
||||||
|
import { ActionDetail } from "@material/mwc-list";
|
||||||
|
import { mdiCheck, mdiDotsVertical } from "@mdi/js";
|
||||||
import "@polymer/paper-tabs/paper-tab";
|
import "@polymer/paper-tabs/paper-tab";
|
||||||
import "@polymer/paper-tabs/paper-tabs";
|
import "@polymer/paper-tabs/paper-tabs";
|
||||||
import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit";
|
import {
|
||||||
import { customElement, property, state } from "lit/decorators";
|
css,
|
||||||
|
CSSResultGroup,
|
||||||
|
html,
|
||||||
|
LitElement,
|
||||||
|
PropertyValues,
|
||||||
|
TemplateResult,
|
||||||
|
} from "lit";
|
||||||
|
import { customElement, property, query, state } from "lit/decorators";
|
||||||
|
import { classMap } from "lit/directives/class-map";
|
||||||
import { fireEvent, HASSDomEvent } from "../../../../common/dom/fire_event";
|
import { fireEvent, HASSDomEvent } from "../../../../common/dom/fire_event";
|
||||||
|
import { stopPropagation } from "../../../../common/dom/stop_propagation";
|
||||||
import { navigate } from "../../../../common/navigate";
|
import { navigate } from "../../../../common/navigate";
|
||||||
|
import { deepEqual } from "../../../../common/util/deep-equal";
|
||||||
|
import "../../../../components/ha-alert";
|
||||||
import "../../../../components/ha-circular-progress";
|
import "../../../../components/ha-circular-progress";
|
||||||
import "../../../../components/ha-dialog";
|
import "../../../../components/ha-dialog";
|
||||||
import "../../../../components/ha-alert";
|
import { HaYamlEditor } from "../../../../components/ha-yaml-editor";
|
||||||
import type {
|
import type {
|
||||||
LovelaceBadgeConfig,
|
LovelaceBadgeConfig,
|
||||||
LovelaceCardConfig,
|
LovelaceCardConfig,
|
||||||
@ -20,6 +33,11 @@ import {
|
|||||||
import { haStyleDialog } from "../../../../resources/styles";
|
import { haStyleDialog } from "../../../../resources/styles";
|
||||||
import type { HomeAssistant } from "../../../../types";
|
import type { HomeAssistant } from "../../../../types";
|
||||||
import "../../components/hui-entity-editor";
|
import "../../components/hui-entity-editor";
|
||||||
|
import {
|
||||||
|
DEFAULT_VIEW_LAYOUT,
|
||||||
|
PANEL_VIEW_LAYOUT,
|
||||||
|
VIEWS_NO_BADGE_SUPPORT,
|
||||||
|
} from "../../views/const";
|
||||||
import { addView, deleteView, replaceView } from "../config-util";
|
import { addView, deleteView, replaceView } from "../config-util";
|
||||||
import "../hui-badge-preview";
|
import "../hui-badge-preview";
|
||||||
import { processEditorEntities } from "../process-editor-entities";
|
import { processEditorEntities } from "../process-editor-entities";
|
||||||
@ -31,12 +49,6 @@ import {
|
|||||||
import "./hui-view-editor";
|
import "./hui-view-editor";
|
||||||
import "./hui-view-visibility-editor";
|
import "./hui-view-visibility-editor";
|
||||||
import { EditViewDialogParams } from "./show-edit-view-dialog";
|
import { EditViewDialogParams } from "./show-edit-view-dialog";
|
||||||
import {
|
|
||||||
DEFAULT_VIEW_LAYOUT,
|
|
||||||
PANEL_VIEW_LAYOUT,
|
|
||||||
VIEWS_NO_BADGE_SUPPORT,
|
|
||||||
} from "../../views/const";
|
|
||||||
import { deepEqual } from "../../../../common/util/deep-equal";
|
|
||||||
|
|
||||||
@customElement("hui-dialog-edit-view")
|
@customElement("hui-dialog-edit-view")
|
||||||
export class HuiDialogEditView extends LitElement {
|
export class HuiDialogEditView extends LitElement {
|
||||||
@ -56,6 +68,10 @@ export class HuiDialogEditView extends LitElement {
|
|||||||
|
|
||||||
@state() private _dirty = false;
|
@state() private _dirty = false;
|
||||||
|
|
||||||
|
@state() private _yamlMode = false;
|
||||||
|
|
||||||
|
@query("ha-yaml-editor") private _editor?: HaYamlEditor;
|
||||||
|
|
||||||
private _curTabIndex = 0;
|
private _curTabIndex = 0;
|
||||||
|
|
||||||
get _type(): string {
|
get _type(): string {
|
||||||
@ -67,6 +83,16 @@ export class HuiDialogEditView extends LitElement {
|
|||||||
: this._config.type || DEFAULT_VIEW_LAYOUT;
|
: this._config.type || DEFAULT_VIEW_LAYOUT;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected updated(changedProperties: PropertyValues) {
|
||||||
|
if (this._yamlMode && changedProperties.has("_yamlMode")) {
|
||||||
|
const viewConfig = {
|
||||||
|
...this._config,
|
||||||
|
badges: this._badges,
|
||||||
|
};
|
||||||
|
this._editor?.setValue(viewConfig);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public showDialog(params: EditViewDialogParams): void {
|
public showDialog(params: EditViewDialogParams): void {
|
||||||
this._params = params;
|
this._params = params;
|
||||||
|
|
||||||
@ -89,6 +115,7 @@ export class HuiDialogEditView extends LitElement {
|
|||||||
this._params = undefined;
|
this._params = undefined;
|
||||||
this._config = {};
|
this._config = {};
|
||||||
this._badges = [];
|
this._badges = [];
|
||||||
|
this._yamlMode = false;
|
||||||
this._dirty = false;
|
this._dirty = false;
|
||||||
fireEvent(this, "dialog-closed", { dialog: this.localName });
|
fireEvent(this, "dialog-closed", { dialog: this.localName });
|
||||||
}
|
}
|
||||||
@ -111,62 +138,74 @@ export class HuiDialogEditView extends LitElement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let content;
|
let content;
|
||||||
switch (this._curTab) {
|
|
||||||
case "tab-settings":
|
if (this._yamlMode) {
|
||||||
content = html`
|
content = html`
|
||||||
<hui-view-editor
|
<ha-yaml-editor
|
||||||
.isNew=${this._params.viewIndex === undefined}
|
.hass=${this.hass}
|
||||||
.hass=${this.hass}
|
dialogInitialFocus
|
||||||
.config=${this._config}
|
@value-changed=${this._viewYamlChanged}
|
||||||
@view-config-changed=${this._viewConfigChanged}
|
></ha-yaml-editor>
|
||||||
></hui-view-editor>
|
`;
|
||||||
`;
|
} else {
|
||||||
break;
|
switch (this._curTab) {
|
||||||
case "tab-badges":
|
case "tab-settings":
|
||||||
content = html`
|
content = html`
|
||||||
${this._badges?.length
|
<hui-view-editor
|
||||||
? html`
|
.isNew=${this._params.viewIndex === undefined}
|
||||||
${VIEWS_NO_BADGE_SUPPORT.includes(this._type)
|
.hass=${this.hass}
|
||||||
? html`
|
.config=${this._config}
|
||||||
<ha-alert alert-type="warning">
|
@view-config-changed=${this._viewConfigChanged}
|
||||||
${this.hass!.localize(
|
></hui-view-editor>
|
||||||
"ui.panel.lovelace.editor.edit_badges.view_no_badges"
|
`;
|
||||||
)}
|
break;
|
||||||
</ha-alert>
|
case "tab-badges":
|
||||||
`
|
content = html`
|
||||||
: ""}
|
${this._badges?.length
|
||||||
<div class="preview-badges">
|
? html`
|
||||||
${this._badges.map(
|
${VIEWS_NO_BADGE_SUPPORT.includes(this._type)
|
||||||
(badgeConfig) => html`
|
? html`
|
||||||
<hui-badge-preview
|
<ha-alert alert-type="warning">
|
||||||
.hass=${this.hass}
|
${this.hass!.localize(
|
||||||
.config=${badgeConfig}
|
"ui.panel.lovelace.editor.edit_badges.view_no_badges"
|
||||||
></hui-badge-preview>
|
)}
|
||||||
`
|
</ha-alert>
|
||||||
)}
|
`
|
||||||
</div>
|
: ""}
|
||||||
`
|
<div class="preview-badges">
|
||||||
: ""}
|
${this._badges.map(
|
||||||
<hui-entity-editor
|
(badgeConfig) => html`
|
||||||
.hass=${this.hass}
|
<hui-badge-preview
|
||||||
.entities=${this._badges}
|
.hass=${this.hass}
|
||||||
@entities-changed=${this._badgesChanged}
|
.config=${badgeConfig}
|
||||||
></hui-entity-editor>
|
></hui-badge-preview>
|
||||||
`;
|
`
|
||||||
break;
|
)}
|
||||||
case "tab-visibility":
|
</div>
|
||||||
content = html`
|
`
|
||||||
<hui-view-visibility-editor
|
: ""}
|
||||||
.hass=${this.hass}
|
<hui-entity-editor
|
||||||
.config=${this._config}
|
.hass=${this.hass}
|
||||||
@view-visibility-changed=${this._viewVisibilityChanged}
|
.entities=${this._badges}
|
||||||
></hui-view-visibility-editor>
|
@entities-changed=${this._badgesChanged}
|
||||||
`;
|
></hui-entity-editor>
|
||||||
break;
|
`;
|
||||||
case "tab-cards":
|
break;
|
||||||
content = html` Cards `;
|
case "tab-visibility":
|
||||||
break;
|
content = html`
|
||||||
|
<hui-view-visibility-editor
|
||||||
|
.hass=${this.hass}
|
||||||
|
.config=${this._config}
|
||||||
|
@view-visibility-changed=${this._viewVisibilityChanged}
|
||||||
|
></hui-view-visibility-editor>
|
||||||
|
`;
|
||||||
|
break;
|
||||||
|
case "tab-cards":
|
||||||
|
content = html` Cards `;
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return html`
|
return html`
|
||||||
<ha-dialog
|
<ha-dialog
|
||||||
open
|
open
|
||||||
@ -174,31 +213,75 @@ export class HuiDialogEditView extends LitElement {
|
|||||||
escapeKeyAction
|
escapeKeyAction
|
||||||
@closed=${this.closeDialog}
|
@closed=${this.closeDialog}
|
||||||
.heading=${this._viewConfigTitle}
|
.heading=${this._viewConfigTitle}
|
||||||
|
class=${classMap({
|
||||||
|
"yaml-mode": this._yamlMode,
|
||||||
|
})}
|
||||||
>
|
>
|
||||||
<div slot="heading">
|
<div slot="heading">
|
||||||
<h2>${this._viewConfigTitle}</h2>
|
<h2>${this._viewConfigTitle}</h2>
|
||||||
<paper-tabs
|
<ha-button-menu
|
||||||
scrollable
|
slot="icons"
|
||||||
hide-scroll-buttons
|
fixed
|
||||||
.selected=${this._curTabIndex}
|
corner="BOTTOM_END"
|
||||||
@selected-item-changed=${this._handleTabSelected}
|
menuCorner="END"
|
||||||
|
@action=${this._handleAction}
|
||||||
|
@closed=${stopPropagation}
|
||||||
>
|
>
|
||||||
<paper-tab id="tab-settings" dialogInitialFocus
|
<ha-icon-button
|
||||||
>${this.hass!.localize(
|
slot="trigger"
|
||||||
"ui.panel.lovelace.editor.edit_view.tab_settings"
|
.label=${this.hass!.localize("ui.common.menu")}
|
||||||
)}</paper-tab
|
.path=${mdiDotsVertical}
|
||||||
>
|
></ha-icon-button>
|
||||||
<paper-tab id="tab-badges"
|
<mwc-list-item graphic="icon">
|
||||||
>${this.hass!.localize(
|
${this.hass!.localize(
|
||||||
"ui.panel.lovelace.editor.edit_view.tab_badges"
|
"ui.panel.lovelace.editor.edit_view.edit_ui"
|
||||||
)}</paper-tab
|
)}
|
||||||
>
|
${!this._yamlMode
|
||||||
<paper-tab id="tab-visibility"
|
? html`<ha-svg-icon
|
||||||
>${this.hass!.localize(
|
class="selected_menu_item"
|
||||||
"ui.panel.lovelace.editor.edit_view.tab_visibility"
|
slot="graphic"
|
||||||
)}</paper-tab
|
.path=${mdiCheck}
|
||||||
>
|
></ha-svg-icon>`
|
||||||
</paper-tabs>
|
: ``}
|
||||||
|
</mwc-list-item>
|
||||||
|
|
||||||
|
<mwc-list-item graphic="icon">
|
||||||
|
${this.hass!.localize(
|
||||||
|
"ui.panel.lovelace.editor.edit_view.edit_yaml"
|
||||||
|
)}
|
||||||
|
${this._yamlMode
|
||||||
|
? html`<ha-svg-icon
|
||||||
|
class="selected_menu_item"
|
||||||
|
slot="graphic"
|
||||||
|
.path=${mdiCheck}
|
||||||
|
></ha-svg-icon>`
|
||||||
|
: ``}
|
||||||
|
</mwc-list-item>
|
||||||
|
</ha-button-menu>
|
||||||
|
${!this._yamlMode
|
||||||
|
? html`<paper-tabs
|
||||||
|
scrollable
|
||||||
|
hide-scroll-buttons
|
||||||
|
.selected=${this._curTabIndex}
|
||||||
|
@selected-item-changed=${this._handleTabSelected}
|
||||||
|
>
|
||||||
|
<paper-tab id="tab-settings" dialogInitialFocus
|
||||||
|
>${this.hass!.localize(
|
||||||
|
"ui.panel.lovelace.editor.edit_view.tab_settings"
|
||||||
|
)}</paper-tab
|
||||||
|
>
|
||||||
|
<paper-tab id="tab-badges"
|
||||||
|
>${this.hass!.localize(
|
||||||
|
"ui.panel.lovelace.editor.edit_view.tab_badges"
|
||||||
|
)}</paper-tab
|
||||||
|
>
|
||||||
|
<paper-tab id="tab-visibility"
|
||||||
|
>${this.hass!.localize(
|
||||||
|
"ui.panel.lovelace.editor.edit_view.tab_visibility"
|
||||||
|
)}</paper-tab
|
||||||
|
>
|
||||||
|
</paper-tabs>`
|
||||||
|
: ""}
|
||||||
</div>
|
</div>
|
||||||
${content}
|
${content}
|
||||||
${this._params.viewIndex !== undefined
|
${this._params.viewIndex !== undefined
|
||||||
@ -235,6 +318,19 @@ export class HuiDialogEditView extends LitElement {
|
|||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async _handleAction(ev: CustomEvent<ActionDetail>) {
|
||||||
|
ev.stopPropagation();
|
||||||
|
ev.preventDefault();
|
||||||
|
switch (ev.detail.index) {
|
||||||
|
case 0:
|
||||||
|
this._yamlMode = false;
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
this._yamlMode = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private async _delete(): Promise<void> {
|
private async _delete(): Promise<void> {
|
||||||
if (!this._params) {
|
if (!this._params) {
|
||||||
return;
|
return;
|
||||||
@ -348,6 +444,17 @@ export class HuiDialogEditView extends LitElement {
|
|||||||
this._dirty = true;
|
this._dirty = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private _viewYamlChanged(ev: CustomEvent) {
|
||||||
|
ev.stopPropagation();
|
||||||
|
if (!ev.detail.isValid) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const { badges = [], ...config } = ev.detail.value;
|
||||||
|
this._config = config;
|
||||||
|
this._badges = badges;
|
||||||
|
this._dirty = true;
|
||||||
|
}
|
||||||
|
|
||||||
private _isConfigChanged(): boolean {
|
private _isConfigChanged(): boolean {
|
||||||
return (
|
return (
|
||||||
this._creatingView ||
|
this._creatingView ||
|
||||||
@ -366,6 +473,9 @@ export class HuiDialogEditView extends LitElement {
|
|||||||
return [
|
return [
|
||||||
haStyleDialog,
|
haStyleDialog,
|
||||||
css`
|
css`
|
||||||
|
ha-dialog.yaml-mode {
|
||||||
|
--dialog-content-padding: 0;
|
||||||
|
}
|
||||||
h2 {
|
h2 {
|
||||||
display: block;
|
display: block;
|
||||||
color: var(--primary-text-color);
|
color: var(--primary-text-color);
|
||||||
@ -421,6 +531,22 @@ export class HuiDialogEditView extends LitElement {
|
|||||||
ha-circular-progress[active] {
|
ha-circular-progress[active] {
|
||||||
display: block;
|
display: block;
|
||||||
}
|
}
|
||||||
|
ha-button-menu {
|
||||||
|
color: var(--secondary-text-color);
|
||||||
|
position: absolute;
|
||||||
|
right: 16px;
|
||||||
|
top: 14px;
|
||||||
|
inset-inline-end: 16px;
|
||||||
|
inset-inline-start: initial;
|
||||||
|
direction: var(--direction);
|
||||||
|
}
|
||||||
|
ha-button-menu,
|
||||||
|
ha-icon-button {
|
||||||
|
--mdc-theme-text-primary-on-background: var(--primary-text-color);
|
||||||
|
}
|
||||||
|
.selected_menu_item {
|
||||||
|
color: var(--primary-color);
|
||||||
|
}
|
||||||
.hidden {
|
.hidden {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
@ -33,7 +33,7 @@ export class HuiViewEditor extends LitElement {
|
|||||||
private _suggestedPath = false;
|
private _suggestedPath = false;
|
||||||
|
|
||||||
private _schema = memoizeOne(
|
private _schema = memoizeOne(
|
||||||
(localize: LocalizeFunc, subview: boolean, showAdvanced: boolean) =>
|
(localize: LocalizeFunc) =>
|
||||||
[
|
[
|
||||||
{ name: "title", selector: { text: {} } },
|
{ name: "title", selector: { text: {} } },
|
||||||
{
|
{
|
||||||
@ -69,14 +69,6 @@ export class HuiViewEditor extends LitElement {
|
|||||||
boolean: {},
|
boolean: {},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
...(subview && showAdvanced
|
|
||||||
? [
|
|
||||||
{
|
|
||||||
name: "back_path",
|
|
||||||
selector: { navigation: {} },
|
|
||||||
},
|
|
||||||
]
|
|
||||||
: []),
|
|
||||||
] as const
|
] as const
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -98,11 +90,7 @@ export class HuiViewEditor extends LitElement {
|
|||||||
return html``;
|
return html``;
|
||||||
}
|
}
|
||||||
|
|
||||||
const schema = this._schema(
|
const schema = this._schema(this.hass.localize);
|
||||||
this.hass.localize,
|
|
||||||
this._config.subview ?? false,
|
|
||||||
this.hass.userData?.showAdvanced ?? false
|
|
||||||
);
|
|
||||||
|
|
||||||
const data = {
|
const data = {
|
||||||
theme: "Backend-selected",
|
theme: "Backend-selected",
|
||||||
@ -128,9 +116,6 @@ export class HuiViewEditor extends LitElement {
|
|||||||
if (config.type === "masonry") {
|
if (config.type === "masonry") {
|
||||||
delete config.type;
|
delete config.type;
|
||||||
}
|
}
|
||||||
if (!config.subview) {
|
|
||||||
delete config.back_path;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (
|
if (
|
||||||
this.isNew &&
|
this.isNew &&
|
||||||
@ -155,10 +140,6 @@ export class HuiViewEditor extends LitElement {
|
|||||||
return this.hass.localize("ui.panel.lovelace.editor.edit_view.type");
|
return this.hass.localize("ui.panel.lovelace.editor.edit_view.type");
|
||||||
case "subview":
|
case "subview":
|
||||||
return this.hass.localize("ui.panel.lovelace.editor.edit_view.subview");
|
return this.hass.localize("ui.panel.lovelace.editor.edit_view.subview");
|
||||||
case "back_path":
|
|
||||||
return this.hass.localize(
|
|
||||||
"ui.panel.lovelace.editor.edit_view.back_path"
|
|
||||||
);
|
|
||||||
default:
|
default:
|
||||||
return this.hass!.localize(
|
return this.hass!.localize(
|
||||||
`ui.panel.lovelace.editor.card.generic.${schema.name}`
|
`ui.panel.lovelace.editor.card.generic.${schema.name}`
|
||||||
@ -174,10 +155,6 @@ export class HuiViewEditor extends LitElement {
|
|||||||
return this.hass.localize(
|
return this.hass.localize(
|
||||||
"ui.panel.lovelace.editor.edit_view.subview_helper"
|
"ui.panel.lovelace.editor.edit_view.subview_helper"
|
||||||
);
|
);
|
||||||
case "back_path":
|
|
||||||
return this.hass.localize(
|
|
||||||
"ui.panel.lovelace.editor.edit_view.back_path_helper"
|
|
||||||
);
|
|
||||||
default:
|
default:
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
|
@ -1855,8 +1855,8 @@
|
|||||||
"show_info": "Information",
|
"show_info": "Information",
|
||||||
"default_name": "New Automation",
|
"default_name": "New Automation",
|
||||||
"missing_name": "Cannot save automation without a name",
|
"missing_name": "Cannot save automation without a name",
|
||||||
|
"traces_not_available": "Automations need an ID for history to be tracked. Add an ID to your automation to make it available in traces.",
|
||||||
"load_error_not_editable": "Only automations in automations.yaml are editable.",
|
"load_error_not_editable": "Only automations in automations.yaml are editable.",
|
||||||
"load_error_not_duplicable": "Only automations in automations.yaml can be duplicated.",
|
|
||||||
"load_error_not_deletable": "Only automations in automations.yaml can be deleted.",
|
"load_error_not_deletable": "Only automations in automations.yaml can be deleted.",
|
||||||
"load_error_unknown": "Error loading automation ({err_no}).",
|
"load_error_unknown": "Error loading automation ({err_no}).",
|
||||||
"save": "Save",
|
"save": "Save",
|
||||||
@ -2341,7 +2341,6 @@
|
|||||||
"parallel": "Max number of parallel runs"
|
"parallel": "Max number of parallel runs"
|
||||||
},
|
},
|
||||||
"load_error_not_editable": "Only scripts inside scripts.yaml are editable.",
|
"load_error_not_editable": "Only scripts inside scripts.yaml are editable.",
|
||||||
"load_error_not_duplicable": "Only scripts in scripts.yaml can be duplicated.",
|
|
||||||
"load_error_not_deletable": "Only scripts in scripts.yaml can be deleted.",
|
"load_error_not_deletable": "Only scripts in scripts.yaml can be deleted.",
|
||||||
"load_error_unknown": "Error loading script ({err_no}).",
|
"load_error_unknown": "Error loading script ({err_no}).",
|
||||||
"delete_confirm_title": "Delete script?",
|
"delete_confirm_title": "Delete script?",
|
||||||
@ -2610,6 +2609,7 @@
|
|||||||
},
|
},
|
||||||
"devices": {
|
"devices": {
|
||||||
"add_prompt": "No {name} have been added using this {type} yet. You can add one by clicking the + button above.",
|
"add_prompt": "No {name} have been added using this {type} yet. You can add one by clicking the + button above.",
|
||||||
|
"add_device": "Add Device",
|
||||||
"caption": "Devices",
|
"caption": "Devices",
|
||||||
"description": "Manage configured devices",
|
"description": "Manage configured devices",
|
||||||
"device_info": "{type} info",
|
"device_info": "{type} info",
|
||||||
@ -2985,8 +2985,6 @@
|
|||||||
"error": "Error",
|
"error": "Error",
|
||||||
"could_not_load": "Config flow could not be loaded",
|
"could_not_load": "Config flow could not be loaded",
|
||||||
"not_loaded": "The integration could not be loaded, try to restart Home Assistant.",
|
"not_loaded": "The integration could not be loaded, try to restart Home Assistant.",
|
||||||
"missing_credentials_title": "Add application credentials?",
|
|
||||||
"missing_credentials": "Setting up {integration} requires configuring application credentials. Do you want to do that now?",
|
|
||||||
"supported_brand_flow": "Support for {supported_brand} devices is provided by {flow_domain_name}. Do you want to continue?",
|
"supported_brand_flow": "Support for {supported_brand} devices is provided by {flow_domain_name}. Do you want to continue?",
|
||||||
"missing_zwave_zigbee": "To add a {integration} device, you first need {supported_hardware_link} and the {integration} integration set up. If you already have the hardware then you can proceed with the setup of {integration}.",
|
"missing_zwave_zigbee": "To add a {integration} device, you first need {supported_hardware_link} and the {integration} integration set up. If you already have the hardware then you can proceed with the setup of {integration}.",
|
||||||
"supported_hardware": "supported hardware",
|
"supported_hardware": "supported hardware",
|
||||||
@ -3059,7 +3057,9 @@
|
|||||||
"editor": {
|
"editor": {
|
||||||
"caption": "Add Credential",
|
"caption": "Add Credential",
|
||||||
"description": "OAuth is used to grant Home Assistant access to information on other websites without giving a passwords. This mechanism is used by companies such as Spotify, Google, Withings, Microsoft, and Twitter.",
|
"description": "OAuth is used to grant Home Assistant access to information on other websites without giving a passwords. This mechanism is used by companies such as Spotify, Google, Withings, Microsoft, and Twitter.",
|
||||||
"view_documentation": "View documentation",
|
"missing_credentials": "Setting up {integration} requires configuring application credentials.",
|
||||||
|
"missing_credentials_domain_link": "View {integration} documentation",
|
||||||
|
"view_documentation": "View application credentials documentation",
|
||||||
"add": "Add",
|
"add": "Add",
|
||||||
"domain": "Integration",
|
"domain": "Integration",
|
||||||
"name": "Name",
|
"name": "Name",
|
||||||
@ -3804,8 +3804,8 @@
|
|||||||
},
|
},
|
||||||
"subview": "Subview",
|
"subview": "Subview",
|
||||||
"subview_helper": "Subviews don't appear in tabs and have a back button.",
|
"subview_helper": "Subviews don't appear in tabs and have a back button.",
|
||||||
"back_path": "Back path (optional)",
|
"edit_ui": "Edit in visual editor",
|
||||||
"back_path_helper": "Only for subviews. If empty, clicking on back button will go to the previous page."
|
"edit_yaml": "Edit in YAML"
|
||||||
},
|
},
|
||||||
"edit_badges": {
|
"edit_badges": {
|
||||||
"view_no_badges": "Badges are not be supported by the current view type."
|
"view_no_badges": "Badges are not be supported by the current view type."
|
||||||
|
@ -3,6 +3,7 @@ export interface BrandsOptions {
|
|||||||
type: "icon" | "logo" | "icon@2x" | "logo@2x";
|
type: "icon" | "logo" | "icon@2x" | "logo@2x";
|
||||||
useFallback?: boolean;
|
useFallback?: boolean;
|
||||||
darkOptimized?: boolean;
|
darkOptimized?: boolean;
|
||||||
|
brand?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface HardwareBrandsOptions {
|
export interface HardwareBrandsOptions {
|
||||||
@ -13,9 +14,11 @@ export interface HardwareBrandsOptions {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const brandsUrl = (options: BrandsOptions): string =>
|
export const brandsUrl = (options: BrandsOptions): string =>
|
||||||
`https://brands.home-assistant.io/${options.useFallback ? "_/" : ""}${
|
`https://brands.home-assistant.io/${options.brand ? "brands/" : ""}${
|
||||||
options.domain
|
options.useFallback ? "_/" : ""
|
||||||
}/${options.darkOptimized ? "dark_" : ""}${options.type}.png`;
|
}${options.domain}/${options.darkOptimized ? "dark_" : ""}${
|
||||||
|
options.type
|
||||||
|
}.png`;
|
||||||
|
|
||||||
export const hardwareBrandsUrl = (options: HardwareBrandsOptions): string =>
|
export const hardwareBrandsUrl = (options: HardwareBrandsOptions): string =>
|
||||||
`https://brands.home-assistant.io/hardware/${options.category}/${
|
`https://brands.home-assistant.io/hardware/${options.category}/${
|
||||||
|
Loading…
x
Reference in New Issue
Block a user