mirror of
https://github.com/home-assistant/frontend.git
synced 2026-07-01 20:52:21 +00:00
Compare commits
17 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 932e74fdaa | |||
| df65ba0a3d | |||
| 61cdc8ba82 | |||
| 2936614b54 | |||
| 627e7822cc | |||
| 3b4a17cf26 | |||
| 5422614fbe | |||
| e1e4b29227 | |||
| 49e74bc374 | |||
| cd539efc98 | |||
| 4cf70c40c9 | |||
| 1bc24d9dfa | |||
| e84cb85c8e | |||
| 23335fffdb | |||
| 0a93a681e3 | |||
| 7bc2cad83e | |||
| 39ee60a8ef |
@@ -67,7 +67,7 @@ DO NOT DELETE ANY TEXT from this template! Otherwise, your issue may be closed w
|
||||
<!--
|
||||
If your issue is about how an entity is shown in the UI, please add the state
|
||||
and attributes for all situations with a screenshot of the UI.
|
||||
You can find this information at `/config/developer-tools/state`
|
||||
You can find this information at `/config/tools/state`
|
||||
-->
|
||||
|
||||
```yaml
|
||||
|
||||
@@ -94,8 +94,8 @@ body:
|
||||
label: State of relevant entities
|
||||
description: >
|
||||
If your issue is about how an entity is shown in the UI, please add the
|
||||
state and attributes for all situations. You can find this information
|
||||
at Developer Tools -> States.
|
||||
state and attributes for all situations. You can find this
|
||||
information in the Details view of the More info dialog.
|
||||
render: txt
|
||||
- type: textarea
|
||||
attributes:
|
||||
|
||||
+1
-1
@@ -172,7 +172,7 @@
|
||||
"eslint": "10.6.0",
|
||||
"eslint-config-prettier": "10.1.8",
|
||||
"eslint-import-resolver-webpack": "0.13.11",
|
||||
"eslint-plugin-import-x": "4.17.0",
|
||||
"eslint-plugin-import-x": "4.17.1",
|
||||
"eslint-plugin-lit": "2.3.1",
|
||||
"eslint-plugin-lit-a11y": "5.1.1",
|
||||
"eslint-plugin-unused-imports": "4.4.1",
|
||||
|
||||
@@ -57,8 +57,8 @@ export const CONFIG_SUB_ROUTES: Record<
|
||||
translationKey: "ui.components.navigation-picker.route.scripts",
|
||||
iconPath: mdiScriptText,
|
||||
},
|
||||
"developer-tools": {
|
||||
translationKey: "ui.components.navigation-picker.route.developer_tools",
|
||||
tools: {
|
||||
translationKey: "ui.components.navigation-picker.route.tools",
|
||||
iconPath: mdiHammer,
|
||||
},
|
||||
integrations: {
|
||||
|
||||
+16
-6
@@ -27,6 +27,7 @@ export interface LogbookEntry {
|
||||
source?: string; // The trigger source (English phrase, parsed for the cause)
|
||||
domain?: string;
|
||||
state?: string; // The state of the entity
|
||||
attributes?: { event_type?: string }; // Selected attributes the backend surfaces
|
||||
// Context data
|
||||
context_id?: string;
|
||||
context_user_id?: string;
|
||||
@@ -244,13 +245,13 @@ export const parseTriggerSource = (source: string): ParsedTriggerSource => {
|
||||
};
|
||||
|
||||
// Short label shown instead of the bare timestamp for each timestamp-state
|
||||
// domain. Typed to TIMESTAMP_STATE_DOMAINS minus datetime (a real value), so a
|
||||
// new timestamp domain won't compile until it gets a label here.
|
||||
// domain. Typed to TIMESTAMP_STATE_DOMAINS minus datetime (a real value) and
|
||||
// event (handled separately via its event type), so a new timestamp domain
|
||||
// won't compile until it gets a label here.
|
||||
type LogbookActionMessage =
|
||||
| "pressed"
|
||||
| "activated"
|
||||
| "scanned"
|
||||
| "detected_event_no_type"
|
||||
| "updated"
|
||||
| "sent"
|
||||
| "detected"
|
||||
@@ -261,14 +262,13 @@ type LogbookActionMessage =
|
||||
| "command_sent";
|
||||
|
||||
const STATE_ACTION_MESSAGES: Record<
|
||||
Exclude<TimestampStateDomain, "datetime">,
|
||||
Exclude<TimestampStateDomain, "datetime" | "event">,
|
||||
LogbookActionMessage
|
||||
> = {
|
||||
button: "pressed",
|
||||
input_button: "pressed",
|
||||
scene: "activated",
|
||||
tag: "scanned",
|
||||
event: "detected_event_no_type",
|
||||
image: "updated",
|
||||
notify: "sent",
|
||||
wake_word: "detected",
|
||||
@@ -284,8 +284,18 @@ export const localizeStateMessage = (
|
||||
hass: HomeAssistant,
|
||||
state: string,
|
||||
stateObj: HassEntity,
|
||||
domain: string
|
||||
domain: string,
|
||||
attributes?: LogbookEntry["attributes"]
|
||||
): string => {
|
||||
// Events show the triggered event type, falling back to a generic label when
|
||||
// the type is unknown (the timestamp state is meaningless on its own).
|
||||
if (domain === "event") {
|
||||
const eventType = attributes?.event_type;
|
||||
if (eventType != null) {
|
||||
return hass.formatEntityAttributeValue(stateObj, "event_type", eventType);
|
||||
}
|
||||
return hass.localize(`${LOGBOOK_LOCALIZE_PATH}.detected_event_no_type`);
|
||||
}
|
||||
const actionKey: LogbookActionMessage | undefined =
|
||||
STATE_ACTION_MESSAGES[domain as keyof typeof STATE_ACTION_MESSAGES];
|
||||
if (actionKey) {
|
||||
|
||||
@@ -28,6 +28,21 @@ const useHash = __DEMO__;
|
||||
const curPath = () =>
|
||||
useHash ? location.hash.substring(1) : location.pathname;
|
||||
|
||||
// Developer tools was renamed to Tools (/config/tools) in 2026.8; it had moved
|
||||
// from /developer-tools to /config in 2026.2. Redirect both old locations to
|
||||
// the new one. Applied on the initial route and on every navigation so
|
||||
// bookmarks and external links to the old URLs resolve too, not just in-app
|
||||
// navigation.
|
||||
const redirectLegacyToolsPath = (path: string): string => {
|
||||
if (path.startsWith("/config/developer-tools")) {
|
||||
return path.replace("/config/developer-tools", "/config/tools");
|
||||
}
|
||||
if (path.startsWith("/developer-tools")) {
|
||||
return path.replace("/developer-tools", "/config/tools");
|
||||
}
|
||||
return path;
|
||||
};
|
||||
|
||||
const panelUrl = (path: string) => {
|
||||
const dividerPos = path.indexOf("/", 1);
|
||||
return dividerPos === -1 ? path.substring(1) : path.substring(1, dividerPos);
|
||||
@@ -50,7 +65,7 @@ export class HomeAssistantAppEl extends QuickBarMixin(HassElement) {
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
const path = curPath();
|
||||
const path = redirectLegacyToolsPath(curPath());
|
||||
|
||||
this._route = {
|
||||
prefix: "",
|
||||
@@ -106,10 +121,7 @@ export class HomeAssistantAppEl extends QuickBarMixin(HassElement) {
|
||||
|
||||
// Navigation
|
||||
const updateRoute = (path = curPath()) => {
|
||||
// Developer tools panel was moved to config in 2026.2
|
||||
if (path.startsWith("/developer-tools")) {
|
||||
path = path.replace("/developer-tools", "/config/developer-tools");
|
||||
}
|
||||
path = redirectLegacyToolsPath(path);
|
||||
if (this._route && path === this._route.path) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -211,8 +211,8 @@ export const configSections: Record<string, PageNavigation[]> = {
|
||||
adminOnly: true,
|
||||
},
|
||||
{
|
||||
path: "/config/developer-tools",
|
||||
translationKey: "developer_tools",
|
||||
path: "/config/tools",
|
||||
translationKey: "tools",
|
||||
iconPath: mdiHammer,
|
||||
iconColor: "#7A5AA6",
|
||||
core: true,
|
||||
@@ -328,10 +328,10 @@ export const configSections: Record<string, PageNavigation[]> = {
|
||||
adminOnly: true,
|
||||
},
|
||||
],
|
||||
developer_tools: [
|
||||
tools: [
|
||||
{
|
||||
path: "/config/developer-tools",
|
||||
translationKey: "ui.panel.config.dashboard.developer_tools.main",
|
||||
path: "/config/tools",
|
||||
translationKey: "ui.panel.config.dashboard.tools.main",
|
||||
iconPath: mdiHammer,
|
||||
iconColor: "#7A5AA6",
|
||||
core: true,
|
||||
|
||||
@@ -70,9 +70,9 @@ class HaPanelConfig extends HassRouterPage {
|
||||
tag: "ha-config-system-navigation",
|
||||
load: () => import("./core/ha-config-system-navigation"),
|
||||
},
|
||||
"developer-tools": {
|
||||
tag: "ha-panel-developer-tools",
|
||||
load: () => import("./developer-tools/ha-panel-developer-tools"),
|
||||
tools: {
|
||||
tag: "ha-panel-tools",
|
||||
load: () => import("./tools/ha-panel-tools"),
|
||||
cache: true,
|
||||
},
|
||||
logs: {
|
||||
|
||||
@@ -18,7 +18,7 @@ import {
|
||||
import { showConfigFlowDialog } from "../../../dialogs/config-flow/show-dialog-config-flow";
|
||||
import type { HomeAssistant } from "../../../types";
|
||||
import { brandsUrl } from "../../../util/brands-url";
|
||||
import { fixStatisticsIssue } from "../developer-tools/statistics/fix-statistics";
|
||||
import { fixStatisticsIssue } from "../tools/statistics/fix-statistics";
|
||||
import { showVacuumSegmentMappingDialog } from "../entities/dialogs/show-dialog-vacuum-segment-mapping";
|
||||
import { showRepairsFlowDialog } from "./show-dialog-repair-flow";
|
||||
import { showRepairsIssueDialog } from "./show-repair-issue-dialog";
|
||||
@@ -171,7 +171,7 @@ class HaConfigRepairs extends LitElement {
|
||||
issue.translation_key &&
|
||||
STATISTIC_TYPES.includes(issue.translation_key as any)
|
||||
) {
|
||||
this.hass.loadFragmentTranslation("developer-tools");
|
||||
this.hass.loadFragmentTranslation("config");
|
||||
const data = await fetchRepairsIssueData(
|
||||
this.hass.connection,
|
||||
issue.domain,
|
||||
|
||||
+23
-25
@@ -48,7 +48,7 @@ import { resolveMediaSource } from "../../../../data/media_source";
|
||||
import { MatchMinHeightMixin } from "../../../../mixins/match-min-height-mixin";
|
||||
import { withViewTransition } from "../../../../common/util/view-transition";
|
||||
|
||||
@customElement("developer-tools-action")
|
||||
@customElement("tools-action")
|
||||
class HaPanelDevAction extends MatchMinHeightMixin(LitElement) {
|
||||
@property({ attribute: false }) public hass!: HomeAssistant;
|
||||
|
||||
@@ -130,14 +130,12 @@ class HaPanelDevAction extends MatchMinHeightMixin(LitElement) {
|
||||
|
||||
const modeButtons: ToggleButton[] = [
|
||||
{
|
||||
label: this.hass.localize(
|
||||
"ui.panel.config.developer-tools.tabs.actions.ui_mode"
|
||||
),
|
||||
label: this.hass.localize("ui.panel.config.tools.tabs.actions.ui_mode"),
|
||||
value: "ui",
|
||||
},
|
||||
{
|
||||
label: this.hass.localize(
|
||||
"ui.panel.config.developer-tools.tabs.actions.yaml_mode"
|
||||
"ui.panel.config.tools.tabs.actions.yaml_mode"
|
||||
),
|
||||
value: "yaml",
|
||||
},
|
||||
@@ -163,7 +161,7 @@ class HaPanelDevAction extends MatchMinHeightMixin(LitElement) {
|
||||
<div class="header-row">
|
||||
<div class="header-title">
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.developer-tools.tabs.actions.title"
|
||||
"ui.panel.config.tools.tabs.actions.title"
|
||||
)}
|
||||
</div>
|
||||
<ha-button-toggle-group
|
||||
@@ -177,7 +175,7 @@ class HaPanelDevAction extends MatchMinHeightMixin(LitElement) {
|
||||
</div>
|
||||
<p class="secondary">
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.developer-tools.tabs.actions.description"
|
||||
"ui.panel.config.tools.tabs.actions.description"
|
||||
)}
|
||||
</p>
|
||||
</div>
|
||||
@@ -220,14 +218,14 @@ class HaPanelDevAction extends MatchMinHeightMixin(LitElement) {
|
||||
!this._uiAvailable
|
||||
? html`<span class="error"
|
||||
>${this.hass.localize(
|
||||
"ui.panel.config.developer-tools.tabs.actions.no_template_ui_support"
|
||||
"ui.panel.config.tools.tabs.actions.no_template_ui_support"
|
||||
)}</span
|
||||
>`
|
||||
: nothing
|
||||
}
|
||||
<ha-progress-button raised @click=${this._callService}>
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.developer-tools.tabs.actions.call_service"
|
||||
"ui.panel.config.tools.tabs.actions.call_service"
|
||||
)}
|
||||
</ha-progress-button>
|
||||
</div>
|
||||
@@ -238,7 +236,7 @@ class HaPanelDevAction extends MatchMinHeightMixin(LitElement) {
|
||||
? html`<div class="content response">
|
||||
<ha-card
|
||||
.header=${this.hass.localize(
|
||||
"ui.panel.config.developer-tools.tabs.actions.response"
|
||||
"ui.panel.config.tools.tabs.actions.response"
|
||||
)}
|
||||
>
|
||||
<div class="card-content">
|
||||
@@ -253,7 +251,7 @@ class HaPanelDevAction extends MatchMinHeightMixin(LitElement) {
|
||||
slot="extra-actions"
|
||||
@click=${this._copyTemplate}
|
||||
>${this.hass.localize(
|
||||
"ui.panel.config.developer-tools.tabs.actions.copy_clipboard_template"
|
||||
"ui.panel.config.tools.tabs.actions.copy_clipboard_template"
|
||||
)}</ha-button
|
||||
>
|
||||
</ha-yaml-editor>
|
||||
@@ -270,10 +268,10 @@ class HaPanelDevAction extends MatchMinHeightMixin(LitElement) {
|
||||
.header=${
|
||||
this._yamlMode
|
||||
? this.hass.localize(
|
||||
"ui.panel.config.developer-tools.tabs.actions.all_parameters"
|
||||
"ui.panel.config.tools.tabs.actions.all_parameters"
|
||||
)
|
||||
: this.hass.localize(
|
||||
"ui.panel.config.developer-tools.tabs.actions.yaml_parameters"
|
||||
"ui.panel.config.tools.tabs.actions.yaml_parameters"
|
||||
)
|
||||
}
|
||||
outlined
|
||||
@@ -287,7 +285,7 @@ class HaPanelDevAction extends MatchMinHeightMixin(LitElement) {
|
||||
target
|
||||
? html`
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.developer-tools.tabs.actions.accepts_target"
|
||||
"ui.panel.config.tools.tabs.actions.accepts_target"
|
||||
)}
|
||||
`
|
||||
: ""
|
||||
@@ -322,17 +320,17 @@ class HaPanelDevAction extends MatchMinHeightMixin(LitElement) {
|
||||
<tr>
|
||||
<th>
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.developer-tools.tabs.actions.column_parameter"
|
||||
"ui.panel.config.tools.tabs.actions.column_parameter"
|
||||
)}
|
||||
</th>
|
||||
<th>
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.developer-tools.tabs.actions.column_description"
|
||||
"ui.panel.config.tools.tabs.actions.column_description"
|
||||
)}
|
||||
</th>
|
||||
<th>
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.developer-tools.tabs.actions.column_example"
|
||||
"ui.panel.config.tools.tabs.actions.column_example"
|
||||
)}
|
||||
</th>
|
||||
</tr>
|
||||
@@ -371,7 +369,7 @@ class HaPanelDevAction extends MatchMinHeightMixin(LitElement) {
|
||||
appearance="plain"
|
||||
@click=${this._fillExampleData}
|
||||
>${this.hass.localize(
|
||||
"ui.panel.config.developer-tools.tabs.actions.fill_example_data"
|
||||
"ui.panel.config.tools.tabs.actions.fill_example_data"
|
||||
)}</ha-button
|
||||
>`
|
||||
: ""
|
||||
@@ -406,14 +404,14 @@ class HaPanelDevAction extends MatchMinHeightMixin(LitElement) {
|
||||
const errorCategory = yamlMode ? "yaml" : "ui";
|
||||
if (!serviceData?.action) {
|
||||
return localize(
|
||||
`ui.panel.config.developer-tools.tabs.actions.errors.${errorCategory}.no_action`
|
||||
`ui.panel.config.tools.tabs.actions.errors.${errorCategory}.no_action`
|
||||
);
|
||||
}
|
||||
const domain = computeDomain(serviceData.action);
|
||||
const service = computeObjectId(serviceData.action);
|
||||
if (!domain || !service) {
|
||||
return localize(
|
||||
`ui.panel.config.developer-tools.tabs.actions.errors.${errorCategory}.invalid_action`
|
||||
`ui.panel.config.tools.tabs.actions.errors.${errorCategory}.invalid_action`
|
||||
);
|
||||
}
|
||||
const dataIsTemplate =
|
||||
@@ -427,7 +425,7 @@ class HaPanelDevAction extends MatchMinHeightMixin(LitElement) {
|
||||
!serviceData.data?.area_id
|
||||
) {
|
||||
return localize(
|
||||
`ui.panel.config.developer-tools.tabs.actions.errors.${errorCategory}.no_target`
|
||||
`ui.panel.config.tools.tabs.actions.errors.${errorCategory}.no_target`
|
||||
);
|
||||
}
|
||||
for (const field of fields) {
|
||||
@@ -437,7 +435,7 @@ class HaPanelDevAction extends MatchMinHeightMixin(LitElement) {
|
||||
(!serviceData.data || serviceData.data[field.key] === undefined)
|
||||
) {
|
||||
return localize(
|
||||
`ui.panel.config.developer-tools.tabs.actions.errors.${errorCategory}.missing_required_field`,
|
||||
`ui.panel.config.tools.tabs.actions.errors.${errorCategory}.missing_required_field`,
|
||||
{ key: field.key }
|
||||
);
|
||||
}
|
||||
@@ -496,7 +494,7 @@ class HaPanelDevAction extends MatchMinHeightMixin(LitElement) {
|
||||
forwardHaptic(this, "failure");
|
||||
button.actionError();
|
||||
this._error = this.hass.localize(
|
||||
"ui.panel.config.developer-tools.tabs.actions.errors.yaml.invalid_yaml"
|
||||
"ui.panel.config.tools.tabs.actions.errors.yaml.invalid_yaml"
|
||||
);
|
||||
return;
|
||||
}
|
||||
@@ -569,7 +567,7 @@ class HaPanelDevAction extends MatchMinHeightMixin(LitElement) {
|
||||
rel="noreferrer"
|
||||
><ha-button>
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.developer-tools.tabs.actions.open_media"
|
||||
"ui.panel.config.tools.tabs.actions.open_media"
|
||||
)}
|
||||
</ha-button></a
|
||||
>
|
||||
@@ -829,6 +827,6 @@ class HaPanelDevAction extends MatchMinHeightMixin(LitElement) {
|
||||
|
||||
declare global {
|
||||
interface HTMLElementTagNameMap {
|
||||
"developer-tools-action": HaPanelDevAction;
|
||||
"tools-action": HaPanelDevAction;
|
||||
}
|
||||
}
|
||||
+9
-9
@@ -25,7 +25,7 @@ interface SentenceParsingResult {
|
||||
result: AssistDebugResult | null;
|
||||
}
|
||||
|
||||
@customElement("developer-tools-assist")
|
||||
@customElement("tools-assist")
|
||||
class HaPanelDevAssist extends SubscribeMixin(LitElement) {
|
||||
@property({ attribute: false }) public hass!: HomeAssistant;
|
||||
|
||||
@@ -118,14 +118,14 @@ class HaPanelDevAssist extends SubscribeMixin(LitElement) {
|
||||
<div class="content">
|
||||
<ha-card
|
||||
.header=${this.hass.localize(
|
||||
"ui.panel.config.developer-tools.tabs.assist.title"
|
||||
"ui.panel.config.tools.tabs.assist.title"
|
||||
)}
|
||||
class="form"
|
||||
>
|
||||
<div class="card-content">
|
||||
<p class="description">
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.developer-tools.tabs.assist.description"
|
||||
"ui.panel.config.tools.tabs.assist.description"
|
||||
)}
|
||||
</p>
|
||||
${
|
||||
@@ -143,7 +143,7 @@ class HaPanelDevAssist extends SubscribeMixin(LitElement) {
|
||||
<ha-textarea
|
||||
resize="auto"
|
||||
.label=${this.hass.localize(
|
||||
"ui.panel.config.developer-tools.tabs.assist.sentences"
|
||||
"ui.panel.config.tools.tabs.assist.sentences"
|
||||
)}
|
||||
id="sentences-input"
|
||||
@input=${this._textAreaInput}
|
||||
@@ -157,7 +157,7 @@ class HaPanelDevAssist extends SubscribeMixin(LitElement) {
|
||||
.disabled=${!this._language || !this._validInput}
|
||||
>
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.developer-tools.tabs.assist.parse_sentences"
|
||||
"ui.panel.config.tools.tabs.assist.parse_sentences"
|
||||
)}
|
||||
</ha-button>
|
||||
</div>
|
||||
@@ -184,7 +184,7 @@ class HaPanelDevAssist extends SubscribeMixin(LitElement) {
|
||||
.path=${mdiDownload}
|
||||
></ha-svg-icon>
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.developer-tools.tabs.assist.download_results"
|
||||
"ui.panel.config.tools.tabs.assist.download_results"
|
||||
)}
|
||||
</ha-button>
|
||||
</div>
|
||||
@@ -204,7 +204,7 @@ class HaPanelDevAssist extends SubscribeMixin(LitElement) {
|
||||
</div>
|
||||
<div class="info">
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.developer-tools.tabs.assist.language"
|
||||
"ui.panel.config.tools.tabs.assist.language"
|
||||
)}:
|
||||
${formatLanguageCode(language, this.hass.locale)}
|
||||
(${language})
|
||||
@@ -221,7 +221,7 @@ class HaPanelDevAssist extends SubscribeMixin(LitElement) {
|
||||
`
|
||||
: html`<ha-alert alert-type="error">
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.developer-tools.tabs.assist.no_match"
|
||||
"ui.panel.config.tools.tabs.assist.no_match"
|
||||
)}
|
||||
</ha-alert>`
|
||||
}
|
||||
@@ -304,6 +304,6 @@ class HaPanelDevAssist extends SubscribeMixin(LitElement) {
|
||||
|
||||
declare global {
|
||||
interface HTMLElementTagNameMap {
|
||||
"developer-tools-assist": HaPanelDevAssist;
|
||||
"tools-assist": HaPanelDevAssist;
|
||||
}
|
||||
}
|
||||
+2
-2
@@ -17,12 +17,12 @@ class HaDebugConnectionRow extends LitElement {
|
||||
<ha-list-item-base>
|
||||
<span slot="headline"
|
||||
>${this.hass.localize(
|
||||
"ui.panel.config.developer-tools.tabs.debug.debug_connection.title"
|
||||
"ui.panel.config.tools.tabs.debug.debug_connection.title"
|
||||
)}</span
|
||||
>
|
||||
<span slot="supporting-text"
|
||||
>${this.hass.localize(
|
||||
"ui.panel.config.developer-tools.tabs.debug.debug_connection.description"
|
||||
"ui.panel.config.tools.tabs.debug.debug_connection.description"
|
||||
)}</span
|
||||
>
|
||||
<ha-switch
|
||||
+2
-2
@@ -20,12 +20,12 @@ class HaDebugDisableViewTransitionRow extends LitElement {
|
||||
<ha-list-item-base>
|
||||
<span slot="headline"
|
||||
>${this.hass.localize(
|
||||
"ui.panel.config.developer-tools.tabs.debug.disable_view_transition.title"
|
||||
"ui.panel.config.tools.tabs.debug.disable_view_transition.title"
|
||||
)}</span
|
||||
>
|
||||
<span slot="supporting-text"
|
||||
>${this.hass.localize(
|
||||
"ui.panel.config.developer-tools.tabs.debug.disable_view_transition.description"
|
||||
"ui.panel.config.tools.tabs.debug.disable_view_transition.description"
|
||||
)}</span
|
||||
>
|
||||
<ha-switch
|
||||
+2
-2
@@ -230,13 +230,13 @@ export class HaDebugViewportEnvironmentCard extends LitElement {
|
||||
return html`
|
||||
<ha-card
|
||||
.header=${this.hass.localize(
|
||||
"ui.panel.config.developer-tools.tabs.debug.viewport_environment.title"
|
||||
"ui.panel.config.tools.tabs.debug.viewport_environment.title"
|
||||
)}
|
||||
>
|
||||
<div class="card-content">
|
||||
<p class="explanation">
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.developer-tools.tabs.debug.viewport_environment.description"
|
||||
"ui.panel.config.tools.tabs.debug.viewport_environment.description"
|
||||
)}
|
||||
</p>
|
||||
<ha-code-editor
|
||||
+6
-6
@@ -20,7 +20,7 @@ import "./ha-debug-connection-row";
|
||||
import "./ha-debug-disable-view-transition-row";
|
||||
import "./ha-debug-viewport-environment-card";
|
||||
|
||||
@customElement("developer-tools-debug")
|
||||
@customElement("tools-debug")
|
||||
class HaPanelDevDebug extends SubscribeMixin(LitElement) {
|
||||
@property({ attribute: false }) public hass!: HomeAssistant;
|
||||
|
||||
@@ -31,7 +31,7 @@ class HaPanelDevDebug extends SubscribeMixin(LitElement) {
|
||||
<div class="content">
|
||||
<ha-card
|
||||
.header=${this.hass.localize(
|
||||
"ui.panel.config.developer-tools.tabs.debug.title"
|
||||
"ui.panel.config.tools.tabs.debug.title"
|
||||
)}
|
||||
>
|
||||
<ha-list-base>
|
||||
@@ -45,13 +45,13 @@ class HaPanelDevDebug extends SubscribeMixin(LitElement) {
|
||||
</ha-card>
|
||||
<ha-card
|
||||
.header=${this.hass.localize(
|
||||
"ui.panel.config.developer-tools.tabs.debug.entity_diagnostic.title"
|
||||
"ui.panel.config.tools.tabs.debug.entity_diagnostic.title"
|
||||
)}
|
||||
>
|
||||
<div class="card-content">
|
||||
<ha-entity-picker
|
||||
.helper=${this.hass.localize(
|
||||
"ui.panel.config.developer-tools.tabs.debug.entity_diagnostic.description"
|
||||
"ui.panel.config.tools.tabs.debug.entity_diagnostic.description"
|
||||
)}
|
||||
@value-changed=${this._entityPicked}
|
||||
></ha-entity-picker>
|
||||
@@ -62,7 +62,7 @@ class HaPanelDevDebug extends SubscribeMixin(LitElement) {
|
||||
appearance="filled"
|
||||
.disabled=${!this._entityId}
|
||||
>${this.hass.localize(
|
||||
"ui.panel.config.developer-tools.tabs.debug.entity_diagnostic.copy_to_clipboard"
|
||||
"ui.panel.config.tools.tabs.debug.entity_diagnostic.copy_to_clipboard"
|
||||
)}</ha-button
|
||||
>
|
||||
</div>
|
||||
@@ -136,6 +136,6 @@ class HaPanelDevDebug extends SubscribeMixin(LitElement) {
|
||||
|
||||
declare global {
|
||||
interface HTMLElementTagNameMap {
|
||||
"developer-tools-debug": HaPanelDevDebug;
|
||||
"tools-debug": HaPanelDevDebug;
|
||||
}
|
||||
}
|
||||
+18
-18
@@ -76,7 +76,7 @@ class EventSubscribeCard extends LitElement {
|
||||
return html`
|
||||
<ha-card
|
||||
header=${this.hass!.localize(
|
||||
"ui.panel.config.developer-tools.tabs.events.listen_to_events"
|
||||
"ui.panel.config.tools.tabs.events.listen_to_events"
|
||||
)}
|
||||
>
|
||||
<div class="card-content">
|
||||
@@ -84,10 +84,10 @@ class EventSubscribeCard extends LitElement {
|
||||
.label=${
|
||||
this._subscribed
|
||||
? this.hass!.localize(
|
||||
"ui.panel.config.developer-tools.tabs.events.listening_to"
|
||||
"ui.panel.config.tools.tabs.events.listening_to"
|
||||
)
|
||||
: this.hass!.localize(
|
||||
"ui.panel.config.developer-tools.tabs.events.subscribe_to"
|
||||
"ui.panel.config.tools.tabs.events.subscribe_to"
|
||||
)
|
||||
}
|
||||
.disabled=${this._subscribed !== undefined}
|
||||
@@ -96,11 +96,11 @@ class EventSubscribeCard extends LitElement {
|
||||
></ha-input>
|
||||
<ha-input
|
||||
.label=${this.hass!.localize(
|
||||
"ui.panel.config.developer-tools.tabs.events.filter_events"
|
||||
"ui.panel.config.tools.tabs.events.filter_events"
|
||||
)}
|
||||
.value=${this._eventFilter}
|
||||
.disabled=${this._subscribed !== undefined}
|
||||
.hint=${`${this.hass!.localize("ui.panel.config.developer-tools.tabs.events.filter_helper")}${this._ignoredEventsCount ? ` ${this.hass!.localize("ui.panel.config.developer-tools.tabs.events.filter_ignored", { count: this._ignoredEventsCount })}` : ""}`}
|
||||
.hint=${`${this.hass!.localize("ui.panel.config.tools.tabs.events.filter_helper")}${this._ignoredEventsCount ? ` ${this.hass!.localize("ui.panel.config.tools.tabs.events.filter_ignored", { count: this._ignoredEventsCount })}` : ""}`}
|
||||
@input=${this._filterChanged}
|
||||
></ha-input>
|
||||
${
|
||||
@@ -118,10 +118,10 @@ class EventSubscribeCard extends LitElement {
|
||||
${
|
||||
this._subscribed
|
||||
? this.hass!.localize(
|
||||
"ui.panel.config.developer-tools.tabs.events.stop_listening"
|
||||
"ui.panel.config.tools.tabs.events.stop_listening"
|
||||
)
|
||||
: this.hass!.localize(
|
||||
"ui.panel.config.developer-tools.tabs.events.start_listening"
|
||||
"ui.panel.config.tools.tabs.events.start_listening"
|
||||
)
|
||||
}
|
||||
</ha-button>
|
||||
@@ -131,7 +131,7 @@ class EventSubscribeCard extends LitElement {
|
||||
@click=${this._clearEvents}
|
||||
>
|
||||
${this.hass!.localize(
|
||||
"ui.panel.config.developer-tools.tabs.events.clear_events"
|
||||
"ui.panel.config.tools.tabs.events.clear_events"
|
||||
)}
|
||||
</ha-button>
|
||||
</div>
|
||||
@@ -144,10 +144,10 @@ class EventSubscribeCard extends LitElement {
|
||||
if (!this._events.length) {
|
||||
const message = this._subscribed
|
||||
? this.hass!.localize(
|
||||
"ui.panel.config.developer-tools.tabs.events.waiting_for_events"
|
||||
"ui.panel.config.tools.tabs.events.waiting_for_events"
|
||||
)
|
||||
: this.hass!.localize(
|
||||
"ui.panel.config.developer-tools.tabs.events.subscribe_prompt"
|
||||
"ui.panel.config.tools.tabs.events.subscribe_prompt"
|
||||
);
|
||||
return html`
|
||||
<ha-card class="events-card">
|
||||
@@ -172,7 +172,7 @@ class EventSubscribeCard extends LitElement {
|
||||
.path=${mdiChevronDoubleLeft}
|
||||
.disabled=${index >= bufferTotal - 1}
|
||||
.label=${this.hass!.localize(
|
||||
"ui.panel.config.developer-tools.tabs.events.oldest_event"
|
||||
"ui.panel.config.tools.tabs.events.oldest_event"
|
||||
)}
|
||||
@click=${this._showOldest}
|
||||
></ha-icon-button>
|
||||
@@ -180,13 +180,13 @@ class EventSubscribeCard extends LitElement {
|
||||
.path=${mdiChevronLeft}
|
||||
.disabled=${index >= bufferTotal - 1}
|
||||
.label=${this.hass!.localize(
|
||||
"ui.panel.config.developer-tools.tabs.events.older_event"
|
||||
"ui.panel.config.tools.tabs.events.older_event"
|
||||
)}
|
||||
@click=${this._showOlder}
|
||||
></ha-icon-button>
|
||||
<div class="event-info">
|
||||
${this.hass!.localize(
|
||||
"ui.panel.config.developer-tools.tabs.events.event_fired",
|
||||
"ui.panel.config.tools.tabs.events.event_fired",
|
||||
{
|
||||
name: position,
|
||||
time: formatTimeWithSeconds(
|
||||
@@ -208,7 +208,7 @@ class EventSubscribeCard extends LitElement {
|
||||
<ha-tooltip for="buffer-info" placement="bottom">
|
||||
<span class="buffer-tooltip">
|
||||
${this.hass!.localize(
|
||||
"ui.panel.config.developer-tools.tabs.events.buffer_disclaimer",
|
||||
"ui.panel.config.tools.tabs.events.buffer_disclaimer",
|
||||
{ count: MAX_BUFFERED_EVENTS }
|
||||
)}
|
||||
</span>
|
||||
@@ -221,7 +221,7 @@ class EventSubscribeCard extends LitElement {
|
||||
.path=${mdiChevronRight}
|
||||
.disabled=${atNewest}
|
||||
.label=${this.hass!.localize(
|
||||
"ui.panel.config.developer-tools.tabs.events.newer_event"
|
||||
"ui.panel.config.tools.tabs.events.newer_event"
|
||||
)}
|
||||
@click=${this._showNewer}
|
||||
></ha-icon-button>
|
||||
@@ -229,7 +229,7 @@ class EventSubscribeCard extends LitElement {
|
||||
.path=${mdiChevronDoubleRight}
|
||||
.disabled=${atNewest}
|
||||
.label=${this.hass!.localize(
|
||||
"ui.panel.config.developer-tools.tabs.events.newest_event"
|
||||
"ui.panel.config.tools.tabs.events.newest_event"
|
||||
)}
|
||||
@click=${this._showNewest}
|
||||
></ha-icon-button>
|
||||
@@ -362,13 +362,13 @@ class EventSubscribeCard extends LitElement {
|
||||
}, this._eventType);
|
||||
} catch (error) {
|
||||
this._error = this.hass!.localize(
|
||||
"ui.panel.config.developer-tools.tabs.events.subscribe_failed",
|
||||
"ui.panel.config.tools.tabs.events.subscribe_failed",
|
||||
{
|
||||
error:
|
||||
error instanceof Error
|
||||
? error.message
|
||||
: this.hass!.localize(
|
||||
"ui.panel.config.developer-tools.tabs.events.unknown_error"
|
||||
"ui.panel.config.tools.tabs.events.unknown_error"
|
||||
),
|
||||
}
|
||||
);
|
||||
+1
-1
@@ -27,7 +27,7 @@ class EventsList extends LitElement {
|
||||
>
|
||||
<span>
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.developer-tools.tabs.events.count_listeners",
|
||||
"ui.panel.config.tools.tabs.events.count_listeners",
|
||||
{
|
||||
count: event.listener_count,
|
||||
}
|
||||
+10
-10
@@ -14,7 +14,7 @@ import { documentationUrl } from "../../../../util/documentation-url";
|
||||
import "./event-subscribe-card";
|
||||
import "./events-list";
|
||||
|
||||
@customElement("developer-tools-event")
|
||||
@customElement("tools-event")
|
||||
class HaPanelDevEvent extends LitElement {
|
||||
@property({ attribute: false }) public hass!: HomeAssistant;
|
||||
|
||||
@@ -40,7 +40,7 @@ class HaPanelDevEvent extends LitElement {
|
||||
<div class="card-content">
|
||||
<p>
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.developer-tools.tabs.events.description"
|
||||
"ui.panel.config.tools.tabs.events.description"
|
||||
)}
|
||||
<a
|
||||
href=${documentationUrl(
|
||||
@@ -51,14 +51,14 @@ class HaPanelDevEvent extends LitElement {
|
||||
rel="noreferrer"
|
||||
>
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.developer-tools.tabs.events.documentation"
|
||||
"ui.panel.config.tools.tabs.events.documentation"
|
||||
)}
|
||||
</a>
|
||||
</p>
|
||||
<div class="inputs">
|
||||
<ha-input
|
||||
.label=${this.hass.localize(
|
||||
"ui.panel.config.developer-tools.tabs.events.type"
|
||||
"ui.panel.config.tools.tabs.events.type"
|
||||
)}
|
||||
autofocus
|
||||
required
|
||||
@@ -67,7 +67,7 @@ class HaPanelDevEvent extends LitElement {
|
||||
></ha-input>
|
||||
<p>
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.developer-tools.tabs.events.data"
|
||||
"ui.panel.config.tools.tabs.events.data"
|
||||
)}
|
||||
</p>
|
||||
</div>
|
||||
@@ -85,7 +85,7 @@ class HaPanelDevEvent extends LitElement {
|
||||
appearance="filled"
|
||||
.disabled=${!this._isValid}
|
||||
>${this.hass.localize(
|
||||
"ui.panel.config.developer-tools.tabs.events.fire_event"
|
||||
"ui.panel.config.tools.tabs.events.fire_event"
|
||||
)}</ha-button
|
||||
>
|
||||
</div>
|
||||
@@ -101,7 +101,7 @@ class HaPanelDevEvent extends LitElement {
|
||||
<div>
|
||||
<h2>
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.developer-tools.tabs.events.active_listeners"
|
||||
"ui.panel.config.tools.tabs.events.active_listeners"
|
||||
)}
|
||||
</h2>
|
||||
<events-list
|
||||
@@ -131,7 +131,7 @@ class HaPanelDevEvent extends LitElement {
|
||||
if (!this._eventType) {
|
||||
showAlertDialog(this, {
|
||||
text: this.hass.localize(
|
||||
"ui.panel.config.developer-tools.tabs.events.alert_event_type"
|
||||
"ui.panel.config.tools.tabs.events.alert_event_type"
|
||||
),
|
||||
});
|
||||
return;
|
||||
@@ -143,7 +143,7 @@ class HaPanelDevEvent extends LitElement {
|
||||
);
|
||||
fireEvent(this, "hass-notification", {
|
||||
message: this.hass.localize(
|
||||
"ui.panel.config.developer-tools.tabs.events.notification_event_fired",
|
||||
"ui.panel.config.tools.tabs.events.notification_event_fired",
|
||||
{ type: this._eventType }
|
||||
),
|
||||
});
|
||||
@@ -221,6 +221,6 @@ class HaPanelDevEvent extends LitElement {
|
||||
|
||||
declare global {
|
||||
interface HTMLElementTagNameMap {
|
||||
"developer-tools-event": HaPanelDevEvent;
|
||||
"tools-event": HaPanelDevEvent;
|
||||
}
|
||||
}
|
||||
+21
-25
@@ -12,42 +12,42 @@ import "../../../components/ha-tab-group";
|
||||
import "../../../components/ha-tab-group-tab";
|
||||
import "../../../components/ha-top-app-bar-fixed";
|
||||
import type { HomeAssistant, Route } from "../../../types";
|
||||
import "./developer-tools-router";
|
||||
import "./tools-router";
|
||||
import type { HaDropdownSelectEvent } from "../../../components/ha-dropdown";
|
||||
|
||||
const DEVELOPER_TOOLS_TABS = [
|
||||
const TOOLS_TABS = [
|
||||
{
|
||||
panel: "yaml",
|
||||
translationKey: "ui.panel.config.developer-tools.tabs.yaml.title",
|
||||
translationKey: "ui.panel.config.tools.tabs.yaml.title",
|
||||
},
|
||||
{
|
||||
panel: "state",
|
||||
translationKey: "ui.panel.config.developer-tools.tabs.states.title",
|
||||
translationKey: "ui.panel.config.tools.tabs.states.title",
|
||||
},
|
||||
{
|
||||
panel: "action",
|
||||
translationKey: "ui.panel.config.developer-tools.tabs.actions.title",
|
||||
translationKey: "ui.panel.config.tools.tabs.actions.title",
|
||||
},
|
||||
{
|
||||
panel: "template",
|
||||
translationKey: "ui.panel.config.developer-tools.tabs.templates.title",
|
||||
translationKey: "ui.panel.config.tools.tabs.templates.title",
|
||||
},
|
||||
{
|
||||
panel: "event",
|
||||
translationKey: "ui.panel.config.developer-tools.tabs.events.title",
|
||||
translationKey: "ui.panel.config.tools.tabs.events.title",
|
||||
},
|
||||
{
|
||||
panel: "statistics",
|
||||
translationKey: "ui.panel.config.developer-tools.tabs.statistics.title",
|
||||
translationKey: "ui.panel.config.tools.tabs.statistics.title",
|
||||
},
|
||||
{
|
||||
panel: "assist",
|
||||
translationKey: "ui.panel.config.developer-tools.tabs.assist.tab",
|
||||
translationKey: "ui.panel.config.tools.tabs.assist.tab",
|
||||
},
|
||||
] as const;
|
||||
|
||||
@customElement("ha-panel-developer-tools")
|
||||
class PanelDeveloperTools extends LitElement {
|
||||
@customElement("ha-panel-tools")
|
||||
class PanelTools extends LitElement {
|
||||
@property({ attribute: false }) public hass!: HomeAssistant;
|
||||
|
||||
@property({ attribute: false }) public route!: Route;
|
||||
@@ -68,9 +68,7 @@ class PanelDeveloperTools extends LitElement {
|
||||
@click=${this._handleBack}
|
||||
></ha-icon-button-arrow-prev>
|
||||
<div slot="title">
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.dashboard.developer_tools.main"
|
||||
)}
|
||||
${this.hass.localize("ui.panel.config.dashboard.tools.main")}
|
||||
</div>
|
||||
<ha-dropdown slot="actionItems" @wa-select=${this._handleMenuAction}>
|
||||
<ha-icon-button
|
||||
@@ -79,13 +77,11 @@ class PanelDeveloperTools extends LitElement {
|
||||
.path=${mdiDotsVertical}
|
||||
></ha-icon-button>
|
||||
<ha-dropdown-item value="debug">
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.developer-tools.tabs.debug.title"
|
||||
)}
|
||||
${this.hass.localize("ui.panel.config.tools.tabs.debug.title")}
|
||||
</ha-dropdown-item>
|
||||
</ha-dropdown>
|
||||
<ha-tab-group @wa-tab-show=${this._handlePageSelected} slot="subRow">
|
||||
${DEVELOPER_TOOLS_TABS.map(
|
||||
${TOOLS_TABS.map(
|
||||
(tab) => html`
|
||||
<ha-tab-group-tab
|
||||
slot="nav"
|
||||
@@ -93,7 +89,7 @@ class PanelDeveloperTools extends LitElement {
|
||||
.active=${page === tab.panel}
|
||||
>
|
||||
<a
|
||||
href="/config/developer-tools/${tab.panel}"
|
||||
href="/config/tools/${tab.panel}"
|
||||
@click=${this._handleTabAnchorClick}
|
||||
>${this.hass.localize(tab.translationKey)}</a
|
||||
>
|
||||
@@ -101,11 +97,11 @@ class PanelDeveloperTools extends LitElement {
|
||||
`
|
||||
)}
|
||||
</ha-tab-group>
|
||||
<developer-tools-router
|
||||
<tools-router
|
||||
.route=${this.route}
|
||||
.narrow=${this.narrow}
|
||||
.hass=${this.hass}
|
||||
></developer-tools-router>
|
||||
></tools-router>
|
||||
</ha-top-app-bar-fixed>
|
||||
`;
|
||||
}
|
||||
@@ -124,7 +120,7 @@ class PanelDeveloperTools extends LitElement {
|
||||
return;
|
||||
}
|
||||
if (newPage !== this._page) {
|
||||
navigate(`/config/developer-tools/${newPage}`);
|
||||
navigate(`/config/tools/${newPage}`);
|
||||
} else {
|
||||
scrollTo({ behavior: "smooth", top: 0 });
|
||||
}
|
||||
@@ -133,7 +129,7 @@ class PanelDeveloperTools extends LitElement {
|
||||
private async _handleMenuAction(ev: HaDropdownSelectEvent) {
|
||||
const action = ev.detail.item.value;
|
||||
if (action === "debug") {
|
||||
navigate(`/config/developer-tools/debug`);
|
||||
navigate(`/config/tools/debug`);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -146,7 +142,7 @@ class PanelDeveloperTools extends LitElement {
|
||||
}
|
||||
|
||||
static readonly styles: CSSResultGroup = css`
|
||||
developer-tools-router {
|
||||
tools-router {
|
||||
display: block;
|
||||
height: 100%;
|
||||
}
|
||||
@@ -170,6 +166,6 @@ class PanelDeveloperTools extends LitElement {
|
||||
|
||||
declare global {
|
||||
interface HTMLElementTagNameMap {
|
||||
"ha-panel-developer-tools": PanelDeveloperTools;
|
||||
"ha-panel-tools": PanelTools;
|
||||
}
|
||||
}
|
||||
+10
-14
@@ -24,7 +24,7 @@ import { haStyle } from "../../../../resources/styles";
|
||||
import { loadVirtualizer } from "../../../../resources/virtualizer";
|
||||
import { showToast } from "../../../../util/toast";
|
||||
|
||||
@customElement("developer-tools-state-renderer")
|
||||
@customElement("tools-state-renderer")
|
||||
class HaPanelDevStateRenderer extends LitElement {
|
||||
@property({ attribute: false }) public entities: HassEntity[] = [];
|
||||
|
||||
@@ -79,16 +79,12 @@ class HaPanelDevStateRenderer extends LitElement {
|
||||
<div class="row" role="row" aria-rowindex="1">
|
||||
<div class="header" role="columnheader">
|
||||
<span class="padded">
|
||||
${this._i18n.localize(
|
||||
"ui.panel.config.developer-tools.tabs.states.entity"
|
||||
)}
|
||||
${this._i18n.localize("ui.panel.config.tools.tabs.states.entity")}
|
||||
</span>
|
||||
</div>
|
||||
<div class="header" role="columnheader">
|
||||
<span class="padded">
|
||||
${this._i18n.localize(
|
||||
"ui.panel.config.developer-tools.tabs.states.state"
|
||||
)}
|
||||
${this._i18n.localize("ui.panel.config.tools.tabs.states.state")}
|
||||
</span>
|
||||
</div>
|
||||
<div class="header" role="columnheader" ?hidden=${!showDevice}>
|
||||
@@ -106,7 +102,7 @@ class HaPanelDevStateRenderer extends LitElement {
|
||||
<div class="header" role="columnheader">
|
||||
<span class="padded">
|
||||
${this._i18n.localize(
|
||||
"ui.panel.config.developer-tools.tabs.states.attributes"
|
||||
"ui.panel.config.tools.tabs.states.attributes"
|
||||
)}
|
||||
</span>
|
||||
</div>
|
||||
@@ -134,7 +130,7 @@ class HaPanelDevStateRenderer extends LitElement {
|
||||
<div class="cell" role="cell" aria-colspan="5">
|
||||
<span class="padded">
|
||||
${this._i18n.localize(
|
||||
"ui.panel.config.developer-tools.tabs.states.no_entities"
|
||||
"ui.panel.config.tools.tabs.states.no_entities"
|
||||
)}
|
||||
</span>
|
||||
</div>
|
||||
@@ -195,10 +191,10 @@ class HaPanelDevStateRenderer extends LitElement {
|
||||
@click=${this._copyEntity}
|
||||
.entity=${item}
|
||||
alt=${this._i18n.localize(
|
||||
"ui.panel.config.developer-tools.tabs.states.copy_id"
|
||||
"ui.panel.config.tools.tabs.states.copy_id"
|
||||
)}
|
||||
title=${this._i18n.localize(
|
||||
"ui.panel.config.developer-tools.tabs.states.copy_id"
|
||||
"ui.panel.config.tools.tabs.states.copy_id"
|
||||
)}
|
||||
.path=${mdiClipboardTextMultipleOutline}
|
||||
></ha-svg-icon>
|
||||
@@ -211,10 +207,10 @@ class HaPanelDevStateRenderer extends LitElement {
|
||||
@click=${this._entityMoreInfo}
|
||||
.entity=${item}
|
||||
alt=${this._i18n.localize(
|
||||
"ui.panel.config.developer-tools.tabs.states.more_info"
|
||||
"ui.panel.config.tools.tabs.states.more_info"
|
||||
)}
|
||||
title=${this._i18n.localize(
|
||||
"ui.panel.config.developer-tools.tabs.states.more_info"
|
||||
"ui.panel.config.tools.tabs.states.more_info"
|
||||
)}
|
||||
.path=${mdiInformationOutline}
|
||||
></ha-svg-icon>
|
||||
@@ -438,7 +434,7 @@ class HaPanelDevStateRenderer extends LitElement {
|
||||
|
||||
declare global {
|
||||
interface HTMLElementTagNameMap {
|
||||
"developer-tools-state-renderer": HaPanelDevStateRenderer;
|
||||
"tools-state-renderer": HaPanelDevStateRenderer;
|
||||
}
|
||||
|
||||
interface HASSDomEvents {
|
||||
+20
-20
@@ -42,7 +42,7 @@ import { showAlertDialog } from "../../../../dialogs/generic/show-dialog-box";
|
||||
import { haStyle } from "../../../../resources/styles";
|
||||
import type { HomeAssistant, HomeAssistantRegistries } from "../../../../types";
|
||||
import { showToast } from "../../../../util/toast";
|
||||
import "./developer-tools-state-renderer";
|
||||
import "./tools-state-renderer";
|
||||
|
||||
// Use virtualizer after threshold to avoid performance issues
|
||||
// NOTE: If virtualizer is used when filtered entiity state
|
||||
@@ -51,7 +51,7 @@ import "./developer-tools-state-renderer";
|
||||
// virtualized list, an undesirable effect.
|
||||
const VIRTUALIZE_THRESHOLD = 100;
|
||||
|
||||
@customElement("developer-tools-state")
|
||||
@customElement("tools-state")
|
||||
class HaPanelDevState extends LitElement {
|
||||
@property({ attribute: false }) public hass!: HomeAssistant;
|
||||
|
||||
@@ -165,7 +165,7 @@ class HaPanelDevState extends LitElement {
|
||||
<div class="heading">
|
||||
<h1>
|
||||
${this._i18n.localize(
|
||||
"ui.panel.config.developer-tools.tabs.states.current_entities"
|
||||
"ui.panel.config.tools.tabs.states.current_entities"
|
||||
)}
|
||||
</h1>
|
||||
${
|
||||
@@ -192,7 +192,7 @@ class HaPanelDevState extends LitElement {
|
||||
@change=${this._saveAttributeCheckboxState}
|
||||
>
|
||||
${this._i18n.localize(
|
||||
"ui.panel.config.developer-tools.tabs.states.attributes"
|
||||
"ui.panel.config.tools.tabs.states.attributes"
|
||||
)}
|
||||
</ha-checkbox>
|
||||
`
|
||||
@@ -201,7 +201,7 @@ class HaPanelDevState extends LitElement {
|
||||
</div>
|
||||
<ha-expansion-panel
|
||||
.header=${this._i18n.localize(
|
||||
"ui.panel.config.developer-tools.tabs.states.set_state"
|
||||
"ui.panel.config.tools.tabs.states.set_state"
|
||||
)}
|
||||
outlined
|
||||
.expanded=${this._expanded}
|
||||
@@ -209,10 +209,10 @@ class HaPanelDevState extends LitElement {
|
||||
>
|
||||
<p>
|
||||
${this._i18n.localize(
|
||||
"ui.panel.config.developer-tools.tabs.states.description1"
|
||||
"ui.panel.config.tools.tabs.states.description1"
|
||||
)}<br />
|
||||
${this._i18n.localize(
|
||||
"ui.panel.config.developer-tools.tabs.states.description2"
|
||||
"ui.panel.config.tools.tabs.states.description2"
|
||||
)}
|
||||
</p>
|
||||
${
|
||||
@@ -237,7 +237,7 @@ class HaPanelDevState extends LitElement {
|
||||
.path=${mdiContentCopy}
|
||||
@click=${this._copyStateEntity}
|
||||
title=${this._i18n.localize(
|
||||
"ui.panel.config.developer-tools.tabs.states.copy_id"
|
||||
"ui.panel.config.tools.tabs.states.copy_id"
|
||||
)}
|
||||
></ha-icon-button>
|
||||
</div>
|
||||
@@ -246,7 +246,7 @@ class HaPanelDevState extends LitElement {
|
||||
}
|
||||
<ha-input
|
||||
.label=${this._i18n.localize(
|
||||
"ui.panel.config.developer-tools.tabs.states.state"
|
||||
"ui.panel.config.tools.tabs.states.state"
|
||||
)}
|
||||
required
|
||||
autocapitalize="none"
|
||||
@@ -259,7 +259,7 @@ class HaPanelDevState extends LitElement {
|
||||
></ha-input>
|
||||
<p>
|
||||
${this._i18n.localize(
|
||||
"ui.panel.config.developer-tools.tabs.states.state_attributes"
|
||||
"ui.panel.config.tools.tabs.states.state_attributes"
|
||||
)}
|
||||
</p>
|
||||
<ha-yaml-editor
|
||||
@@ -274,7 +274,7 @@ class HaPanelDevState extends LitElement {
|
||||
.disabled=${!this._validJSON}
|
||||
raised
|
||||
>${this._i18n.localize(
|
||||
"ui.panel.config.developer-tools.tabs.states.set_state"
|
||||
"ui.panel.config.tools.tabs.states.set_state"
|
||||
)}</ha-button
|
||||
>
|
||||
<ha-icon-button
|
||||
@@ -290,7 +290,7 @@ class HaPanelDevState extends LitElement {
|
||||
? html`<p>
|
||||
<b
|
||||
>${this._i18n.localize(
|
||||
"ui.panel.config.developer-tools.tabs.states.last_changed"
|
||||
"ui.panel.config.tools.tabs.states.last_changed"
|
||||
)}:</b
|
||||
><br />
|
||||
<a href=${this._historyFromLastChanged(this._entity)}
|
||||
@@ -300,7 +300,7 @@ class HaPanelDevState extends LitElement {
|
||||
<p>
|
||||
<b
|
||||
>${this._i18n.localize(
|
||||
"ui.panel.config.developer-tools.tabs.states.last_updated"
|
||||
"ui.panel.config.tools.tabs.states.last_updated"
|
||||
)}:</b
|
||||
><br />
|
||||
<a href=${this._historyFromLastUpdated(this._entity)}
|
||||
@@ -312,7 +312,7 @@ class HaPanelDevState extends LitElement {
|
||||
</div>
|
||||
</div>
|
||||
</ha-expansion-panel>
|
||||
<developer-tools-state-renderer
|
||||
<tools-state-renderer
|
||||
.narrow=${this.narrow}
|
||||
.entities=${entities}
|
||||
.virtualize=${entities.length > VIRTUALIZE_THRESHOLD}
|
||||
@@ -324,7 +324,7 @@ class HaPanelDevState extends LitElement {
|
||||
<ha-input-search
|
||||
slot="filter-entities"
|
||||
.label=${this._i18n.localize(
|
||||
"ui.panel.config.developer-tools.tabs.states.filter_entities"
|
||||
"ui.panel.config.tools.tabs.states.filter_entities"
|
||||
)}
|
||||
.value=${this._entityFilter}
|
||||
@input=${this._entityFilterChanged}
|
||||
@@ -332,7 +332,7 @@ class HaPanelDevState extends LitElement {
|
||||
<ha-input-search
|
||||
slot="filter-states"
|
||||
.label=${this._i18n.localize(
|
||||
"ui.panel.config.developer-tools.tabs.states.filter_states"
|
||||
"ui.panel.config.tools.tabs.states.filter_states"
|
||||
)}
|
||||
type="search"
|
||||
.value=${this._stateFilter}
|
||||
@@ -357,13 +357,13 @@ class HaPanelDevState extends LitElement {
|
||||
<ha-input-search
|
||||
slot="filter-attributes"
|
||||
.label=${this._i18n.localize(
|
||||
"ui.panel.config.developer-tools.tabs.states.filter_attributes"
|
||||
"ui.panel.config.tools.tabs.states.filter_attributes"
|
||||
)}
|
||||
type="search"
|
||||
.value=${this._attributeFilter}
|
||||
@input=${this._attributeFilterChanged}
|
||||
></ha-input-search>
|
||||
</developer-tools-state-renderer>
|
||||
</tools-state-renderer>
|
||||
`;
|
||||
}
|
||||
|
||||
@@ -469,7 +469,7 @@ class HaPanelDevState extends LitElement {
|
||||
if (!this._entityId) {
|
||||
showAlertDialog(this, {
|
||||
text: this._i18n.localize(
|
||||
"ui.panel.config.developer-tools.tabs.states.alert_entity_field"
|
||||
"ui.panel.config.tools.tabs.states.alert_entity_field"
|
||||
),
|
||||
});
|
||||
return;
|
||||
@@ -758,6 +758,6 @@ class HaPanelDevState extends LitElement {
|
||||
|
||||
declare global {
|
||||
interface HTMLElementTagNameMap {
|
||||
"developer-tools-state": HaPanelDevState;
|
||||
"tools-state": HaPanelDevState;
|
||||
}
|
||||
}
|
||||
+13
-13
@@ -132,7 +132,7 @@ export class DialogStatisticsFixUnsupportedUnitMetadata extends DirtyStateProvid
|
||||
@click=${this._fetchOutliers}
|
||||
>
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.developer-tools.tabs.statistics.fix_issue.adjust_sum.outliers"
|
||||
"ui.panel.config.tools.tabs.statistics.fix_issue.adjust_sum.outliers"
|
||||
)}
|
||||
</ha-button>
|
||||
<ha-button slot="primaryAction" data-dialog="close">
|
||||
@@ -156,7 +156,7 @@ export class DialogStatisticsFixUnsupportedUnitMetadata extends DirtyStateProvid
|
||||
@click=${this._fixIssue}
|
||||
>
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.developer-tools.tabs.statistics.fix_issue.adjust_sum.adjust"
|
||||
"ui.panel.config.tools.tabs.statistics.fix_issue.adjust_sum.adjust"
|
||||
)}</ha-button
|
||||
>
|
||||
`;
|
||||
@@ -166,7 +166,7 @@ export class DialogStatisticsFixUnsupportedUnitMetadata extends DirtyStateProvid
|
||||
<ha-dialog
|
||||
.open=${this._open}
|
||||
header-title=${this.hass.localize(
|
||||
"ui.panel.config.developer-tools.tabs.statistics.fix_issue.adjust_sum.title"
|
||||
"ui.panel.config.tools.tabs.statistics.fix_issue.adjust_sum.title"
|
||||
)}
|
||||
.preventScrimClose=${this.isDirtyState}
|
||||
@closed=${this._dialogClosed}
|
||||
@@ -194,7 +194,7 @@ export class DialogStatisticsFixUnsupportedUnitMetadata extends DirtyStateProvid
|
||||
} else if (this._statsHour.length < 1 && this._stats5min.length < 1) {
|
||||
stats = html`<p>
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.developer-tools.tabs.statistics.fix_issue.adjust_sum.no_statistics_found"
|
||||
"ui.panel.config.tools.tabs.statistics.fix_issue.adjust_sum.no_statistics_found"
|
||||
)}
|
||||
</p>`;
|
||||
} else {
|
||||
@@ -234,20 +234,20 @@ export class DialogStatisticsFixUnsupportedUnitMetadata extends DirtyStateProvid
|
||||
return html`
|
||||
<div class="text-content">
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.developer-tools.tabs.statistics.fix_issue.adjust_sum.info_text_1"
|
||||
"ui.panel.config.tools.tabs.statistics.fix_issue.adjust_sum.info_text_1"
|
||||
)}
|
||||
</div>
|
||||
<div class="text-content">
|
||||
<b
|
||||
>${this.hass.localize(
|
||||
"ui.panel.config.developer-tools.tabs.statistics.fix_issue.adjust_sum.statistic"
|
||||
"ui.panel.config.tools.tabs.statistics.fix_issue.adjust_sum.statistic"
|
||||
)}</b
|
||||
>
|
||||
${this._params!.statistic.statistic_id}
|
||||
</div>
|
||||
<ha-selector-datetime
|
||||
.label=${this.hass.localize(
|
||||
"ui.panel.config.developer-tools.tabs.statistics.fix_issue.adjust_sum.pick_a_time"
|
||||
"ui.panel.config.tools.tabs.statistics.fix_issue.adjust_sum.pick_a_time"
|
||||
)}
|
||||
.hass=${this.hass}
|
||||
.selector=${this._dateTimeSelector}
|
||||
@@ -289,7 +289,7 @@ export class DialogStatisticsFixUnsupportedUnitMetadata extends DirtyStateProvid
|
||||
<div class="text-content">
|
||||
<b
|
||||
>${this.hass.localize(
|
||||
"ui.panel.config.developer-tools.tabs.statistics.fix_issue.adjust_sum.statistic"
|
||||
"ui.panel.config.tools.tabs.statistics.fix_issue.adjust_sum.statistic"
|
||||
)}</b
|
||||
>
|
||||
${this._params!.statistic.statistic_id}
|
||||
@@ -298,7 +298,7 @@ export class DialogStatisticsFixUnsupportedUnitMetadata extends DirtyStateProvid
|
||||
<div class="table-row">
|
||||
<span
|
||||
>${this.hass.localize(
|
||||
"ui.panel.config.developer-tools.tabs.statistics.fix_issue.adjust_sum.start"
|
||||
"ui.panel.config.tools.tabs.statistics.fix_issue.adjust_sum.start"
|
||||
)}</span
|
||||
>
|
||||
<span
|
||||
@@ -313,7 +313,7 @@ export class DialogStatisticsFixUnsupportedUnitMetadata extends DirtyStateProvid
|
||||
<div class="table-row">
|
||||
<span
|
||||
>${this.hass.localize(
|
||||
"ui.panel.config.developer-tools.tabs.statistics.fix_issue.adjust_sum.end"
|
||||
"ui.panel.config.tools.tabs.statistics.fix_issue.adjust_sum.end"
|
||||
)}</span
|
||||
>
|
||||
<span
|
||||
@@ -327,7 +327,7 @@ export class DialogStatisticsFixUnsupportedUnitMetadata extends DirtyStateProvid
|
||||
|
||||
<ha-selector-number
|
||||
.label=${this.hass.localize(
|
||||
"ui.panel.config.developer-tools.tabs.statistics.fix_issue.adjust_sum.new_value"
|
||||
"ui.panel.config.tools.tabs.statistics.fix_issue.adjust_sum.new_value"
|
||||
)}
|
||||
.hass=${this.hass}
|
||||
.selector=${this._amountSelector(unit || undefined, this._precision)}
|
||||
@@ -506,7 +506,7 @@ export class DialogStatisticsFixUnsupportedUnitMetadata extends DirtyStateProvid
|
||||
this._busy = false;
|
||||
showAlertDialog(this, {
|
||||
text: this.hass.localize(
|
||||
"ui.panel.config.developer-tools.tabs.statistics.fix_issue.adjust_sum.error_sum_adjusted",
|
||||
"ui.panel.config.tools.tabs.statistics.fix_issue.adjust_sum.error_sum_adjusted",
|
||||
{ message: err.message || err }
|
||||
),
|
||||
});
|
||||
@@ -514,7 +514,7 @@ export class DialogStatisticsFixUnsupportedUnitMetadata extends DirtyStateProvid
|
||||
}
|
||||
showToast(this, {
|
||||
message: this.hass.localize(
|
||||
"ui.panel.config.developer-tools.tabs.statistics.fix_issue.adjust_sum.sum_adjusted"
|
||||
"ui.panel.config.tools.tabs.statistics.fix_issue.adjust_sum.sum_adjusted"
|
||||
),
|
||||
});
|
||||
this._markDirtyStateClean();
|
||||
+8
-8
@@ -53,13 +53,13 @@ export class DialogStatisticsFixUnitsChanged extends LitElement {
|
||||
<ha-dialog
|
||||
.open=${this._open}
|
||||
header-title=${this.hass.localize(
|
||||
"ui.panel.config.developer-tools.tabs.statistics.fix_issue.units_changed.title"
|
||||
"ui.panel.config.tools.tabs.statistics.fix_issue.units_changed.title"
|
||||
)}
|
||||
@closed=${this._dialogClosed}
|
||||
>
|
||||
<p>
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.developer-tools.tabs.statistics.fix_issue.units_changed.info_text_1",
|
||||
"ui.panel.config.tools.tabs.statistics.fix_issue.units_changed.info_text_1",
|
||||
{
|
||||
name: getStatisticLabel(
|
||||
this.hass,
|
||||
@@ -72,16 +72,16 @@ export class DialogStatisticsFixUnitsChanged extends LitElement {
|
||||
}
|
||||
)}<br />
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.developer-tools.tabs.statistics.fix_issue.units_changed.info_text_2"
|
||||
"ui.panel.config.tools.tabs.statistics.fix_issue.units_changed.info_text_2"
|
||||
)}<br />
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.developer-tools.tabs.statistics.fix_issue.units_changed.info_text_3"
|
||||
"ui.panel.config.tools.tabs.statistics.fix_issue.units_changed.info_text_3"
|
||||
)}
|
||||
</p>
|
||||
|
||||
<ha-radio-group
|
||||
.label=${this.hass.localize(
|
||||
"ui.panel.config.developer-tools.tabs.statistics.fix_issue.units_changed.how_to_fix"
|
||||
"ui.panel.config.tools.tabs.statistics.fix_issue.units_changed.how_to_fix"
|
||||
)}
|
||||
.value=${this._action}
|
||||
name="action"
|
||||
@@ -89,13 +89,13 @@ export class DialogStatisticsFixUnitsChanged extends LitElement {
|
||||
>
|
||||
<ha-radio-option value="update" autofocus>
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.developer-tools.tabs.statistics.fix_issue.units_changed.update",
|
||||
"ui.panel.config.tools.tabs.statistics.fix_issue.units_changed.update",
|
||||
this._params.issue.data
|
||||
)}
|
||||
</ha-radio-option>
|
||||
<ha-radio-option value="clear">
|
||||
${this.hass.localize(
|
||||
`ui.panel.config.developer-tools.tabs.statistics.fix_issue.units_changed.clear`
|
||||
`ui.panel.config.tools.tabs.statistics.fix_issue.units_changed.clear`
|
||||
)}
|
||||
</ha-radio-option>
|
||||
</ha-radio-group>
|
||||
@@ -110,7 +110,7 @@ export class DialogStatisticsFixUnitsChanged extends LitElement {
|
||||
</ha-button>
|
||||
<ha-button slot="primaryAction" @click=${this._fixIssue}>
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.developer-tools.tabs.statistics.fix_issue.fix"
|
||||
"ui.panel.config.tools.tabs.statistics.fix_issue.fix"
|
||||
)}
|
||||
</ha-button>
|
||||
</ha-dialog-footer>
|
||||
+17
-17
@@ -50,13 +50,13 @@ export class DialogStatisticsFix extends LitElement {
|
||||
<ha-dialog
|
||||
.open=${this._open}
|
||||
header-title=${this.hass.localize(
|
||||
`ui.panel.config.developer-tools.tabs.statistics.fix_issue.${issue.type}.title`
|
||||
`ui.panel.config.tools.tabs.statistics.fix_issue.${issue.type}.title`
|
||||
)}
|
||||
@closed=${this._dialogClosed}
|
||||
>
|
||||
<p>
|
||||
${this.hass.localize(
|
||||
`ui.panel.config.developer-tools.tabs.statistics.fix_issue.${issue.type}.info_text_1`,
|
||||
`ui.panel.config.tools.tabs.statistics.fix_issue.${issue.type}.info_text_1`,
|
||||
{
|
||||
name: getStatisticLabel(
|
||||
this.hass,
|
||||
@@ -67,24 +67,24 @@ export class DialogStatisticsFix extends LitElement {
|
||||
...(issue.type === "mean_type_changed"
|
||||
? {
|
||||
metadata_mean_type: this.hass.localize(
|
||||
`ui.panel.config.developer-tools.tabs.statistics.mean_type.${issue.data.metadata_mean_type}`
|
||||
`ui.panel.config.tools.tabs.statistics.mean_type.${issue.data.metadata_mean_type}`
|
||||
),
|
||||
state_mean_type: this.hass.localize(
|
||||
`ui.panel.config.developer-tools.tabs.statistics.mean_type.${issue.data.state_mean_type}`
|
||||
`ui.panel.config.tools.tabs.statistics.mean_type.${issue.data.state_mean_type}`
|
||||
),
|
||||
}
|
||||
: {}),
|
||||
}
|
||||
)}<br /><br />
|
||||
${this.hass.localize(
|
||||
`ui.panel.config.developer-tools.tabs.statistics.fix_issue.${issue.type}.info_text_2`,
|
||||
`ui.panel.config.tools.tabs.statistics.fix_issue.${issue.type}.info_text_2`,
|
||||
{ statistic_id: issue.data.statistic_id }
|
||||
)}
|
||||
${
|
||||
issue.type === "mean_type_changed"
|
||||
? html`<br /><br />
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.developer-tools.tabs.statistics.fix_issue.mean_type_changed.info_text_3",
|
||||
"ui.panel.config.tools.tabs.statistics.fix_issue.mean_type_changed.info_text_3",
|
||||
{ statistic_id: issue.data.statistic_id }
|
||||
)}`
|
||||
: issue.type === "entity_not_recorded"
|
||||
@@ -98,7 +98,7 @@ export class DialogStatisticsFix extends LitElement {
|
||||
rel="noreferrer noopener"
|
||||
>
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.developer-tools.tabs.statistics.fix_issue.entity_not_recorded.info_text_3_link"
|
||||
"ui.panel.config.tools.tabs.statistics.fix_issue.entity_not_recorded.info_text_3_link"
|
||||
)}</a
|
||||
>`
|
||||
: issue.type === "entity_no_longer_recorded"
|
||||
@@ -111,22 +111,22 @@ export class DialogStatisticsFix extends LitElement {
|
||||
rel="noreferrer noopener"
|
||||
>
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.developer-tools.tabs.statistics.fix_issue.entity_no_longer_recorded.info_text_3_link"
|
||||
"ui.panel.config.tools.tabs.statistics.fix_issue.entity_no_longer_recorded.info_text_3_link"
|
||||
)}</a
|
||||
><br /><br />
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.developer-tools.tabs.statistics.fix_issue.entity_no_longer_recorded.info_text_4"
|
||||
"ui.panel.config.tools.tabs.statistics.fix_issue.entity_no_longer_recorded.info_text_4"
|
||||
)}`
|
||||
: issue.type === "state_class_removed"
|
||||
? html`<ul>
|
||||
<li>
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.developer-tools.tabs.statistics.fix_issue.state_class_removed.info_text_3"
|
||||
"ui.panel.config.tools.tabs.statistics.fix_issue.state_class_removed.info_text_3"
|
||||
)}
|
||||
</li>
|
||||
<li>
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.developer-tools.tabs.statistics.fix_issue.state_class_removed.info_text_4"
|
||||
"ui.panel.config.tools.tabs.statistics.fix_issue.state_class_removed.info_text_4"
|
||||
)}
|
||||
<a
|
||||
href="https://developers.home-assistant.io/docs/core/entity/sensor/#long-term-statistics"
|
||||
@@ -134,18 +134,18 @@ export class DialogStatisticsFix extends LitElement {
|
||||
rel="noreferrer noopener"
|
||||
>
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.developer-tools.tabs.statistics.fix_issue.state_class_removed.info_text_4_link"
|
||||
"ui.panel.config.tools.tabs.statistics.fix_issue.state_class_removed.info_text_4_link"
|
||||
)}</a
|
||||
>
|
||||
</li>
|
||||
<li>
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.developer-tools.tabs.statistics.fix_issue.state_class_removed.info_text_5"
|
||||
"ui.panel.config.tools.tabs.statistics.fix_issue.state_class_removed.info_text_5"
|
||||
)}
|
||||
</li>
|
||||
</ul>
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.developer-tools.tabs.statistics.fix_issue.state_class_removed.info_text_6",
|
||||
"ui.panel.config.tools.tabs.statistics.fix_issue.state_class_removed.info_text_6",
|
||||
{ statistic_id: issue.data.statistic_id }
|
||||
)}`
|
||||
: nothing
|
||||
@@ -195,15 +195,15 @@ export class DialogStatisticsFix extends LitElement {
|
||||
title:
|
||||
err.code === "timeout"
|
||||
? this.hass.localize(
|
||||
"ui.panel.config.developer-tools.tabs.statistics.fix_issue.clearing_timeout_title"
|
||||
"ui.panel.config.tools.tabs.statistics.fix_issue.clearing_timeout_title"
|
||||
)
|
||||
: this.hass.localize(
|
||||
"ui.panel.config.developer-tools.tabs.statistics.fix_issue.clearing_failed"
|
||||
"ui.panel.config.tools.tabs.statistics.fix_issue.clearing_failed"
|
||||
),
|
||||
text:
|
||||
err.code === "timeout"
|
||||
? this.hass.localize(
|
||||
"ui.panel.config.developer-tools.tabs.statistics.fix_issue.clearing_timeout_text"
|
||||
"ui.panel.config.tools.tabs.statistics.fix_issue.clearing_timeout_text"
|
||||
)
|
||||
: err.message,
|
||||
});
|
||||
+19
-23
@@ -98,7 +98,7 @@ type DisplayedStatisticData = StatisticData & {
|
||||
issues_string?: string;
|
||||
};
|
||||
|
||||
@customElement("developer-tools-statistics")
|
||||
@customElement("tools-statistics")
|
||||
class HaPanelDevStatistics extends KeyboardShortcutMixin(LitElement) {
|
||||
@property({ type: Boolean, reflect: true }) public narrow = false;
|
||||
|
||||
@@ -188,7 +188,7 @@ class HaPanelDevStatistics extends KeyboardShortcutMixin(LitElement) {
|
||||
?.map(
|
||||
(issue) =>
|
||||
localize(
|
||||
`ui.panel.config.developer-tools.tabs.statistics.issues.${issue.type}`,
|
||||
`ui.panel.config.tools.tabs.statistics.issues.${issue.type}`,
|
||||
issue.data
|
||||
) || issue.type
|
||||
)
|
||||
@@ -204,7 +204,7 @@ class HaPanelDevStatistics extends KeyboardShortcutMixin(LitElement) {
|
||||
): DataTableColumnContainer<DisplayedStatisticData> => ({
|
||||
displayName: {
|
||||
title: localize(
|
||||
"ui.panel.config.developer-tools.tabs.statistics.data_table.name"
|
||||
"ui.panel.config.tools.tabs.statistics.data_table.name"
|
||||
),
|
||||
main: true,
|
||||
sortable: true,
|
||||
@@ -225,7 +225,7 @@ class HaPanelDevStatistics extends KeyboardShortcutMixin(LitElement) {
|
||||
area: getAreaTableColumn(localize),
|
||||
statistic_id: {
|
||||
title: localize(
|
||||
"ui.panel.config.developer-tools.tabs.statistics.data_table.statistic_id"
|
||||
"ui.panel.config.tools.tabs.statistics.data_table.statistic_id"
|
||||
),
|
||||
sortable: true,
|
||||
filterable: true,
|
||||
@@ -233,7 +233,7 @@ class HaPanelDevStatistics extends KeyboardShortcutMixin(LitElement) {
|
||||
},
|
||||
statistics_unit_of_measurement: {
|
||||
title: localize(
|
||||
"ui.panel.config.developer-tools.tabs.statistics.data_table.statistics_unit"
|
||||
"ui.panel.config.tools.tabs.statistics.data_table.statistics_unit"
|
||||
),
|
||||
sortable: true,
|
||||
filterable: true,
|
||||
@@ -241,7 +241,7 @@ class HaPanelDevStatistics extends KeyboardShortcutMixin(LitElement) {
|
||||
},
|
||||
source: {
|
||||
title: localize(
|
||||
"ui.panel.config.developer-tools.tabs.statistics.data_table.source"
|
||||
"ui.panel.config.tools.tabs.statistics.data_table.source"
|
||||
),
|
||||
sortable: true,
|
||||
filterable: true,
|
||||
@@ -249,7 +249,7 @@ class HaPanelDevStatistics extends KeyboardShortcutMixin(LitElement) {
|
||||
},
|
||||
issues_string: {
|
||||
title: localize(
|
||||
"ui.panel.config.developer-tools.tabs.statistics.data_table.issue"
|
||||
"ui.panel.config.tools.tabs.statistics.data_table.issue"
|
||||
),
|
||||
sortable: true,
|
||||
filterable: true,
|
||||
@@ -259,14 +259,12 @@ class HaPanelDevStatistics extends KeyboardShortcutMixin(LitElement) {
|
||||
template: (statistic) =>
|
||||
html`${
|
||||
statistic.issues_string ??
|
||||
localize("ui.panel.config.developer-tools.tabs.statistics.no_issue")
|
||||
localize("ui.panel.config.tools.tabs.statistics.no_issue")
|
||||
}`,
|
||||
},
|
||||
fix: {
|
||||
title: "",
|
||||
label: localize(
|
||||
"ui.panel.config.developer-tools.tabs.statistics.fix_issue.fix"
|
||||
),
|
||||
label: localize("ui.panel.config.tools.tabs.statistics.fix_issue.fix"),
|
||||
type: "icon",
|
||||
template: (statistic) =>
|
||||
html`${
|
||||
@@ -281,8 +279,8 @@ class HaPanelDevStatistics extends KeyboardShortcutMixin(LitElement) {
|
||||
statistic.issues.some((issue) =>
|
||||
FIXABLE_ISSUES.includes(issue.type)
|
||||
)
|
||||
? "ui.panel.config.developer-tools.tabs.statistics.fix_issue.fix"
|
||||
: "ui.panel.config.developer-tools.tabs.statistics.fix_issue.info"
|
||||
? "ui.panel.config.tools.tabs.statistics.fix_issue.fix"
|
||||
: "ui.panel.config.tools.tabs.statistics.fix_issue.info"
|
||||
)}
|
||||
</ha-button>`
|
||||
: "—"
|
||||
@@ -293,9 +291,7 @@ class HaPanelDevStatistics extends KeyboardShortcutMixin(LitElement) {
|
||||
},
|
||||
actions: {
|
||||
title: "",
|
||||
label: localize(
|
||||
"ui.panel.config.developer-tools.tabs.statistics.adjust_sum"
|
||||
),
|
||||
label: localize("ui.panel.config.tools.tabs.statistics.adjust_sum"),
|
||||
type: "icon-button",
|
||||
showNarrow: true,
|
||||
template: (statistic) =>
|
||||
@@ -303,7 +299,7 @@ class HaPanelDevStatistics extends KeyboardShortcutMixin(LitElement) {
|
||||
? html`
|
||||
<ha-icon-button
|
||||
.label=${localize(
|
||||
"ui.panel.config.developer-tools.tabs.statistics.adjust_sum"
|
||||
"ui.panel.config.tools.tabs.statistics.adjust_sum"
|
||||
)}
|
||||
.path=${mdiSlopeUphill}
|
||||
.statistic=${statistic}
|
||||
@@ -500,7 +496,7 @@ class HaPanelDevStatistics extends KeyboardShortcutMixin(LitElement) {
|
||||
</ha-dropdown-item>
|
||||
<ha-dropdown-item @click=${this._selectAllIssues}>
|
||||
${this._i18n.localize(
|
||||
"ui.panel.config.developer-tools.tabs.statistics.data_table.select_all_issues"
|
||||
"ui.panel.config.tools.tabs.statistics.data_table.select_all_issues"
|
||||
)}
|
||||
</ha-dropdown-item>
|
||||
<ha-dropdown-item @click=${this._selectNone}>
|
||||
@@ -529,7 +525,7 @@ class HaPanelDevStatistics extends KeyboardShortcutMixin(LitElement) {
|
||||
</div>
|
||||
<ha-assist-chip
|
||||
.label=${this._i18n.localize(
|
||||
"ui.panel.config.developer-tools.tabs.statistics.delete_selected"
|
||||
"ui.panel.config.tools.tabs.statistics.delete_selected"
|
||||
)}
|
||||
.disabled=${!this._selected.length}
|
||||
@click=${this._clearSelected}
|
||||
@@ -563,7 +559,7 @@ class HaPanelDevStatistics extends KeyboardShortcutMixin(LitElement) {
|
||||
this._registries.areas
|
||||
)}
|
||||
.noDataText=${this._i18n.localize(
|
||||
"ui.panel.config.developer-tools.tabs.statistics.data_table.no_statistics"
|
||||
"ui.panel.config.tools.tabs.statistics.data_table.no_statistics"
|
||||
)}
|
||||
.filter=${this.filter}
|
||||
.selectable=${this._selectMode}
|
||||
@@ -770,10 +766,10 @@ class HaPanelDevStatistics extends KeyboardShortcutMixin(LitElement) {
|
||||
|
||||
await showConfirmationDialog(this, {
|
||||
title: this._i18n.localize(
|
||||
"ui.panel.config.developer-tools.tabs.statistics.multi_delete.title"
|
||||
"ui.panel.config.tools.tabs.statistics.multi_delete.title"
|
||||
),
|
||||
text: html`${this._i18n.localize(
|
||||
"ui.panel.config.developer-tools.tabs.statistics.multi_delete.info_text",
|
||||
"ui.panel.config.tools.tabs.statistics.multi_delete.info_text",
|
||||
{ statistic_count: deletableIds.length }
|
||||
)}`,
|
||||
confirmText: this._i18n.localize("ui.common.delete"),
|
||||
@@ -925,6 +921,6 @@ class HaPanelDevStatistics extends KeyboardShortcutMixin(LitElement) {
|
||||
|
||||
declare global {
|
||||
interface HTMLElementTagNameMap {
|
||||
"developer-tools-statistics": HaPanelDevStatistics;
|
||||
"tools-statistics": HaPanelDevStatistics;
|
||||
}
|
||||
}
|
||||
+19
-19
@@ -40,7 +40,7 @@ For loop example getting entity values in the weather domain:
|
||||
{{ state.name | lower }} is {{state.state_with_unit}}
|
||||
{%- endfor %}.`;
|
||||
|
||||
@customElement("developer-tools-template")
|
||||
@customElement("tools-template")
|
||||
class HaPanelDevTemplate extends LitElement {
|
||||
@property({ attribute: false }) public hass!: HomeAssistant;
|
||||
|
||||
@@ -108,7 +108,7 @@ class HaPanelDevTemplate extends LitElement {
|
||||
<div class="content">
|
||||
<ha-expansion-panel
|
||||
.header=${this.hass.localize(
|
||||
"ui.panel.config.developer-tools.tabs.templates.about"
|
||||
"ui.panel.config.tools.tabs.templates.about"
|
||||
)}
|
||||
outlined
|
||||
.expanded=${this._descriptionExpanded}
|
||||
@@ -117,7 +117,7 @@ class HaPanelDevTemplate extends LitElement {
|
||||
<div class="description">
|
||||
<p>
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.developer-tools.tabs.templates.description"
|
||||
"ui.panel.config.tools.tabs.templates.description"
|
||||
)}
|
||||
</p>
|
||||
<ul>
|
||||
@@ -127,7 +127,7 @@ class HaPanelDevTemplate extends LitElement {
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
>${this.hass.localize(
|
||||
"ui.panel.config.developer-tools.tabs.templates.jinja_documentation"
|
||||
"ui.panel.config.tools.tabs.templates.jinja_documentation"
|
||||
)}
|
||||
</a>
|
||||
</li>
|
||||
@@ -141,7 +141,7 @@ class HaPanelDevTemplate extends LitElement {
|
||||
rel="noreferrer"
|
||||
>
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.developer-tools.tabs.templates.template_extensions"
|
||||
"ui.panel.config.tools.tabs.templates.template_extensions"
|
||||
)}</a
|
||||
>
|
||||
</li>
|
||||
@@ -159,7 +159,7 @@ class HaPanelDevTemplate extends LitElement {
|
||||
<ha-card
|
||||
class="edit-pane"
|
||||
header=${this.hass.localize(
|
||||
"ui.panel.config.developer-tools.tabs.templates.editor"
|
||||
"ui.panel.config.tools.tabs.templates.editor"
|
||||
)}
|
||||
>
|
||||
<div class="card-content">
|
||||
@@ -177,7 +177,7 @@ class HaPanelDevTemplate extends LitElement {
|
||||
<div class="card-actions">
|
||||
<ha-button appearance="plain" @click=${this._restoreDemo}>
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.developer-tools.tabs.templates.reset"
|
||||
"ui.panel.config.tools.tabs.templates.reset"
|
||||
)}
|
||||
</ha-button>
|
||||
<ha-button appearance="plain" @click=${this._clear}>
|
||||
@@ -186,7 +186,7 @@ class HaPanelDevTemplate extends LitElement {
|
||||
</div>
|
||||
<ha-tip>
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.developer-tools.tabs.templates.keyboard_tip",
|
||||
"ui.panel.config.tools.tabs.templates.keyboard_tip",
|
||||
{
|
||||
autocomplete: html`<kbd>Ctrl</kbd>+<kbd>Space</kbd>`,
|
||||
}
|
||||
@@ -197,7 +197,7 @@ class HaPanelDevTemplate extends LitElement {
|
||||
<ha-card
|
||||
class="render-pane"
|
||||
header=${this.hass.localize(
|
||||
"ui.panel.config.developer-tools.tabs.templates.result"
|
||||
"ui.panel.config.tools.tabs.templates.result"
|
||||
)}
|
||||
>
|
||||
<div class="card-content ha-scrollbar">
|
||||
@@ -231,7 +231,7 @@ ${
|
||||
}</pre>
|
||||
<p>
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.developer-tools.tabs.templates.result_type"
|
||||
"ui.panel.config.tools.tabs.templates.result_type"
|
||||
)}:
|
||||
${resultType}
|
||||
</p>
|
||||
@@ -240,7 +240,7 @@ ${
|
||||
? html`
|
||||
<p>
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.developer-tools.tabs.templates.time"
|
||||
"ui.panel.config.tools.tabs.templates.time"
|
||||
)}
|
||||
</p>
|
||||
`
|
||||
@@ -253,7 +253,7 @@ ${
|
||||
? html`
|
||||
<p class="all_listeners">
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.developer-tools.tabs.templates.all_listeners"
|
||||
"ui.panel.config.tools.tabs.templates.all_listeners"
|
||||
)}
|
||||
</p>
|
||||
`
|
||||
@@ -262,7 +262,7 @@ ${
|
||||
? html`
|
||||
<p>
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.developer-tools.tabs.templates.listeners"
|
||||
"ui.panel.config.tools.tabs.templates.listeners"
|
||||
)}
|
||||
</p>
|
||||
<ul>
|
||||
@@ -273,7 +273,7 @@ ${
|
||||
<li>
|
||||
<b
|
||||
>${this.hass.localize(
|
||||
"ui.panel.config.developer-tools.tabs.templates.domain"
|
||||
"ui.panel.config.tools.tabs.templates.domain"
|
||||
)}</b
|
||||
>: ${domain}
|
||||
</li>
|
||||
@@ -286,7 +286,7 @@ ${
|
||||
<li>
|
||||
<b
|
||||
>${this.hass.localize(
|
||||
"ui.panel.config.developer-tools.tabs.templates.entity"
|
||||
"ui.panel.config.tools.tabs.templates.entity"
|
||||
)}</b
|
||||
>: ${entity_id}
|
||||
</li>
|
||||
@@ -297,7 +297,7 @@ ${
|
||||
: !this._templateResult.listeners.time
|
||||
? html`<span class="all_listeners">
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.developer-tools.tabs.templates.no_listeners"
|
||||
"ui.panel.config.tools.tabs.templates.no_listeners"
|
||||
)}
|
||||
</span>`
|
||||
: nothing
|
||||
@@ -596,7 +596,7 @@ ${
|
||||
if (
|
||||
!(await showConfirmationDialog(this, {
|
||||
text: this.hass.localize(
|
||||
"ui.panel.config.developer-tools.tabs.templates.confirm_reset"
|
||||
"ui.panel.config.tools.tabs.templates.confirm_reset"
|
||||
),
|
||||
warning: true,
|
||||
}))
|
||||
@@ -612,7 +612,7 @@ ${
|
||||
if (
|
||||
!(await showConfirmationDialog(this, {
|
||||
text: this.hass.localize(
|
||||
"ui.panel.config.developer-tools.tabs.templates.confirm_clear"
|
||||
"ui.panel.config.tools.tabs.templates.confirm_clear"
|
||||
),
|
||||
warning: true,
|
||||
}))
|
||||
@@ -632,6 +632,6 @@ ${
|
||||
|
||||
declare global {
|
||||
interface HTMLElementTagNameMap {
|
||||
"developer-tools-template": HaPanelDevTemplate;
|
||||
"tools-template": HaPanelDevTemplate;
|
||||
}
|
||||
}
|
||||
+19
-19
@@ -3,8 +3,8 @@ import type { RouterOptions } from "../../../layouts/hass-router-page";
|
||||
import { HassRouterPage } from "../../../layouts/hass-router-page";
|
||||
import type { HomeAssistant } from "../../../types";
|
||||
|
||||
@customElement("developer-tools-router")
|
||||
class DeveloperToolsRouter extends HassRouterPage {
|
||||
@customElement("tools-router")
|
||||
class ToolsRouter extends HassRouterPage {
|
||||
@property({ attribute: false }) public hass!: HomeAssistant;
|
||||
|
||||
@property({ type: Boolean }) public narrow = false;
|
||||
@@ -22,37 +22,37 @@ class DeveloperToolsRouter extends HassRouterPage {
|
||||
showLoading: true,
|
||||
routes: {
|
||||
event: {
|
||||
tag: "developer-tools-event",
|
||||
load: () => import("./event/developer-tools-event"),
|
||||
tag: "tools-event",
|
||||
load: () => import("./event/tools-event"),
|
||||
},
|
||||
service: "action",
|
||||
action: {
|
||||
tag: "developer-tools-action",
|
||||
load: () => import("./action/developer-tools-action"),
|
||||
tag: "tools-action",
|
||||
load: () => import("./action/tools-action"),
|
||||
},
|
||||
state: {
|
||||
tag: "developer-tools-state",
|
||||
load: () => import("./state/developer-tools-state"),
|
||||
tag: "tools-state",
|
||||
load: () => import("./state/tools-state"),
|
||||
},
|
||||
template: {
|
||||
tag: "developer-tools-template",
|
||||
load: () => import("./template/developer-tools-template"),
|
||||
tag: "tools-template",
|
||||
load: () => import("./template/tools-template"),
|
||||
},
|
||||
statistics: {
|
||||
tag: "developer-tools-statistics",
|
||||
load: () => import("./statistics/developer-tools-statistics"),
|
||||
tag: "tools-statistics",
|
||||
load: () => import("./statistics/tools-statistics"),
|
||||
},
|
||||
yaml: {
|
||||
tag: "developer-yaml-config",
|
||||
load: () => import("./yaml_configuration/developer-yaml-config"),
|
||||
tag: "tools-yaml-config",
|
||||
load: () => import("./yaml_configuration/tools-yaml-config"),
|
||||
},
|
||||
assist: {
|
||||
tag: "developer-tools-assist",
|
||||
load: () => import("./assist/developer-tools-assist"),
|
||||
tag: "tools-assist",
|
||||
load: () => import("./assist/tools-assist"),
|
||||
},
|
||||
debug: {
|
||||
tag: "developer-tools-debug",
|
||||
load: () => import("./debug/developer-tools-debug"),
|
||||
tag: "tools-debug",
|
||||
load: () => import("./debug/tools-debug"),
|
||||
},
|
||||
},
|
||||
};
|
||||
@@ -77,6 +77,6 @@ class DeveloperToolsRouter extends HassRouterPage {
|
||||
|
||||
declare global {
|
||||
interface HTMLElementTagNameMap {
|
||||
"developer-tools-router": DeveloperToolsRouter;
|
||||
"tools-router": ToolsRouter;
|
||||
}
|
||||
}
|
||||
+18
-18
@@ -16,7 +16,7 @@ import { haStyle } from "../../../../resources/styles";
|
||||
import type { HomeAssistant, Route, TranslationDict } from "../../../../types";
|
||||
|
||||
type ReloadableDomain = Exclude<
|
||||
keyof TranslationDict["ui"]["panel"]["config"]["developer-tools"]["tabs"]["yaml"]["section"]["reloading"],
|
||||
keyof TranslationDict["ui"]["panel"]["config"]["tools"]["tabs"]["yaml"]["section"]["reloading"],
|
||||
"heading" | "introduction" | "reload"
|
||||
>;
|
||||
|
||||
@@ -25,8 +25,8 @@ interface TranslatedReloadableDomain {
|
||||
name: string;
|
||||
}
|
||||
|
||||
@customElement("developer-yaml-config")
|
||||
export class DeveloperYamlConfig extends LitElement {
|
||||
@customElement("tools-yaml-config")
|
||||
export class ToolsYamlConfig extends LitElement {
|
||||
@property({ attribute: false }) public hass!: HomeAssistant;
|
||||
|
||||
@property({ attribute: "is-wide", type: Boolean }) public isWide = false;
|
||||
@@ -61,10 +61,10 @@ export class DeveloperYamlConfig extends LitElement {
|
||||
domain,
|
||||
name:
|
||||
this.hass.localize(
|
||||
`ui.panel.config.developer-tools.tabs.yaml.section.reloading.${domain}`
|
||||
`ui.panel.config.tools.tabs.yaml.section.reloading.${domain}`
|
||||
) ||
|
||||
this.hass.localize(
|
||||
"ui.panel.config.developer-tools.tabs.yaml.section.reloading.reload",
|
||||
"ui.panel.config.tools.tabs.yaml.section.reloading.reload",
|
||||
{ domain: domainToName(this.hass.localize, domain) }
|
||||
),
|
||||
}))
|
||||
@@ -80,12 +80,12 @@ export class DeveloperYamlConfig extends LitElement {
|
||||
<ha-card
|
||||
outlined
|
||||
header=${this.hass.localize(
|
||||
"ui.panel.config.developer-tools.tabs.yaml.section.validation.heading"
|
||||
"ui.panel.config.tools.tabs.yaml.section.validation.heading"
|
||||
)}
|
||||
>
|
||||
<div class="card-content">
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.developer-tools.tabs.yaml.section.validation.introduction"
|
||||
"ui.panel.config.tools.tabs.yaml.section.validation.introduction"
|
||||
)}
|
||||
${
|
||||
!this._validateResult
|
||||
@@ -103,10 +103,10 @@ export class DeveloperYamlConfig extends LitElement {
|
||||
${
|
||||
this._validateResult.result === "valid"
|
||||
? this.hass.localize(
|
||||
"ui.panel.config.developer-tools.tabs.yaml.section.validation.valid"
|
||||
"ui.panel.config.tools.tabs.yaml.section.validation.valid"
|
||||
)
|
||||
: this.hass.localize(
|
||||
"ui.panel.config.developer-tools.tabs.yaml.section.validation.invalid"
|
||||
"ui.panel.config.tools.tabs.yaml.section.validation.invalid"
|
||||
)
|
||||
}
|
||||
</div>
|
||||
@@ -116,7 +116,7 @@ export class DeveloperYamlConfig extends LitElement {
|
||||
? html`<ha-alert
|
||||
alert-type="error"
|
||||
.title=${this.hass.localize(
|
||||
"ui.panel.config.developer-tools.tabs.yaml.section.validation.errors"
|
||||
"ui.panel.config.tools.tabs.yaml.section.validation.errors"
|
||||
)}
|
||||
>
|
||||
<!-- prettier-ignore -->
|
||||
@@ -131,7 +131,7 @@ export class DeveloperYamlConfig extends LitElement {
|
||||
? html`<ha-alert
|
||||
alert-type="warning"
|
||||
.title=${this.hass.localize(
|
||||
"ui.panel.config.developer-tools.tabs.yaml.section.validation.warnings"
|
||||
"ui.panel.config.tools.tabs.yaml.section.validation.warnings"
|
||||
)}
|
||||
>
|
||||
<!-- prettier-ignore -->
|
||||
@@ -148,7 +148,7 @@ export class DeveloperYamlConfig extends LitElement {
|
||||
<div class="card-actions">
|
||||
<ha-button appearance="plain" @click=${this._validateConfig}>
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.developer-tools.tabs.yaml.section.validation.check_config"
|
||||
"ui.panel.config.tools.tabs.yaml.section.validation.check_config"
|
||||
)}
|
||||
</ha-button>
|
||||
<ha-button
|
||||
@@ -158,7 +158,7 @@ export class DeveloperYamlConfig extends LitElement {
|
||||
.disabled=${this._validateResult?.result === "invalid"}
|
||||
>
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.developer-tools.tabs.yaml.section.server_management.restart"
|
||||
"ui.panel.config.tools.tabs.yaml.section.server_management.restart"
|
||||
)}
|
||||
</ha-button>
|
||||
</div>
|
||||
@@ -166,18 +166,18 @@ export class DeveloperYamlConfig extends LitElement {
|
||||
<ha-card
|
||||
outlined
|
||||
header=${this.hass.localize(
|
||||
"ui.panel.config.developer-tools.tabs.yaml.section.reloading.heading"
|
||||
"ui.panel.config.tools.tabs.yaml.section.reloading.heading"
|
||||
)}
|
||||
>
|
||||
<div class="card-content">
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.developer-tools.tabs.yaml.section.reloading.introduction"
|
||||
"ui.panel.config.tools.tabs.yaml.section.reloading.introduction"
|
||||
)}
|
||||
</div>
|
||||
<div class="card-actions">
|
||||
<ha-call-service-button domain="homeassistant" service="reload_all"
|
||||
>${this.hass.localize(
|
||||
"ui.panel.config.developer-tools.tabs.yaml.section.reloading.all"
|
||||
"ui.panel.config.tools.tabs.yaml.section.reloading.all"
|
||||
)}
|
||||
</ha-call-service-button>
|
||||
</div>
|
||||
@@ -186,7 +186,7 @@ export class DeveloperYamlConfig extends LitElement {
|
||||
domain="homeassistant"
|
||||
service="reload_core_config"
|
||||
>${this.hass.localize(
|
||||
"ui.panel.config.developer-tools.tabs.yaml.section.reloading.core"
|
||||
"ui.panel.config.tools.tabs.yaml.section.reloading.core"
|
||||
)}
|
||||
</ha-call-service-button>
|
||||
</div>
|
||||
@@ -269,6 +269,6 @@ export class DeveloperYamlConfig extends LitElement {
|
||||
|
||||
declare global {
|
||||
interface HTMLElementTagNameMap {
|
||||
"developer-yaml-config": DeveloperYamlConfig;
|
||||
"tools-yaml-config": ToolsYamlConfig;
|
||||
}
|
||||
}
|
||||
@@ -273,7 +273,13 @@ const computeLogbookValue = (
|
||||
if (item.entity_id && item.state) {
|
||||
return {
|
||||
text: stateObj
|
||||
? localizeStateMessage(hass, item.state, stateObj, domain!)
|
||||
? localizeStateMessage(
|
||||
hass,
|
||||
item.state,
|
||||
stateObj,
|
||||
domain!,
|
||||
item.attributes
|
||||
)
|
||||
: item.state,
|
||||
type: "state",
|
||||
};
|
||||
|
||||
@@ -2,6 +2,7 @@ import { mdiVolumeHigh, mdiVolumeOff } from "@mdi/js";
|
||||
import { html, nothing } from "lit";
|
||||
import type { TemplateResult } from "lit";
|
||||
import { supportsFeature } from "../../../../common/entity/supports-feature";
|
||||
import type { LocalizeFunc } from "../../../../common/translations/localize";
|
||||
import "../../../../components/ha-control-button";
|
||||
import "../../../../components/ha-svg-icon";
|
||||
import { forwardHaptic } from "../../../../data/haptics";
|
||||
@@ -12,7 +13,7 @@ import {
|
||||
import type { HomeAssistant } from "../../../../types";
|
||||
|
||||
export const renderMuteButton = (
|
||||
hass: HomeAssistant,
|
||||
localize: LocalizeFunc,
|
||||
stateObj: MediaPlayerEntity,
|
||||
showMuteButton: boolean | undefined,
|
||||
disabled: boolean,
|
||||
@@ -28,7 +29,7 @@ export const renderMuteButton = (
|
||||
return html`
|
||||
<ha-control-button
|
||||
class="mute"
|
||||
.label=${hass.localize(
|
||||
.label=${localize(
|
||||
`ui.card.media_player.${isMuted ? "media_volume_unmute" : "media_volume_mute"}`
|
||||
)}
|
||||
.disabled=${disabled}
|
||||
@@ -43,13 +44,13 @@ export const renderMuteButton = (
|
||||
|
||||
export const toggleMediaPlayerMute = (
|
||||
ev: Event,
|
||||
hass: HomeAssistant,
|
||||
callService: HomeAssistant["callService"],
|
||||
stateObj: MediaPlayerEntity,
|
||||
el: HTMLElement
|
||||
): void => {
|
||||
ev.stopPropagation();
|
||||
forwardHaptic(el, "light");
|
||||
hass.callService("media_player", "volume_mute", {
|
||||
callService("media_player", "volume_mute", {
|
||||
entity_id: stateObj.entity_id,
|
||||
is_volume_muted: !stateObj.attributes.is_volume_muted,
|
||||
});
|
||||
|
||||
@@ -1,12 +1,19 @@
|
||||
import { consume } from "@lit/context";
|
||||
import { mdiShieldOff } from "@mdi/js";
|
||||
import type { HassEntity } from "home-assistant-js-websocket";
|
||||
import type { PropertyValues, TemplateResult } from "lit";
|
||||
import { html, LitElement, nothing } from "lit";
|
||||
import { customElement, property, state } from "lit/decorators";
|
||||
import { styleMap } from "lit/directives/style-map";
|
||||
import memoizeOne from "memoize-one";
|
||||
import {
|
||||
consumeEntityState,
|
||||
consumeLocalize,
|
||||
} from "../../../common/decorators/consume-context-entry";
|
||||
import { computeDomain } from "../../../common/entity/compute_domain";
|
||||
import type { HASSDomEvent } from "../../../common/dom/fire_event";
|
||||
import { stateColorCss } from "../../../common/entity/state_color";
|
||||
import type { LocalizeFunc } from "../../../common/translations/localize";
|
||||
import "../../../components/ha-control-button";
|
||||
import "../../../components/ha-control-button-group";
|
||||
import "../../../components/ha-control-select";
|
||||
@@ -21,8 +28,9 @@ import {
|
||||
setProtectedAlarmControlPanelMode,
|
||||
supportedAlarmModes,
|
||||
} from "../../../data/alarm_control_panel";
|
||||
import { apiContext } from "../../../data/context";
|
||||
import { UNAVAILABLE } from "../../../data/entity/entity";
|
||||
import type { HomeAssistant } from "../../../types";
|
||||
import type { HomeAssistant, HomeAssistantApi } from "../../../types";
|
||||
import type { LovelaceCardFeature, LovelaceCardFeatureEditor } from "../types";
|
||||
import { cardFeatureStyles } from "./common/card-feature-styles";
|
||||
import { filterModes } from "./common/filter-modes";
|
||||
@@ -31,6 +39,11 @@ import type {
|
||||
LovelaceCardFeatureContext,
|
||||
} from "./types";
|
||||
|
||||
const supportsAlarmModesCardFeatureFromState = (stateObj: HassEntity) => {
|
||||
const domain = computeDomain(stateObj.entity_id);
|
||||
return domain === "alarm_control_panel";
|
||||
};
|
||||
|
||||
export const supportsAlarmModesCardFeature = (
|
||||
hass: HomeAssistant,
|
||||
context: LovelaceCardFeatureContext
|
||||
@@ -39,8 +52,7 @@ export const supportsAlarmModesCardFeature = (
|
||||
? hass.states[context.entity_id]
|
||||
: undefined;
|
||||
if (!stateObj) return false;
|
||||
const domain = computeDomain(stateObj.entity_id);
|
||||
return domain === "alarm_control_panel";
|
||||
return supportsAlarmModesCardFeatureFromState(stateObj);
|
||||
};
|
||||
|
||||
@customElement("hui-alarm-modes-card-feature")
|
||||
@@ -48,10 +60,20 @@ class HuiAlarmModeCardFeature
|
||||
extends LitElement
|
||||
implements LovelaceCardFeature
|
||||
{
|
||||
@property({ attribute: false }) public hass?: HomeAssistant;
|
||||
|
||||
@property({ attribute: false }) public context?: LovelaceCardFeatureContext;
|
||||
|
||||
@state()
|
||||
@consumeEntityState({ entityIdPath: ["context", "entity_id"] })
|
||||
private _stateObj?: AlarmControlPanelEntity;
|
||||
|
||||
@state()
|
||||
@consumeLocalize()
|
||||
private _localize!: LocalizeFunc;
|
||||
|
||||
@state()
|
||||
@consume({ context: apiContext, subscribe: true })
|
||||
private _api!: HomeAssistantApi;
|
||||
|
||||
@state() private _config?: AlarmModesCardFeatureConfig;
|
||||
|
||||
@state() _currentMode?: AlarmMode;
|
||||
@@ -74,25 +96,10 @@ class HuiAlarmModeCardFeature
|
||||
this._config = config;
|
||||
}
|
||||
|
||||
private get _stateObj() {
|
||||
if (!this.hass || !this.context || !this.context.entity_id) {
|
||||
return undefined;
|
||||
}
|
||||
return this.hass.states[this.context.entity_id] as
|
||||
AlarmControlPanelEntity | undefined;
|
||||
}
|
||||
|
||||
protected willUpdate(changedProp: PropertyValues<this>): void {
|
||||
protected willUpdate(changedProp: PropertyValues): void {
|
||||
super.willUpdate(changedProp);
|
||||
if (
|
||||
(changedProp.has("hass") || changedProp.has("context")) &&
|
||||
this._stateObj
|
||||
) {
|
||||
const oldHass = changedProp.get("hass") as HomeAssistant | undefined;
|
||||
const oldStateObj = oldHass?.states[this.context!.entity_id!];
|
||||
if (oldStateObj !== this._stateObj) {
|
||||
this._currentMode = this._getCurrentMode(this._stateObj);
|
||||
}
|
||||
if (changedProp.has("_stateObj") && this._stateObj) {
|
||||
this._currentMode = this._getCurrentMode(this._stateObj);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -126,7 +133,11 @@ class HuiAlarmModeCardFeature
|
||||
private async _setMode(mode: AlarmMode) {
|
||||
await setProtectedAlarmControlPanelMode(
|
||||
this,
|
||||
this.hass!,
|
||||
{
|
||||
callService: this._api.callService,
|
||||
callWS: this._api.callWS,
|
||||
localize: this._localize,
|
||||
},
|
||||
this._stateObj!,
|
||||
mode
|
||||
);
|
||||
@@ -135,10 +146,9 @@ class HuiAlarmModeCardFeature
|
||||
protected render(): TemplateResult | typeof nothing {
|
||||
if (
|
||||
!this._config ||
|
||||
!this.hass ||
|
||||
!this.context ||
|
||||
!this._stateObj ||
|
||||
!supportsAlarmModesCardFeature(this.hass, this.context)
|
||||
!supportsAlarmModesCardFeatureFromState(this._stateObj)
|
||||
) {
|
||||
return nothing;
|
||||
}
|
||||
@@ -152,7 +162,7 @@ class HuiAlarmModeCardFeature
|
||||
this._config.modes
|
||||
).map<ControlSelectOption>((mode) => ({
|
||||
value: mode,
|
||||
label: this.hass!.localize(`ui.card.alarm_control_panel.modes.${mode}`),
|
||||
label: this._localize(`ui.card.alarm_control_panel.modes.${mode}`),
|
||||
path: ALARM_MODES[mode].path,
|
||||
}));
|
||||
|
||||
@@ -160,7 +170,7 @@ class HuiAlarmModeCardFeature
|
||||
return html`
|
||||
<ha-control-button-group>
|
||||
<ha-control-button
|
||||
.label=${this.hass.localize("ui.card.alarm_control_panel.disarm")}
|
||||
.label=${this._localize("ui.card.alarm_control_panel.disarm")}
|
||||
@click=${this._disarm}
|
||||
>
|
||||
<ha-svg-icon .path=${mdiShieldOff}></ha-svg-icon>
|
||||
@@ -175,7 +185,7 @@ class HuiAlarmModeCardFeature
|
||||
.value=${this._currentMode}
|
||||
@value-changed=${this._valueChanged}
|
||||
hide-option-label
|
||||
.label=${this.hass.localize("ui.card.alarm_control_panel.modes_label")}
|
||||
.label=${this._localize("ui.card.alarm_control_panel.modes_label")}
|
||||
style=${styleMap({
|
||||
"--control-select-color": color,
|
||||
"--modes-count": options.length.toString(),
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
import type { HassEntity } from "home-assistant-js-websocket";
|
||||
import { css, LitElement, nothing, html } from "lit";
|
||||
import { customElement, property, state } from "lit/decorators";
|
||||
import { consumeEntityState } from "../../../common/decorators/consume-context-entry";
|
||||
import { computeDomain } from "../../../common/entity/compute_domain";
|
||||
import { isNumericFromAttributes } from "../../../common/number/format_number";
|
||||
import type { HomeAssistant } from "../../../types";
|
||||
@@ -9,6 +11,11 @@ import type {
|
||||
BarGaugeCardFeatureConfig,
|
||||
} from "./types";
|
||||
|
||||
const supportsBarGaugeCardFeatureFromState = (stateObj: HassEntity) => {
|
||||
const domain = computeDomain(stateObj.entity_id);
|
||||
return domain === "sensor" && isNumericFromAttributes(stateObj.attributes);
|
||||
};
|
||||
|
||||
export const supportsBarGaugeCardFeature = (
|
||||
hass: HomeAssistant,
|
||||
context: LovelaceCardFeatureContext
|
||||
@@ -17,16 +24,17 @@ export const supportsBarGaugeCardFeature = (
|
||||
? hass.states[context.entity_id]
|
||||
: undefined;
|
||||
if (!stateObj) return false;
|
||||
const domain = computeDomain(stateObj.entity_id);
|
||||
return domain === "sensor" && isNumericFromAttributes(stateObj.attributes);
|
||||
return supportsBarGaugeCardFeatureFromState(stateObj);
|
||||
};
|
||||
|
||||
@customElement("hui-bar-gauge-card-feature")
|
||||
class HuiBarGaugeCardFeature extends LitElement implements LovelaceCardFeature {
|
||||
@property({ attribute: false }) public hass!: HomeAssistant;
|
||||
|
||||
@property({ attribute: false }) public context!: LovelaceCardFeatureContext;
|
||||
|
||||
@state()
|
||||
@consumeEntityState({ entityIdPath: ["context", "entity_id"] })
|
||||
private _stateObj?: HassEntity;
|
||||
|
||||
@state() private _config?: BarGaugeCardFeatureConfig;
|
||||
|
||||
static getStubConfig(): BarGaugeCardFeatureConfig {
|
||||
@@ -50,15 +58,13 @@ class HuiBarGaugeCardFeature extends LitElement implements LovelaceCardFeature {
|
||||
render() {
|
||||
if (
|
||||
!this._config ||
|
||||
!this.hass ||
|
||||
!this.context ||
|
||||
!this.context.entity_id ||
|
||||
!this.hass.states[this.context.entity_id] ||
|
||||
!supportsBarGaugeCardFeature(this.hass, this.context)
|
||||
!this._stateObj ||
|
||||
!supportsBarGaugeCardFeatureFromState(this._stateObj)
|
||||
) {
|
||||
return nothing;
|
||||
}
|
||||
const stateObj = this.hass.states[this.context.entity_id];
|
||||
const stateObj = this._stateObj;
|
||||
const min = this._config.min ?? 0;
|
||||
const max = this._config.max ?? 100;
|
||||
const value = parseFloat(stateObj.state);
|
||||
|
||||
@@ -1,15 +1,22 @@
|
||||
import { consume } from "@lit/context";
|
||||
import type { HassEntity } from "home-assistant-js-websocket";
|
||||
import { html, LitElement, nothing } from "lit";
|
||||
import { customElement, property, state } from "lit/decorators";
|
||||
import {
|
||||
consumeEntityState,
|
||||
consumeLocalize,
|
||||
} from "../../../common/decorators/consume-context-entry";
|
||||
import { computeDomain } from "../../../common/entity/compute_domain";
|
||||
import type { LocalizeFunc } from "../../../common/translations/localize";
|
||||
import "../../../components/ha-control-button";
|
||||
import "../../../components/ha-control-button-group";
|
||||
import { apiContext, servicesContext } from "../../../data/context";
|
||||
import {
|
||||
hasRequiredScriptFields,
|
||||
requiredScriptFieldsFilled,
|
||||
hasRequiredScriptFieldsForServices,
|
||||
requiredScriptFieldsFilledForServices,
|
||||
} from "../../../data/script";
|
||||
import { showMoreInfoDialog } from "../../../dialogs/more-info/show-ha-more-info-dialog";
|
||||
import type { HomeAssistant } from "../../../types";
|
||||
import type { HomeAssistant, HomeAssistantApi } from "../../../types";
|
||||
import type { LovelaceCardFeature, LovelaceCardFeatureEditor } from "../types";
|
||||
import { cardFeatureStyles } from "./common/card-feature-styles";
|
||||
import type {
|
||||
@@ -17,6 +24,11 @@ import type {
|
||||
LovelaceCardFeatureContext,
|
||||
} from "./types";
|
||||
|
||||
const supportsButtonCardFeatureFromState = (stateObj: HassEntity) => {
|
||||
const domain = computeDomain(stateObj.entity_id);
|
||||
return ["button", "input_button", "scene", "script"].includes(domain);
|
||||
};
|
||||
|
||||
export const supportsButtonCardFeature = (
|
||||
hass: HomeAssistant,
|
||||
context: LovelaceCardFeatureContext
|
||||
@@ -25,27 +37,33 @@ export const supportsButtonCardFeature = (
|
||||
? hass.states[context.entity_id]
|
||||
: undefined;
|
||||
if (!stateObj) return false;
|
||||
const domain = computeDomain(stateObj.entity_id);
|
||||
return ["button", "input_button", "scene", "script"].includes(domain);
|
||||
return supportsButtonCardFeatureFromState(stateObj);
|
||||
};
|
||||
|
||||
@customElement("hui-button-card-feature")
|
||||
class HuiButtonCardFeature extends LitElement implements LovelaceCardFeature {
|
||||
@property({ attribute: false }) public hass?: HomeAssistant;
|
||||
|
||||
@property({ attribute: false }) public context?: LovelaceCardFeatureContext;
|
||||
|
||||
@state()
|
||||
@consumeEntityState({ entityIdPath: ["context", "entity_id"] })
|
||||
private _stateObj?: HassEntity;
|
||||
|
||||
@state()
|
||||
@consumeLocalize()
|
||||
private _localize!: LocalizeFunc;
|
||||
|
||||
@state()
|
||||
@consume({ context: apiContext, subscribe: true })
|
||||
private _api!: HomeAssistantApi;
|
||||
|
||||
@state()
|
||||
@consume({ context: servicesContext, subscribe: true })
|
||||
private _services!: HomeAssistant["services"];
|
||||
|
||||
@state() private _config?: ButtonCardFeatureConfig;
|
||||
|
||||
private get _stateObj() {
|
||||
if (!this.hass || !this.context || !this.context.entity_id) {
|
||||
return undefined;
|
||||
}
|
||||
return this.hass.states[this.context.entity_id!] as HassEntity | undefined;
|
||||
}
|
||||
|
||||
private _pressButton() {
|
||||
if (!this.hass || !this._stateObj) return;
|
||||
if (!this._stateObj) return;
|
||||
|
||||
const domain = computeDomain(this._stateObj.entity_id);
|
||||
const service =
|
||||
@@ -54,8 +72,12 @@ class HuiButtonCardFeature extends LitElement implements LovelaceCardFeature {
|
||||
if (domain === "script") {
|
||||
const entityId = this._stateObj.entity_id;
|
||||
if (
|
||||
hasRequiredScriptFields(this.hass!, entityId) &&
|
||||
!requiredScriptFieldsFilled(this.hass!, entityId, this._config?.data)
|
||||
hasRequiredScriptFieldsForServices(this._services, entityId) &&
|
||||
!requiredScriptFieldsFilledForServices(
|
||||
this._services,
|
||||
entityId,
|
||||
this._config?.data
|
||||
)
|
||||
) {
|
||||
showMoreInfoDialog(this, {
|
||||
entityId: entityId,
|
||||
@@ -74,7 +96,7 @@ class HuiButtonCardFeature extends LitElement implements LovelaceCardFeature {
|
||||
: {}),
|
||||
};
|
||||
|
||||
this.hass.callService(domain, service, serviceData);
|
||||
this._api.callService(domain, service, serviceData);
|
||||
}
|
||||
|
||||
static getStubConfig(): ButtonCardFeatureConfig {
|
||||
@@ -93,10 +115,9 @@ class HuiButtonCardFeature extends LitElement implements LovelaceCardFeature {
|
||||
protected render() {
|
||||
if (
|
||||
!this._config ||
|
||||
!this.hass ||
|
||||
!this.context ||
|
||||
!this._stateObj ||
|
||||
!supportsButtonCardFeature(this.hass, this.context)
|
||||
!supportsButtonCardFeatureFromState(this._stateObj)
|
||||
) {
|
||||
return nothing;
|
||||
}
|
||||
@@ -108,10 +129,7 @@ class HuiButtonCardFeature extends LitElement implements LovelaceCardFeature {
|
||||
class="press-button"
|
||||
@click=${this._pressButton}
|
||||
>
|
||||
${
|
||||
this._config.action_name ??
|
||||
this.hass.localize("ui.card.button.press")
|
||||
}
|
||||
${this._config.action_name ?? this._localize("ui.card.button.press")}
|
||||
</ha-control-button>
|
||||
</ha-control-button-group>
|
||||
`;
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { mdiFan } from "@mdi/js";
|
||||
import type { HassEntity } from "home-assistant-js-websocket";
|
||||
import { customElement } from "lit/decorators";
|
||||
import { computeDomain } from "../../../common/entity/compute_domain";
|
||||
import { supportsFeature } from "../../../common/entity/supports-feature";
|
||||
@@ -12,6 +13,14 @@ import type {
|
||||
LovelaceCardFeatureContext,
|
||||
} from "./types";
|
||||
|
||||
const supportsClimateFanModesCardFeatureFromState = (stateObj: HassEntity) => {
|
||||
const domain = computeDomain(stateObj.entity_id);
|
||||
return (
|
||||
domain === "climate" &&
|
||||
supportsFeature(stateObj, ClimateEntityFeature.FAN_MODE)
|
||||
);
|
||||
};
|
||||
|
||||
export const supportsClimateFanModesCardFeature = (
|
||||
hass: HomeAssistant,
|
||||
context: LovelaceCardFeatureContext
|
||||
@@ -20,11 +29,7 @@ export const supportsClimateFanModesCardFeature = (
|
||||
? hass.states[context.entity_id]
|
||||
: undefined;
|
||||
if (!stateObj) return false;
|
||||
const domain = computeDomain(stateObj.entity_id);
|
||||
return (
|
||||
domain === "climate" &&
|
||||
supportsFeature(stateObj, ClimateEntityFeature.FAN_MODE)
|
||||
);
|
||||
return supportsClimateFanModesCardFeatureFromState(stateObj);
|
||||
};
|
||||
|
||||
@customElement("hui-climate-fan-modes-card-feature")
|
||||
@@ -63,9 +68,8 @@ class HuiClimateFanModesCardFeature
|
||||
|
||||
protected _isSupported(): boolean {
|
||||
return !!(
|
||||
this.hass &&
|
||||
this.context &&
|
||||
supportsClimateFanModesCardFeature(this.hass, this.context)
|
||||
this._stateObj &&
|
||||
supportsClimateFanModesCardFeatureFromState(this._stateObj)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { mdiThermostat } from "@mdi/js";
|
||||
import type { HassEntity } from "home-assistant-js-websocket";
|
||||
import type { TemplateResult } from "lit";
|
||||
import { html } from "lit";
|
||||
import { customElement } from "lit/decorators";
|
||||
@@ -25,6 +26,11 @@ interface HvacModeOption extends HuiModeSelectOption {
|
||||
iconPath: string;
|
||||
}
|
||||
|
||||
const supportsClimateHvacModesCardFeatureFromState = (stateObj: HassEntity) => {
|
||||
const domain = computeDomain(stateObj.entity_id);
|
||||
return domain === "climate";
|
||||
};
|
||||
|
||||
export const supportsClimateHvacModesCardFeature = (
|
||||
hass: HomeAssistant,
|
||||
context: LovelaceCardFeatureContext
|
||||
@@ -33,8 +39,7 @@ export const supportsClimateHvacModesCardFeature = (
|
||||
? hass.states[context.entity_id]
|
||||
: undefined;
|
||||
if (!stateObj) return false;
|
||||
const domain = computeDomain(stateObj.entity_id);
|
||||
return domain === "climate";
|
||||
return supportsClimateHvacModesCardFeatureFromState(stateObj);
|
||||
};
|
||||
|
||||
@customElement("hui-climate-hvac-modes-card-feature")
|
||||
@@ -60,7 +65,7 @@ class HuiClimateHvacModesCardFeature
|
||||
protected readonly _serviceAction = "set_hvac_mode";
|
||||
|
||||
protected get _label(): string {
|
||||
return this.hass!.localize("ui.card.climate.mode");
|
||||
return this._localize("ui.card.climate.mode");
|
||||
}
|
||||
|
||||
protected readonly _showDropdownOptionIcons = false;
|
||||
@@ -94,7 +99,7 @@ class HuiClimateHvacModesCardFeature
|
||||
}
|
||||
|
||||
protected _getOptions(): HvacModeOption[] {
|
||||
if (!this._stateObj || !this.hass) {
|
||||
if (!this._stateObj) {
|
||||
return [];
|
||||
}
|
||||
|
||||
@@ -106,7 +111,7 @@ class HuiClimateHvacModesCardFeature
|
||||
return filterModes(orderedHvacModes, this._config?.hvac_modes).map(
|
||||
(mode) => ({
|
||||
value: mode,
|
||||
label: this.hass!.formatEntityState(this._stateObj!, mode),
|
||||
label: this._formatters.formatEntityState(this._stateObj!, mode),
|
||||
iconPath: climateHvacModeIcon(mode),
|
||||
})
|
||||
);
|
||||
@@ -121,9 +126,8 @@ class HuiClimateHvacModesCardFeature
|
||||
|
||||
protected _isSupported(): boolean {
|
||||
return !!(
|
||||
this.hass &&
|
||||
this.context &&
|
||||
supportsClimateHvacModesCardFeature(this.hass, this.context)
|
||||
this._stateObj &&
|
||||
supportsClimateHvacModesCardFeatureFromState(this._stateObj)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { mdiTuneVariant } from "@mdi/js";
|
||||
import type { HassEntity } from "home-assistant-js-websocket";
|
||||
import { customElement } from "lit/decorators";
|
||||
import { computeDomain } from "../../../common/entity/compute_domain";
|
||||
import { supportsFeature } from "../../../common/entity/supports-feature";
|
||||
@@ -12,6 +13,16 @@ import type {
|
||||
LovelaceCardFeatureContext,
|
||||
} from "./types";
|
||||
|
||||
const supportsClimatePresetModesCardFeatureFromState = (
|
||||
stateObj: HassEntity
|
||||
) => {
|
||||
const domain = computeDomain(stateObj.entity_id);
|
||||
return (
|
||||
domain === "climate" &&
|
||||
supportsFeature(stateObj, ClimateEntityFeature.PRESET_MODE)
|
||||
);
|
||||
};
|
||||
|
||||
export const supportsClimatePresetModesCardFeature = (
|
||||
hass: HomeAssistant,
|
||||
context: LovelaceCardFeatureContext
|
||||
@@ -20,11 +31,7 @@ export const supportsClimatePresetModesCardFeature = (
|
||||
? hass.states[context.entity_id]
|
||||
: undefined;
|
||||
if (!stateObj) return false;
|
||||
const domain = computeDomain(stateObj.entity_id);
|
||||
return (
|
||||
domain === "climate" &&
|
||||
supportsFeature(stateObj, ClimateEntityFeature.PRESET_MODE)
|
||||
);
|
||||
return supportsClimatePresetModesCardFeatureFromState(stateObj);
|
||||
};
|
||||
|
||||
@customElement("hui-climate-preset-modes-card-feature")
|
||||
@@ -65,9 +72,8 @@ class HuiClimatePresetModesCardFeature
|
||||
|
||||
protected _isSupported(): boolean {
|
||||
return !!(
|
||||
this.hass &&
|
||||
this.context &&
|
||||
supportsClimatePresetModesCardFeature(this.hass, this.context)
|
||||
this._stateObj &&
|
||||
supportsClimatePresetModesCardFeatureFromState(this._stateObj)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
+14
-8
@@ -1,4 +1,5 @@
|
||||
import { mdiArrowOscillating } from "@mdi/js";
|
||||
import type { HassEntity } from "home-assistant-js-websocket";
|
||||
import { customElement } from "lit/decorators";
|
||||
import { computeDomain } from "../../../common/entity/compute_domain";
|
||||
import { supportsFeature } from "../../../common/entity/supports-feature";
|
||||
@@ -12,6 +13,16 @@ import type {
|
||||
LovelaceCardFeatureContext,
|
||||
} from "./types";
|
||||
|
||||
const supportsClimateSwingHorizontalModesCardFeatureFromState = (
|
||||
stateObj: HassEntity
|
||||
) => {
|
||||
const domain = computeDomain(stateObj.entity_id);
|
||||
return (
|
||||
domain === "climate" &&
|
||||
supportsFeature(stateObj, ClimateEntityFeature.SWING_HORIZONTAL_MODE)
|
||||
);
|
||||
};
|
||||
|
||||
export const supportsClimateSwingHorizontalModesCardFeature = (
|
||||
hass: HomeAssistant,
|
||||
context: LovelaceCardFeatureContext
|
||||
@@ -20,11 +31,7 @@ export const supportsClimateSwingHorizontalModesCardFeature = (
|
||||
? hass.states[context.entity_id]
|
||||
: undefined;
|
||||
if (!stateObj) return false;
|
||||
const domain = computeDomain(stateObj.entity_id);
|
||||
return (
|
||||
domain === "climate" &&
|
||||
supportsFeature(stateObj, ClimateEntityFeature.SWING_HORIZONTAL_MODE)
|
||||
);
|
||||
return supportsClimateSwingHorizontalModesCardFeatureFromState(stateObj);
|
||||
};
|
||||
|
||||
@customElement("hui-climate-swing-horizontal-modes-card-feature")
|
||||
@@ -65,9 +72,8 @@ class HuiClimateSwingHorizontalModesCardFeature
|
||||
|
||||
protected _isSupported(): boolean {
|
||||
return !!(
|
||||
this.hass &&
|
||||
this.context &&
|
||||
supportsClimateSwingHorizontalModesCardFeature(this.hass, this.context)
|
||||
this._stateObj &&
|
||||
supportsClimateSwingHorizontalModesCardFeatureFromState(this._stateObj)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { mdiArrowOscillating } from "@mdi/js";
|
||||
import type { HassEntity } from "home-assistant-js-websocket";
|
||||
import { customElement } from "lit/decorators";
|
||||
import { computeDomain } from "../../../common/entity/compute_domain";
|
||||
import { supportsFeature } from "../../../common/entity/supports-feature";
|
||||
@@ -12,6 +13,16 @@ import type {
|
||||
LovelaceCardFeatureContext,
|
||||
} from "./types";
|
||||
|
||||
const supportsClimateSwingModesCardFeatureFromState = (
|
||||
stateObj: HassEntity
|
||||
) => {
|
||||
const domain = computeDomain(stateObj.entity_id);
|
||||
return (
|
||||
domain === "climate" &&
|
||||
supportsFeature(stateObj, ClimateEntityFeature.SWING_MODE)
|
||||
);
|
||||
};
|
||||
|
||||
export const supportsClimateSwingModesCardFeature = (
|
||||
hass: HomeAssistant,
|
||||
context: LovelaceCardFeatureContext
|
||||
@@ -20,11 +31,7 @@ export const supportsClimateSwingModesCardFeature = (
|
||||
? hass.states[context.entity_id]
|
||||
: undefined;
|
||||
if (!stateObj) return false;
|
||||
const domain = computeDomain(stateObj.entity_id);
|
||||
return (
|
||||
domain === "climate" &&
|
||||
supportsFeature(stateObj, ClimateEntityFeature.SWING_MODE)
|
||||
);
|
||||
return supportsClimateSwingModesCardFeatureFromState(stateObj);
|
||||
};
|
||||
|
||||
@customElement("hui-climate-swing-modes-card-feature")
|
||||
@@ -65,9 +72,8 @@ class HuiClimateSwingModesCardFeature
|
||||
|
||||
protected _isSupported(): boolean {
|
||||
return !!(
|
||||
this.hass &&
|
||||
this.context &&
|
||||
supportsClimateSwingModesCardFeature(this.hass, this.context)
|
||||
this._stateObj &&
|
||||
supportsClimateSwingModesCardFeatureFromState(this._stateObj)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,14 +1,21 @@
|
||||
import { consume } from "@lit/context";
|
||||
import { mdiMinus, mdiPlus, mdiRestore } from "@mdi/js";
|
||||
import type { HassEntity } from "home-assistant-js-websocket";
|
||||
import type { TemplateResult } from "lit";
|
||||
import { LitElement, html } from "lit";
|
||||
import { customElement, property, state } from "lit/decorators";
|
||||
import {
|
||||
consumeEntityState,
|
||||
consumeLocalize,
|
||||
} from "../../../common/decorators/consume-context-entry";
|
||||
import { computeDomain } from "../../../common/entity/compute_domain";
|
||||
import type { LocalizeFunc } from "../../../common/translations/localize";
|
||||
import "../../../components/ha-control-button";
|
||||
import "../../../components/ha-control-button-group";
|
||||
import "../../../components/ha-control-select";
|
||||
import { apiContext } from "../../../data/context";
|
||||
import { UNAVAILABLE } from "../../../data/entity/entity";
|
||||
import type { HomeAssistant } from "../../../types";
|
||||
import type { HomeAssistant, HomeAssistantApi } from "../../../types";
|
||||
import type { LovelaceCardFeature, LovelaceCardFeatureEditor } from "../types";
|
||||
import { cardFeatureStyles } from "./common/card-feature-styles";
|
||||
import {
|
||||
@@ -17,6 +24,11 @@ import {
|
||||
type LovelaceCardFeatureContext,
|
||||
} from "./types";
|
||||
|
||||
const supportsCounterActionsCardFeatureFromState = (stateObj: HassEntity) => {
|
||||
const domain = computeDomain(stateObj.entity_id);
|
||||
return domain === "counter";
|
||||
};
|
||||
|
||||
export const supportsCounterActionsCardFeature = (
|
||||
hass: HomeAssistant,
|
||||
context: LovelaceCardFeatureContext
|
||||
@@ -25,8 +37,7 @@ export const supportsCounterActionsCardFeature = (
|
||||
? hass.states[context.entity_id]
|
||||
: undefined;
|
||||
if (!stateObj) return false;
|
||||
const domain = computeDomain(stateObj.entity_id);
|
||||
return domain === "counter";
|
||||
return supportsCounterActionsCardFeatureFromState(stateObj);
|
||||
};
|
||||
|
||||
interface CounterButton {
|
||||
@@ -65,18 +76,21 @@ class HuiCounterActionsCardFeature
|
||||
extends LitElement
|
||||
implements LovelaceCardFeature
|
||||
{
|
||||
@property({ attribute: false }) public hass?: HomeAssistant;
|
||||
|
||||
@property({ attribute: false }) public context?: LovelaceCardFeatureContext;
|
||||
|
||||
@state() private _config?: CounterActionsCardFeatureConfig;
|
||||
@state()
|
||||
@consumeEntityState({ entityIdPath: ["context", "entity_id"] })
|
||||
private _stateObj?: HassEntity;
|
||||
|
||||
private get _stateObj() {
|
||||
if (!this.hass || !this.context || !this.context.entity_id) {
|
||||
return undefined;
|
||||
}
|
||||
return this.hass.states[this.context.entity_id!] as HassEntity | undefined;
|
||||
}
|
||||
@state()
|
||||
@consumeLocalize()
|
||||
private _localize!: LocalizeFunc;
|
||||
|
||||
@state()
|
||||
@consume({ context: apiContext, subscribe: true })
|
||||
private _api!: HomeAssistantApi;
|
||||
|
||||
@state() private _config?: CounterActionsCardFeatureConfig;
|
||||
|
||||
public static async getConfigElement(): Promise<LovelaceCardFeatureEditor> {
|
||||
await import("../editor/config-elements/hui-counter-actions-card-feature-editor");
|
||||
@@ -99,10 +113,9 @@ class HuiCounterActionsCardFeature
|
||||
protected render(): TemplateResult | null {
|
||||
if (
|
||||
!this._config ||
|
||||
!this.hass ||
|
||||
!this.context ||
|
||||
!this._stateObj ||
|
||||
!supportsCounterActionsCardFeature(this.hass, this.context)
|
||||
!supportsCounterActionsCardFeatureFromState(this._stateObj)
|
||||
) {
|
||||
return null;
|
||||
}
|
||||
@@ -118,7 +131,7 @@ class HuiCounterActionsCardFeature
|
||||
return html`
|
||||
<ha-control-button
|
||||
.entry=${button}
|
||||
.label=${this.hass!.localize(
|
||||
.label=${this._localize(
|
||||
// @ts-ignore
|
||||
`ui.card.counter.actions.${button.translationKey}`
|
||||
)}
|
||||
@@ -138,7 +151,7 @@ class HuiCounterActionsCardFeature
|
||||
private _onActionTap(ev): void {
|
||||
ev.stopPropagation();
|
||||
const entry = (ev.target! as any).entry as CounterButton;
|
||||
this.hass!.callService("counter", entry.serviceName, {
|
||||
this._api.callService("counter", entry.serviceName, {
|
||||
entity_id: this._stateObj!.entity_id,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,15 +1,23 @@
|
||||
import { consume } from "@lit/context";
|
||||
import { mdiStop } from "@mdi/js";
|
||||
import type { HassEntity } from "home-assistant-js-websocket";
|
||||
import { html, LitElement, nothing } from "lit";
|
||||
import { customElement, property, state } from "lit/decorators";
|
||||
import {
|
||||
consumeEntityState,
|
||||
consumeLocalize,
|
||||
} from "../../../common/decorators/consume-context-entry";
|
||||
import { computeDomain } from "../../../common/entity/compute_domain";
|
||||
import {
|
||||
computeCloseIcon,
|
||||
computeOpenIcon,
|
||||
} from "../../../common/entity/cover_icon";
|
||||
import { supportsFeature } from "../../../common/entity/supports-feature";
|
||||
import type { LocalizeFunc } from "../../../common/translations/localize";
|
||||
import "../../../components/ha-control-button";
|
||||
import "../../../components/ha-control-button-group";
|
||||
import "../../../components/ha-svg-icon";
|
||||
import { apiContext } from "../../../data/context";
|
||||
import {
|
||||
canClose,
|
||||
canOpen,
|
||||
@@ -17,7 +25,7 @@ import {
|
||||
CoverEntityFeature,
|
||||
type CoverEntity,
|
||||
} from "../../../data/cover";
|
||||
import type { HomeAssistant } from "../../../types";
|
||||
import type { HomeAssistant, HomeAssistantApi } from "../../../types";
|
||||
import type { LovelaceCardFeature } from "../types";
|
||||
import { cardFeatureStyles } from "./common/card-feature-styles";
|
||||
import type {
|
||||
@@ -25,6 +33,15 @@ import type {
|
||||
LovelaceCardFeatureContext,
|
||||
} from "./types";
|
||||
|
||||
const supportsCoverOpenCloseCardFeatureFromState = (stateObj: HassEntity) => {
|
||||
const domain = computeDomain(stateObj.entity_id);
|
||||
return (
|
||||
domain === "cover" &&
|
||||
(supportsFeature(stateObj, CoverEntityFeature.OPEN) ||
|
||||
supportsFeature(stateObj, CoverEntityFeature.CLOSE))
|
||||
);
|
||||
};
|
||||
|
||||
export const supportsCoverOpenCloseCardFeature = (
|
||||
hass: HomeAssistant,
|
||||
context: LovelaceCardFeatureContext
|
||||
@@ -33,12 +50,7 @@ export const supportsCoverOpenCloseCardFeature = (
|
||||
? hass.states[context.entity_id]
|
||||
: undefined;
|
||||
if (!stateObj) return false;
|
||||
const domain = computeDomain(stateObj.entity_id);
|
||||
return (
|
||||
domain === "cover" &&
|
||||
(supportsFeature(stateObj, CoverEntityFeature.OPEN) ||
|
||||
supportsFeature(stateObj, CoverEntityFeature.CLOSE))
|
||||
);
|
||||
return supportsCoverOpenCloseCardFeatureFromState(stateObj);
|
||||
};
|
||||
|
||||
@customElement("hui-cover-open-close-card-feature")
|
||||
@@ -46,18 +58,21 @@ class HuiCoverOpenCloseCardFeature
|
||||
extends LitElement
|
||||
implements LovelaceCardFeature
|
||||
{
|
||||
@property({ attribute: false }) public hass?: HomeAssistant;
|
||||
|
||||
@property({ attribute: false }) public context?: LovelaceCardFeatureContext;
|
||||
|
||||
@state() private _config?: CoverOpenCloseCardFeatureConfig;
|
||||
@state()
|
||||
@consumeEntityState({ entityIdPath: ["context", "entity_id"] })
|
||||
private _stateObj?: CoverEntity;
|
||||
|
||||
private get _stateObj() {
|
||||
if (!this.hass || !this.context || !this.context.entity_id) {
|
||||
return undefined;
|
||||
}
|
||||
return this.hass.states[this.context.entity_id!] as CoverEntity | undefined;
|
||||
}
|
||||
@state()
|
||||
@consumeLocalize()
|
||||
private _localize!: LocalizeFunc;
|
||||
|
||||
@state()
|
||||
@consume({ context: apiContext, subscribe: true })
|
||||
private _api!: HomeAssistantApi;
|
||||
|
||||
@state() private _config?: CoverOpenCloseCardFeatureConfig;
|
||||
|
||||
static getStubConfig(): CoverOpenCloseCardFeatureConfig {
|
||||
return {
|
||||
@@ -74,21 +89,21 @@ class HuiCoverOpenCloseCardFeature
|
||||
|
||||
private _onOpenTap(ev): void {
|
||||
ev.stopPropagation();
|
||||
this.hass!.callService("cover", "open_cover", {
|
||||
this._api.callService("cover", "open_cover", {
|
||||
entity_id: this._stateObj!.entity_id,
|
||||
});
|
||||
}
|
||||
|
||||
private _onCloseTap(ev): void {
|
||||
ev.stopPropagation();
|
||||
this.hass!.callService("cover", "close_cover", {
|
||||
this._api.callService("cover", "close_cover", {
|
||||
entity_id: this._stateObj!.entity_id,
|
||||
});
|
||||
}
|
||||
|
||||
private _onStopTap(ev): void {
|
||||
ev.stopPropagation();
|
||||
this.hass!.callService("cover", "stop_cover", {
|
||||
this._api.callService("cover", "stop_cover", {
|
||||
entity_id: this._stateObj!.entity_id,
|
||||
});
|
||||
}
|
||||
@@ -96,10 +111,9 @@ class HuiCoverOpenCloseCardFeature
|
||||
protected render() {
|
||||
if (
|
||||
!this._config ||
|
||||
!this.hass ||
|
||||
!this.context ||
|
||||
!this._stateObj ||
|
||||
!supportsCoverOpenCloseCardFeature(this.hass, this.context)
|
||||
!supportsCoverOpenCloseCardFeatureFromState(this._stateObj)
|
||||
) {
|
||||
return nothing;
|
||||
}
|
||||
@@ -110,7 +124,7 @@ class HuiCoverOpenCloseCardFeature
|
||||
supportsFeature(this._stateObj, CoverEntityFeature.OPEN)
|
||||
? html`
|
||||
<ha-control-button
|
||||
.label=${this.hass.localize("ui.card.cover.open_cover")}
|
||||
.label=${this._localize("ui.card.cover.open_cover")}
|
||||
@click=${this._onOpenTap}
|
||||
.disabled=${!canOpen(this._stateObj)}
|
||||
>
|
||||
@@ -125,7 +139,7 @@ class HuiCoverOpenCloseCardFeature
|
||||
supportsFeature(this._stateObj, CoverEntityFeature.STOP)
|
||||
? html`
|
||||
<ha-control-button
|
||||
.label=${this.hass.localize("ui.card.cover.stop_cover")}
|
||||
.label=${this._localize("ui.card.cover.stop_cover")}
|
||||
@click=${this._onStopTap}
|
||||
.disabled=${!canStop(this._stateObj)}
|
||||
>
|
||||
@@ -138,7 +152,7 @@ class HuiCoverOpenCloseCardFeature
|
||||
supportsFeature(this._stateObj, CoverEntityFeature.CLOSE)
|
||||
? html`
|
||||
<ha-control-button
|
||||
.label=${this.hass.localize("ui.card.cover.close_cover")}
|
||||
.label=${this._localize("ui.card.cover.close_cover")}
|
||||
@click=${this._onCloseTap}
|
||||
.disabled=${!canClose(this._stateObj)}
|
||||
>
|
||||
|
||||
@@ -1,17 +1,35 @@
|
||||
import { consume } from "@lit/context";
|
||||
import type { HassEntity } from "home-assistant-js-websocket";
|
||||
import { html, LitElement, nothing } from "lit";
|
||||
import { customElement, property, state } from "lit/decorators";
|
||||
import { styleMap } from "lit/directives/style-map";
|
||||
import { computeCssColor } from "../../../common/color/compute-color";
|
||||
import {
|
||||
consumeEntityState,
|
||||
consumeLocalize,
|
||||
} from "../../../common/decorators/consume-context-entry";
|
||||
import { transform } from "../../../common/decorators/transform";
|
||||
import type { HASSDomEvent } from "../../../common/dom/fire_event";
|
||||
import { computeAttributeNameDisplay } from "../../../common/entity/compute_attribute_display";
|
||||
import { computeDomain } from "../../../common/entity/compute_domain";
|
||||
import { stateActive } from "../../../common/entity/state_active";
|
||||
import { stateColorCss } from "../../../common/entity/state_color";
|
||||
import type { LocalizeFunc } from "../../../common/translations/localize";
|
||||
import "../../../components/ha-control-slider";
|
||||
import { coverSupportsPosition, type CoverEntity } from "../../../data/cover";
|
||||
import {
|
||||
apiContext,
|
||||
entitiesContext,
|
||||
internationalizationContext,
|
||||
} from "../../../data/context";
|
||||
import { UNAVAILABLE } from "../../../data/entity/entity";
|
||||
import { DOMAIN_ATTRIBUTES_UNITS } from "../../../data/entity/entity_attributes";
|
||||
import type { HomeAssistant } from "../../../types";
|
||||
import type { FrontendLocaleData } from "../../../data/translation";
|
||||
import type {
|
||||
HomeAssistant,
|
||||
HomeAssistantApi,
|
||||
HomeAssistantInternationalization,
|
||||
} from "../../../types";
|
||||
import type { LovelaceCardFeature } from "../types";
|
||||
import { cardFeatureStyles } from "./common/card-feature-styles";
|
||||
import type {
|
||||
@@ -19,6 +37,11 @@ import type {
|
||||
LovelaceCardFeatureContext,
|
||||
} from "./types";
|
||||
|
||||
const supportsCoverPositionCardFeatureFromState = (stateObj: HassEntity) => {
|
||||
const domain = computeDomain(stateObj.entity_id);
|
||||
return domain === "cover" && coverSupportsPosition(stateObj);
|
||||
};
|
||||
|
||||
export const supportsCoverPositionCardFeature = (
|
||||
hass: HomeAssistant,
|
||||
context: LovelaceCardFeatureContext
|
||||
@@ -27,8 +50,7 @@ export const supportsCoverPositionCardFeature = (
|
||||
? hass.states[context.entity_id]
|
||||
: undefined;
|
||||
if (!stateObj) return false;
|
||||
const domain = computeDomain(stateObj.entity_id);
|
||||
return domain === "cover" && coverSupportsPosition(stateObj);
|
||||
return supportsCoverPositionCardFeatureFromState(stateObj);
|
||||
};
|
||||
|
||||
@customElement("hui-cover-position-card-feature")
|
||||
@@ -36,20 +58,34 @@ class HuiCoverPositionCardFeature
|
||||
extends LitElement
|
||||
implements LovelaceCardFeature
|
||||
{
|
||||
@property({ attribute: false }) public hass?: HomeAssistant;
|
||||
|
||||
@property({ attribute: false }) public context?: LovelaceCardFeatureContext;
|
||||
|
||||
@property({ attribute: false }) public color?: string;
|
||||
|
||||
@state() private _config?: CoverPositionCardFeatureConfig;
|
||||
@state()
|
||||
@consumeEntityState({ entityIdPath: ["context", "entity_id"] })
|
||||
private _stateObj?: CoverEntity;
|
||||
|
||||
private get _stateObj(): CoverEntity | undefined {
|
||||
if (!this.hass || !this.context || !this.context.entity_id) {
|
||||
return undefined;
|
||||
}
|
||||
return this.hass.states[this.context.entity_id!];
|
||||
}
|
||||
@state()
|
||||
@consumeLocalize()
|
||||
private _localize!: LocalizeFunc;
|
||||
|
||||
@state()
|
||||
@consume({ context: apiContext, subscribe: true })
|
||||
private _api!: HomeAssistantApi;
|
||||
|
||||
@state()
|
||||
@consume({ context: entitiesContext, subscribe: true })
|
||||
private _entities!: HomeAssistant["entities"];
|
||||
|
||||
@state()
|
||||
@consume({ context: internationalizationContext, subscribe: true })
|
||||
@transform<HomeAssistantInternationalization, FrontendLocaleData>({
|
||||
transformer: ({ locale }) => locale,
|
||||
})
|
||||
private _locale?: FrontendLocaleData;
|
||||
|
||||
@state() private _config?: CoverPositionCardFeatureConfig;
|
||||
|
||||
static getStubConfig(): CoverPositionCardFeatureConfig {
|
||||
return {
|
||||
@@ -67,10 +103,9 @@ class HuiCoverPositionCardFeature
|
||||
protected render() {
|
||||
if (
|
||||
!this._config ||
|
||||
!this.hass ||
|
||||
!this.context ||
|
||||
!this._stateObj ||
|
||||
!supportsCoverPositionCardFeature(this.hass, this.context)
|
||||
!supportsCoverPositionCardFeatureFromState(this._stateObj)
|
||||
) {
|
||||
return nothing;
|
||||
}
|
||||
@@ -104,14 +139,14 @@ class HuiCoverPositionCardFeature
|
||||
show-handle
|
||||
@value-changed=${this._valueChanged}
|
||||
.label=${computeAttributeNameDisplay(
|
||||
this.hass.localize,
|
||||
this._localize,
|
||||
this._stateObj,
|
||||
this.hass.entities,
|
||||
this._entities,
|
||||
"current_position"
|
||||
)}
|
||||
.disabled=${this._stateObj!.state === UNAVAILABLE}
|
||||
.unit=${DOMAIN_ATTRIBUTES_UNITS.cover.current_position}
|
||||
.locale=${this.hass.locale}
|
||||
.locale=${this._locale}
|
||||
></ha-control-slider>
|
||||
`;
|
||||
}
|
||||
@@ -120,7 +155,7 @@ class HuiCoverPositionCardFeature
|
||||
const { value } = ev.detail;
|
||||
if (typeof value !== "number" || isNaN(value)) return;
|
||||
|
||||
this.hass!.callService("cover", "set_cover_position", {
|
||||
this._api.callService("cover", "set_cover_position", {
|
||||
entity_id: this._stateObj!.entity_id,
|
||||
position: value,
|
||||
});
|
||||
|
||||
@@ -1,11 +1,19 @@
|
||||
import { consume } from "@lit/context";
|
||||
import { mdiArrowBottomLeft, mdiArrowTopRight, mdiStop } from "@mdi/js";
|
||||
import type { HassEntity } from "home-assistant-js-websocket";
|
||||
import { LitElement, html, nothing } from "lit";
|
||||
import { customElement, property, state } from "lit/decorators";
|
||||
import {
|
||||
consumeEntityState,
|
||||
consumeLocalize,
|
||||
} from "../../../common/decorators/consume-context-entry";
|
||||
import { computeDomain } from "../../../common/entity/compute_domain";
|
||||
import { supportsFeature } from "../../../common/entity/supports-feature";
|
||||
import type { LocalizeFunc } from "../../../common/translations/localize";
|
||||
import "../../../components/ha-control-button";
|
||||
import "../../../components/ha-control-button-group";
|
||||
import "../../../components/ha-svg-icon";
|
||||
import { apiContext } from "../../../data/context";
|
||||
import {
|
||||
CoverEntityFeature,
|
||||
canCloseTilt,
|
||||
@@ -13,7 +21,7 @@ import {
|
||||
canStopTilt,
|
||||
type CoverEntity,
|
||||
} from "../../../data/cover";
|
||||
import type { HomeAssistant } from "../../../types";
|
||||
import type { HomeAssistant, HomeAssistantApi } from "../../../types";
|
||||
import type { LovelaceCardFeature } from "../types";
|
||||
import { cardFeatureStyles } from "./common/card-feature-styles";
|
||||
import type {
|
||||
@@ -21,6 +29,15 @@ import type {
|
||||
LovelaceCardFeatureContext,
|
||||
} from "./types";
|
||||
|
||||
const supportsCoverTiltCardFeatureFromState = (stateObj: HassEntity) => {
|
||||
const domain = computeDomain(stateObj.entity_id);
|
||||
return (
|
||||
domain === "cover" &&
|
||||
(supportsFeature(stateObj, CoverEntityFeature.OPEN_TILT) ||
|
||||
supportsFeature(stateObj, CoverEntityFeature.CLOSE_TILT))
|
||||
);
|
||||
};
|
||||
|
||||
export const supportsCoverTiltCardFeature = (
|
||||
hass: HomeAssistant,
|
||||
context: LovelaceCardFeatureContext
|
||||
@@ -29,12 +46,7 @@ export const supportsCoverTiltCardFeature = (
|
||||
? hass.states[context.entity_id]
|
||||
: undefined;
|
||||
if (!stateObj) return false;
|
||||
const domain = computeDomain(stateObj.entity_id);
|
||||
return (
|
||||
domain === "cover" &&
|
||||
(supportsFeature(stateObj, CoverEntityFeature.OPEN_TILT) ||
|
||||
supportsFeature(stateObj, CoverEntityFeature.CLOSE_TILT))
|
||||
);
|
||||
return supportsCoverTiltCardFeatureFromState(stateObj);
|
||||
};
|
||||
|
||||
@customElement("hui-cover-tilt-card-feature")
|
||||
@@ -42,18 +54,21 @@ class HuiCoverTiltCardFeature
|
||||
extends LitElement
|
||||
implements LovelaceCardFeature
|
||||
{
|
||||
@property({ attribute: false }) public hass?: HomeAssistant;
|
||||
|
||||
@property({ attribute: false }) public context?: LovelaceCardFeatureContext;
|
||||
|
||||
@state() private _config?: CoverTiltCardFeatureConfig;
|
||||
@state()
|
||||
@consumeEntityState({ entityIdPath: ["context", "entity_id"] })
|
||||
private _stateObj?: CoverEntity;
|
||||
|
||||
private get _stateObj() {
|
||||
if (!this.hass || !this.context || !this.context.entity_id) {
|
||||
return undefined;
|
||||
}
|
||||
return this.hass.states[this.context.entity_id!] as CoverEntity | undefined;
|
||||
}
|
||||
@state()
|
||||
@consumeLocalize()
|
||||
private _localize!: LocalizeFunc;
|
||||
|
||||
@state()
|
||||
@consume({ context: apiContext, subscribe: true })
|
||||
private _api!: HomeAssistantApi;
|
||||
|
||||
@state() private _config?: CoverTiltCardFeatureConfig;
|
||||
|
||||
static getStubConfig(): CoverTiltCardFeatureConfig {
|
||||
return {
|
||||
@@ -70,21 +85,21 @@ class HuiCoverTiltCardFeature
|
||||
|
||||
private _onOpenTap(ev): void {
|
||||
ev.stopPropagation();
|
||||
this.hass!.callService("cover", "open_cover_tilt", {
|
||||
this._api.callService("cover", "open_cover_tilt", {
|
||||
entity_id: this._stateObj!.entity_id,
|
||||
});
|
||||
}
|
||||
|
||||
private _onCloseTap(ev): void {
|
||||
ev.stopPropagation();
|
||||
this.hass!.callService("cover", "close_cover_tilt", {
|
||||
this._api.callService("cover", "close_cover_tilt", {
|
||||
entity_id: this._stateObj!.entity_id,
|
||||
});
|
||||
}
|
||||
|
||||
private _onStopTap(ev): void {
|
||||
ev.stopPropagation();
|
||||
this.hass!.callService("cover", "stop_cover_tilt", {
|
||||
this._api.callService("cover", "stop_cover_tilt", {
|
||||
entity_id: this._stateObj!.entity_id,
|
||||
});
|
||||
}
|
||||
@@ -92,10 +107,9 @@ class HuiCoverTiltCardFeature
|
||||
protected render() {
|
||||
if (
|
||||
!this._config ||
|
||||
!this.hass ||
|
||||
!this.context ||
|
||||
!this._stateObj ||
|
||||
!supportsCoverTiltCardFeature(this.hass, this.context)
|
||||
!supportsCoverTiltCardFeatureFromState(this._stateObj)
|
||||
) {
|
||||
return nothing;
|
||||
}
|
||||
@@ -106,7 +120,7 @@ class HuiCoverTiltCardFeature
|
||||
supportsFeature(this._stateObj, CoverEntityFeature.OPEN_TILT)
|
||||
? html`
|
||||
<ha-control-button
|
||||
.label=${this.hass.localize("ui.card.cover.open_tilt_cover")}
|
||||
.label=${this._localize("ui.card.cover.open_tilt_cover")}
|
||||
@click=${this._onOpenTap}
|
||||
.disabled=${!canOpenTilt(this._stateObj)}
|
||||
>
|
||||
@@ -119,7 +133,7 @@ class HuiCoverTiltCardFeature
|
||||
supportsFeature(this._stateObj, CoverEntityFeature.STOP_TILT)
|
||||
? html`
|
||||
<ha-control-button
|
||||
.label=${this.hass.localize("ui.card.cover.stop_cover")}
|
||||
.label=${this._localize("ui.card.cover.stop_cover")}
|
||||
@click=${this._onStopTap}
|
||||
.disabled=${!canStopTilt(this._stateObj)}
|
||||
>
|
||||
@@ -132,7 +146,7 @@ class HuiCoverTiltCardFeature
|
||||
supportsFeature(this._stateObj, CoverEntityFeature.CLOSE_TILT)
|
||||
? html`
|
||||
<ha-control-button
|
||||
.label=${this.hass.localize("ui.card.cover.close_tilt_cover")}
|
||||
.label=${this._localize("ui.card.cover.close_tilt_cover")}
|
||||
@click=${this._onCloseTap}
|
||||
.disabled=${!canCloseTilt(this._stateObj)}
|
||||
>
|
||||
|
||||
@@ -1,17 +1,35 @@
|
||||
import { consume } from "@lit/context";
|
||||
import type { HassEntity } from "home-assistant-js-websocket";
|
||||
import { css, html, LitElement, nothing } from "lit";
|
||||
import { customElement, property, state } from "lit/decorators";
|
||||
import { styleMap } from "lit/directives/style-map";
|
||||
import { computeCssColor } from "../../../common/color/compute-color";
|
||||
import {
|
||||
consumeEntityState,
|
||||
consumeLocalize,
|
||||
} from "../../../common/decorators/consume-context-entry";
|
||||
import { transform } from "../../../common/decorators/transform";
|
||||
import type { HASSDomEvent } from "../../../common/dom/fire_event";
|
||||
import { computeAttributeNameDisplay } from "../../../common/entity/compute_attribute_display";
|
||||
import { computeDomain } from "../../../common/entity/compute_domain";
|
||||
import { stateColorCss } from "../../../common/entity/state_color";
|
||||
import type { LocalizeFunc } from "../../../common/translations/localize";
|
||||
import type { CoverEntity } from "../../../data/cover";
|
||||
import { coverSupportsTiltPosition } from "../../../data/cover";
|
||||
import {
|
||||
apiContext,
|
||||
entitiesContext,
|
||||
internationalizationContext,
|
||||
} from "../../../data/context";
|
||||
import { UNAVAILABLE } from "../../../data/entity/entity";
|
||||
import { DOMAIN_ATTRIBUTES_UNITS } from "../../../data/entity/entity_attributes";
|
||||
import type { FrontendLocaleData } from "../../../data/translation";
|
||||
import { generateTiltSliderTrackBackgroundGradient } from "../../../state-control/cover/ha-state-control-cover-tilt-position";
|
||||
import type { HomeAssistant } from "../../../types";
|
||||
import type {
|
||||
HomeAssistant,
|
||||
HomeAssistantApi,
|
||||
HomeAssistantInternationalization,
|
||||
} from "../../../types";
|
||||
import type { LovelaceCardFeature } from "../types";
|
||||
import { cardFeatureStyles } from "./common/card-feature-styles";
|
||||
import type {
|
||||
@@ -21,6 +39,15 @@ import type {
|
||||
|
||||
const GRADIENT = generateTiltSliderTrackBackgroundGradient();
|
||||
|
||||
const supportsCoverTiltPositionCardFeatureFromState = (
|
||||
stateObj: HassEntity
|
||||
) => {
|
||||
const domain = computeDomain(stateObj.entity_id);
|
||||
return (
|
||||
domain === "cover" && coverSupportsTiltPosition(stateObj as CoverEntity)
|
||||
);
|
||||
};
|
||||
|
||||
export const supportsCoverTiltPositionCardFeature = (
|
||||
hass: HomeAssistant,
|
||||
context: LovelaceCardFeatureContext
|
||||
@@ -29,10 +56,7 @@ export const supportsCoverTiltPositionCardFeature = (
|
||||
? hass.states[context.entity_id]
|
||||
: undefined;
|
||||
if (!stateObj) return false;
|
||||
const domain = computeDomain(stateObj.entity_id);
|
||||
return (
|
||||
domain === "cover" && coverSupportsTiltPosition(stateObj as CoverEntity)
|
||||
);
|
||||
return supportsCoverTiltPositionCardFeatureFromState(stateObj);
|
||||
};
|
||||
|
||||
@customElement("hui-cover-tilt-position-card-feature")
|
||||
@@ -40,20 +64,34 @@ class HuiCoverTiltPositionCardFeature
|
||||
extends LitElement
|
||||
implements LovelaceCardFeature
|
||||
{
|
||||
@property({ attribute: false }) public hass?: HomeAssistant;
|
||||
|
||||
@property({ attribute: false }) public context?: LovelaceCardFeatureContext;
|
||||
|
||||
@property({ attribute: false }) public color?: string;
|
||||
|
||||
@state() private _config?: CoverTiltPositionCardFeatureConfig;
|
||||
@state()
|
||||
@consumeEntityState({ entityIdPath: ["context", "entity_id"] })
|
||||
private _stateObj?: CoverEntity;
|
||||
|
||||
private get _stateObj() {
|
||||
if (!this.hass || !this.context || !this.context.entity_id) {
|
||||
return undefined;
|
||||
}
|
||||
return this.hass.states[this.context.entity_id!] as CoverEntity | undefined;
|
||||
}
|
||||
@state()
|
||||
@consumeLocalize()
|
||||
private _localize!: LocalizeFunc;
|
||||
|
||||
@state()
|
||||
@consume({ context: apiContext, subscribe: true })
|
||||
private _api!: HomeAssistantApi;
|
||||
|
||||
@state()
|
||||
@consume({ context: entitiesContext, subscribe: true })
|
||||
private _entities!: HomeAssistant["entities"];
|
||||
|
||||
@state()
|
||||
@consume({ context: internationalizationContext, subscribe: true })
|
||||
@transform<HomeAssistantInternationalization, FrontendLocaleData>({
|
||||
transformer: ({ locale }) => locale,
|
||||
})
|
||||
private _locale?: FrontendLocaleData;
|
||||
|
||||
@state() private _config?: CoverTiltPositionCardFeatureConfig;
|
||||
|
||||
static getStubConfig(): CoverTiltPositionCardFeatureConfig {
|
||||
return {
|
||||
@@ -71,10 +109,9 @@ class HuiCoverTiltPositionCardFeature
|
||||
protected render() {
|
||||
if (
|
||||
!this._config ||
|
||||
!this.hass ||
|
||||
!this.context ||
|
||||
!this._stateObj ||
|
||||
!supportsCoverTiltPositionCardFeature(this.hass, this.context)
|
||||
!supportsCoverTiltPositionCardFeatureFromState(this._stateObj)
|
||||
) {
|
||||
return nothing;
|
||||
}
|
||||
@@ -105,14 +142,14 @@ class HuiCoverTiltPositionCardFeature
|
||||
inverted
|
||||
@value-changed=${this._valueChanged}
|
||||
.label=${computeAttributeNameDisplay(
|
||||
this.hass.localize,
|
||||
this._localize,
|
||||
this._stateObj,
|
||||
this.hass.entities,
|
||||
this._entities,
|
||||
"current_tilt_position"
|
||||
)}
|
||||
.disabled=${this._stateObj!.state === UNAVAILABLE}
|
||||
.unit=${DOMAIN_ATTRIBUTES_UNITS.cover.current_tilt_position}
|
||||
.locale=${this.hass.locale}
|
||||
.locale=${this._locale}
|
||||
>
|
||||
<div slot="background" class="gradient"></div
|
||||
></ha-control-slider>
|
||||
@@ -123,7 +160,7 @@ class HuiCoverTiltPositionCardFeature
|
||||
const { value } = ev.detail;
|
||||
if (typeof value !== "number" || isNaN(value)) return;
|
||||
|
||||
this.hass!.callService("cover", "set_cover_tilt_position", {
|
||||
this._api.callService("cover", "set_cover_tilt_position", {
|
||||
entity_id: this._stateObj!.entity_id,
|
||||
tilt_position: value,
|
||||
});
|
||||
|
||||
@@ -1,15 +1,29 @@
|
||||
import { consume } from "@lit/context";
|
||||
import type { HassEntity } from "home-assistant-js-websocket";
|
||||
import { html, LitElement, nothing } from "lit";
|
||||
import { customElement, property, state } from "lit/decorators";
|
||||
import { firstWeekdayIndex } from "../../../common/datetime/first_weekday";
|
||||
import {
|
||||
consumeEntityState,
|
||||
consumeLocalize,
|
||||
} from "../../../common/decorators/consume-context-entry";
|
||||
import { transform } from "../../../common/decorators/transform";
|
||||
import {
|
||||
fireEvent,
|
||||
type HASSDomCurrentTargetEvent,
|
||||
} from "../../../common/dom/fire_event";
|
||||
import { computeDomain } from "../../../common/entity/compute_domain";
|
||||
import type { LocalizeFunc } from "../../../common/translations/localize";
|
||||
import "../../../components/ha-control-button";
|
||||
import "../../../components/ha-control-button-group";
|
||||
import "../../../components/ha-control-slider";
|
||||
import type { HomeAssistant } from "../../../types";
|
||||
import { apiContext, internationalizationContext } from "../../../data/context";
|
||||
import type { FrontendLocaleData } from "../../../data/translation";
|
||||
import type {
|
||||
HomeAssistant,
|
||||
HomeAssistantApi,
|
||||
HomeAssistantInternationalization,
|
||||
} from "../../../types";
|
||||
import type { LovelaceCardFeature } from "../types";
|
||||
import { cardFeatureStyles } from "./common/card-feature-styles";
|
||||
import type {
|
||||
@@ -20,6 +34,14 @@ import type {
|
||||
const loadDatePickerDialog = () =>
|
||||
import("../../../components/date-picker/ha-dialog-date-picker");
|
||||
|
||||
const supportsDateSetCardFeatureFromState = (stateObj: HassEntity) => {
|
||||
const domain = computeDomain(stateObj.entity_id);
|
||||
return (
|
||||
(domain === "input_datetime" && stateObj.attributes.has_date) ||
|
||||
["datetime", "date"].includes(domain)
|
||||
);
|
||||
};
|
||||
|
||||
export const supportsDateSetCardFeature = (
|
||||
hass: HomeAssistant,
|
||||
context: LovelaceCardFeatureContext
|
||||
@@ -28,32 +50,38 @@ export const supportsDateSetCardFeature = (
|
||||
? hass.states[context.entity_id]
|
||||
: undefined;
|
||||
if (!stateObj) return false;
|
||||
const domain = computeDomain(stateObj.entity_id);
|
||||
return (
|
||||
(domain === "input_datetime" && stateObj.attributes.has_date) ||
|
||||
["datetime", "date"].includes(domain)
|
||||
);
|
||||
return supportsDateSetCardFeatureFromState(stateObj);
|
||||
};
|
||||
|
||||
@customElement("hui-date-set-card-feature")
|
||||
class HuiDateSetCardFeature extends LitElement implements LovelaceCardFeature {
|
||||
@property({ attribute: false }) public hass?: HomeAssistant;
|
||||
|
||||
@property({ attribute: false }) public context?: LovelaceCardFeatureContext;
|
||||
|
||||
@property({ attribute: false }) public color?: string;
|
||||
|
||||
@state()
|
||||
@consumeEntityState({ entityIdPath: ["context", "entity_id"] })
|
||||
private _stateObj?: HassEntity;
|
||||
|
||||
@state()
|
||||
@consumeLocalize()
|
||||
private _localize!: LocalizeFunc;
|
||||
|
||||
@state()
|
||||
@consume({ context: internationalizationContext, subscribe: true })
|
||||
@transform<HomeAssistantInternationalization, FrontendLocaleData>({
|
||||
transformer: ({ locale }) => locale,
|
||||
})
|
||||
private _locale?: FrontendLocaleData;
|
||||
|
||||
@state()
|
||||
@consume({ context: apiContext, subscribe: true })
|
||||
private _api!: HomeAssistantApi;
|
||||
|
||||
@state() private _config?: DateSetCardFeatureConfig;
|
||||
|
||||
private get _stateObj() {
|
||||
if (!this.hass || !this.context || !this.context.entity_id) {
|
||||
return undefined;
|
||||
}
|
||||
return this.hass.states[this.context.entity_id!] ?? undefined;
|
||||
}
|
||||
|
||||
private _pressButton(ev: HASSDomCurrentTargetEvent<HTMLElement>) {
|
||||
if (!this.hass || !this._stateObj) return;
|
||||
if (!this._stateObj || !this._locale) return;
|
||||
|
||||
fireEvent(this, "show-dialog", {
|
||||
dialogTag: "ha-dialog-date-picker",
|
||||
@@ -63,14 +91,14 @@ class HuiDateSetCardFeature extends LitElement implements LovelaceCardFeature {
|
||||
min: "1970-01-01",
|
||||
value: this._stateObj.state,
|
||||
onChange: (value) => this._dateChanged(value),
|
||||
locale: this.hass.locale.language,
|
||||
firstWeekday: firstWeekdayIndex(this.hass.locale),
|
||||
locale: this._locale.language,
|
||||
firstWeekday: firstWeekdayIndex(this._locale),
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
private _dateChanged(value: string | undefined) {
|
||||
if (!this.hass || !this._stateObj || !value) return;
|
||||
if (!this._stateObj || !value) return;
|
||||
|
||||
const domain = computeDomain(this._stateObj.entity_id);
|
||||
const service = domain === "input_datetime" ? "set_datetime" : "set_value";
|
||||
@@ -85,12 +113,12 @@ class HuiDateSetCardFeature extends LitElement implements LovelaceCardFeature {
|
||||
selectedDate.getDate()
|
||||
);
|
||||
|
||||
this.hass.callService(domain, service, {
|
||||
this._api.callService(domain, service, {
|
||||
entity_id: this._stateObj.entity_id,
|
||||
datetime: dateObj.toISOString(),
|
||||
});
|
||||
} else {
|
||||
this.hass.callService(domain, service, {
|
||||
this._api.callService(domain, service, {
|
||||
entity_id: this._stateObj.entity_id,
|
||||
date: value,
|
||||
});
|
||||
@@ -113,10 +141,10 @@ class HuiDateSetCardFeature extends LitElement implements LovelaceCardFeature {
|
||||
protected render() {
|
||||
if (
|
||||
!this._config ||
|
||||
!this.hass ||
|
||||
!this.context ||
|
||||
!this._stateObj ||
|
||||
!supportsDateSetCardFeature(this.hass, this.context)
|
||||
!this._locale ||
|
||||
!supportsDateSetCardFeatureFromState(this._stateObj)
|
||||
) {
|
||||
return nothing;
|
||||
}
|
||||
@@ -128,7 +156,7 @@ class HuiDateSetCardFeature extends LitElement implements LovelaceCardFeature {
|
||||
class="press-button"
|
||||
@click=${this._pressButton}
|
||||
>
|
||||
${this.hass.localize("ui.card.date.set_date")}
|
||||
${this._localize("ui.card.date.set_date")}
|
||||
</ha-control-button>
|
||||
</ha-control-button-group>
|
||||
`;
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import type { HassEntity } from "home-assistant-js-websocket";
|
||||
import { customElement } from "lit/decorators";
|
||||
import { computeDomain } from "../../../common/entity/compute_domain";
|
||||
import { supportsFeature } from "../../../common/entity/supports-feature";
|
||||
@@ -16,6 +17,13 @@ import type {
|
||||
|
||||
const FAN_DIRECTIONS: FanDirection[] = ["forward", "reverse"];
|
||||
|
||||
const supportsFanDirectionCardFeatureFromState = (stateObj: HassEntity) => {
|
||||
const domain = computeDomain(stateObj.entity_id);
|
||||
return (
|
||||
domain === "fan" && supportsFeature(stateObj, FanEntityFeature.DIRECTION)
|
||||
);
|
||||
};
|
||||
|
||||
export const supportsFanDirectionCardFeature = (
|
||||
hass: HomeAssistant,
|
||||
context: LovelaceCardFeatureContext
|
||||
@@ -24,10 +32,7 @@ export const supportsFanDirectionCardFeature = (
|
||||
? hass.states[context.entity_id]
|
||||
: undefined;
|
||||
if (!stateObj) return false;
|
||||
const domain = computeDomain(stateObj.entity_id);
|
||||
return (
|
||||
domain === "fan" && supportsFeature(stateObj, FanEntityFeature.DIRECTION)
|
||||
);
|
||||
return supportsFanDirectionCardFeatureFromState(stateObj);
|
||||
};
|
||||
|
||||
@customElement("hui-fan-direction-card-feature")
|
||||
@@ -52,21 +57,19 @@ class HuiFanDirectionCardFeature
|
||||
}
|
||||
|
||||
protected _getOptions(): HuiModeSelectOption[] {
|
||||
if (!this.hass) {
|
||||
if (!this._stateObj) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return FAN_DIRECTIONS.map((direction) => ({
|
||||
value: direction,
|
||||
label: this.hass!.localize(`ui.card.fan.${direction}`),
|
||||
label: this._localize(`ui.card.fan.${direction}`),
|
||||
}));
|
||||
}
|
||||
|
||||
protected _isSupported(): boolean {
|
||||
return !!(
|
||||
this.hass &&
|
||||
this.context &&
|
||||
supportsFanDirectionCardFeature(this.hass, this.context)
|
||||
this._stateObj && supportsFanDirectionCardFeatureFromState(this._stateObj)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,18 +1,26 @@
|
||||
import { consume } from "@lit/context";
|
||||
import { mdiArrowOscillating, mdiArrowOscillatingOff } from "@mdi/js";
|
||||
import type { HassEntity } from "home-assistant-js-websocket";
|
||||
import type { PropertyValues, TemplateResult } from "lit";
|
||||
import { LitElement, html } from "lit";
|
||||
import { customElement, property, state } from "lit/decorators";
|
||||
import { styleMap } from "lit/directives/style-map";
|
||||
import {
|
||||
consumeEntityState,
|
||||
consumeLocalize,
|
||||
} from "../../../common/decorators/consume-context-entry";
|
||||
import { computeDomain } from "../../../common/entity/compute_domain";
|
||||
import type { HASSDomEvent } from "../../../common/dom/fire_event";
|
||||
import { stateColorCss } from "../../../common/entity/state_color";
|
||||
import { supportsFeature } from "../../../common/entity/supports-feature";
|
||||
import type { LocalizeFunc } from "../../../common/translations/localize";
|
||||
import "../../../components/ha-control-select";
|
||||
import type { ControlSelectOption } from "../../../components/ha-control-select";
|
||||
import { apiContext } from "../../../data/context";
|
||||
import { UNAVAILABLE } from "../../../data/entity/entity";
|
||||
import type { FanEntity } from "../../../data/fan";
|
||||
import { FanEntityFeature } from "../../../data/fan";
|
||||
import type { HomeAssistant } from "../../../types";
|
||||
import type { HomeAssistant, HomeAssistantApi } from "../../../types";
|
||||
import type { LovelaceCardFeature } from "../types";
|
||||
import { cardFeatureStyles } from "./common/card-feature-styles";
|
||||
import type {
|
||||
@@ -20,6 +28,13 @@ import type {
|
||||
LovelaceCardFeatureContext,
|
||||
} from "./types";
|
||||
|
||||
const supportsFanOscillateCardFeatureFromState = (stateObj: HassEntity) => {
|
||||
const domain = computeDomain(stateObj.entity_id);
|
||||
return (
|
||||
domain === "fan" && supportsFeature(stateObj, FanEntityFeature.OSCILLATE)
|
||||
);
|
||||
};
|
||||
|
||||
export const supportsFanOscilatteCardFeature = (
|
||||
hass: HomeAssistant,
|
||||
context: LovelaceCardFeatureContext
|
||||
@@ -28,10 +43,7 @@ export const supportsFanOscilatteCardFeature = (
|
||||
? hass.states[context.entity_id]
|
||||
: undefined;
|
||||
if (!stateObj) return false;
|
||||
const domain = computeDomain(stateObj.entity_id);
|
||||
return (
|
||||
domain === "fan" && supportsFeature(stateObj, FanEntityFeature.OSCILLATE)
|
||||
);
|
||||
return supportsFanOscillateCardFeatureFromState(stateObj);
|
||||
};
|
||||
|
||||
@customElement("hui-fan-oscillate-card-feature")
|
||||
@@ -39,21 +51,24 @@ class HuiFanOscillateCardFeature
|
||||
extends LitElement
|
||||
implements LovelaceCardFeature
|
||||
{
|
||||
@property({ attribute: false }) public hass?: HomeAssistant;
|
||||
|
||||
@property({ attribute: false }) public context?: LovelaceCardFeatureContext;
|
||||
|
||||
@state()
|
||||
@consumeEntityState({ entityIdPath: ["context", "entity_id"] })
|
||||
private _stateObj?: FanEntity;
|
||||
|
||||
@state()
|
||||
@consumeLocalize()
|
||||
private _localize!: LocalizeFunc;
|
||||
|
||||
@state()
|
||||
@consume({ context: apiContext, subscribe: true })
|
||||
private _api!: HomeAssistantApi;
|
||||
|
||||
@state() private _config?: FanOscillateCardFeatureConfig;
|
||||
|
||||
@state() _oscillate?: boolean;
|
||||
|
||||
private get _stateObj() {
|
||||
if (!this.hass || !this.context || !this.context.entity_id) {
|
||||
return undefined;
|
||||
}
|
||||
return this.hass.states[this.context.entity_id!] as FanEntity | undefined;
|
||||
}
|
||||
|
||||
static getStubConfig(): FanOscillateCardFeatureConfig {
|
||||
return {
|
||||
type: "fan-oscillate",
|
||||
@@ -67,16 +82,9 @@ class HuiFanOscillateCardFeature
|
||||
this._config = config;
|
||||
}
|
||||
|
||||
protected willUpdate(changedProp: PropertyValues<this>): void {
|
||||
if (
|
||||
(changedProp.has("hass") || changedProp.has("context")) &&
|
||||
this._stateObj
|
||||
) {
|
||||
const oldHass = changedProp.get("hass") as HomeAssistant | undefined;
|
||||
const oldStateObj = oldHass?.states[this.context!.entity_id!];
|
||||
if (oldStateObj !== this._stateObj) {
|
||||
this._oscillate = this._stateObj.attributes.oscillating;
|
||||
}
|
||||
protected willUpdate(changedProp: PropertyValues): void {
|
||||
if (changedProp.has("_stateObj") && this._stateObj) {
|
||||
this._oscillate = this._stateObj.attributes.oscillating;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -98,7 +106,7 @@ class HuiFanOscillateCardFeature
|
||||
}
|
||||
|
||||
private async _updateOscillate(oscillate: boolean) {
|
||||
await this.hass!.callService("fan", "oscillate", {
|
||||
await this._api.callService("fan", "oscillate", {
|
||||
entity_id: this._stateObj!.entity_id,
|
||||
oscillating: oscillate,
|
||||
});
|
||||
@@ -107,10 +115,9 @@ class HuiFanOscillateCardFeature
|
||||
protected render(): TemplateResult | null {
|
||||
if (
|
||||
!this._config ||
|
||||
!this.hass ||
|
||||
!this.context ||
|
||||
!this._stateObj ||
|
||||
!supportsFanOscilatteCardFeature(this.hass, this.context)
|
||||
!supportsFanOscillateCardFeatureFromState(this._stateObj)
|
||||
) {
|
||||
return null;
|
||||
}
|
||||
@@ -120,7 +127,7 @@ class HuiFanOscillateCardFeature
|
||||
const yesNo = ["no", "yes"] as const;
|
||||
const options = yesNo.map<ControlSelectOption>((oscillating) => ({
|
||||
value: oscillating,
|
||||
label: this.hass!.localize(`ui.common.${oscillating}`),
|
||||
label: this._localize(`ui.common.${oscillating}`),
|
||||
path:
|
||||
oscillating === "yes" ? mdiArrowOscillating : mdiArrowOscillatingOff,
|
||||
}));
|
||||
@@ -131,7 +138,7 @@ class HuiFanOscillateCardFeature
|
||||
.value=${this._oscillate ? "yes" : "no"}
|
||||
@value-changed=${this._valueChanged}
|
||||
hide-option-label
|
||||
.label=${this.hass.localize("ui.card.fan.oscillate")}
|
||||
.label=${this._localize("ui.card.fan.oscillate")}
|
||||
style=${styleMap({
|
||||
"--control-select-color": color,
|
||||
})}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { mdiTuneVariant } from "@mdi/js";
|
||||
import type { HassEntity } from "home-assistant-js-websocket";
|
||||
import { customElement } from "lit/decorators";
|
||||
import { computeDomain } from "../../../common/entity/compute_domain";
|
||||
import { supportsFeature } from "../../../common/entity/supports-feature";
|
||||
@@ -12,6 +13,13 @@ import type {
|
||||
LovelaceCardFeatureContext,
|
||||
} from "./types";
|
||||
|
||||
const supportsFanPresetModesCardFeatureFromState = (stateObj: HassEntity) => {
|
||||
const domain = computeDomain(stateObj.entity_id);
|
||||
return (
|
||||
domain === "fan" && supportsFeature(stateObj, FanEntityFeature.PRESET_MODE)
|
||||
);
|
||||
};
|
||||
|
||||
export const supportsFanPresetModesCardFeature = (
|
||||
hass: HomeAssistant,
|
||||
context: LovelaceCardFeatureContext
|
||||
@@ -20,10 +28,7 @@ export const supportsFanPresetModesCardFeature = (
|
||||
? hass.states[context.entity_id]
|
||||
: undefined;
|
||||
if (!stateObj) return false;
|
||||
const domain = computeDomain(stateObj.entity_id);
|
||||
return (
|
||||
domain === "fan" && supportsFeature(stateObj, FanEntityFeature.PRESET_MODE)
|
||||
);
|
||||
return supportsFanPresetModesCardFeatureFromState(stateObj);
|
||||
};
|
||||
|
||||
@customElement("hui-fan-preset-modes-card-feature")
|
||||
@@ -62,9 +67,8 @@ class HuiFanPresetModesCardFeature
|
||||
|
||||
protected _isSupported(): boolean {
|
||||
return !!(
|
||||
this.hass &&
|
||||
this.context &&
|
||||
supportsFanPresetModesCardFeature(this.hass, this.context)
|
||||
this._stateObj &&
|
||||
supportsFanPresetModesCardFeatureFromState(this._stateObj)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,13 +1,27 @@
|
||||
import { consume } from "@lit/context";
|
||||
import type { HassEntity } from "home-assistant-js-websocket";
|
||||
import { css, html, LitElement, nothing } from "lit";
|
||||
import { customElement, property, state } from "lit/decorators";
|
||||
import { computeAttributeNameDisplay } from "../../../common/entity/compute_attribute_display";
|
||||
import {
|
||||
consumeEntityState,
|
||||
consumeLocalize,
|
||||
} from "../../../common/decorators/consume-context-entry";
|
||||
import { transform } from "../../../common/decorators/transform";
|
||||
import type { HASSDomEvent } from "../../../common/dom/fire_event";
|
||||
import { computeDomain } from "../../../common/entity/compute_domain";
|
||||
import { stateActive } from "../../../common/entity/state_active";
|
||||
import { supportsFeature } from "../../../common/entity/supports-feature";
|
||||
import type { LocalizeFunc } from "../../../common/translations/localize";
|
||||
import "../../../components/ha-control-select";
|
||||
import type { ControlSelectOption } from "../../../components/ha-control-select";
|
||||
import "../../../components/ha-control-slider";
|
||||
import {
|
||||
apiContext,
|
||||
entitiesContext,
|
||||
formattersContext,
|
||||
internationalizationContext,
|
||||
} from "../../../data/context";
|
||||
import { UNAVAILABLE } from "../../../data/entity/entity";
|
||||
import { DOMAIN_ATTRIBUTES_UNITS } from "../../../data/entity/entity_attributes";
|
||||
import type { FanEntity, FanSpeed } from "../../../data/fan";
|
||||
@@ -20,7 +34,13 @@ import {
|
||||
fanPercentageToSpeed,
|
||||
fanSpeedToPercentage,
|
||||
} from "../../../data/fan";
|
||||
import type { HomeAssistant } from "../../../types";
|
||||
import type { FrontendLocaleData } from "../../../data/translation";
|
||||
import type {
|
||||
HomeAssistant,
|
||||
HomeAssistantApi,
|
||||
HomeAssistantFormatters,
|
||||
HomeAssistantInternationalization,
|
||||
} from "../../../types";
|
||||
import type { LovelaceCardFeature } from "../types";
|
||||
import { cardFeatureStyles } from "./common/card-feature-styles";
|
||||
import type {
|
||||
@@ -28,6 +48,13 @@ import type {
|
||||
LovelaceCardFeatureContext,
|
||||
} from "./types";
|
||||
|
||||
const supportsFanSpeedCardFeatureFromState = (stateObj: HassEntity) => {
|
||||
const domain = computeDomain(stateObj.entity_id);
|
||||
return (
|
||||
domain === "fan" && supportsFeature(stateObj, FanEntityFeature.SET_SPEED)
|
||||
);
|
||||
};
|
||||
|
||||
export const supportsFanSpeedCardFeature = (
|
||||
hass: HomeAssistant,
|
||||
context: LovelaceCardFeatureContext
|
||||
@@ -36,26 +63,41 @@ export const supportsFanSpeedCardFeature = (
|
||||
? hass.states[context.entity_id]
|
||||
: undefined;
|
||||
if (!stateObj) return false;
|
||||
const domain = computeDomain(stateObj.entity_id);
|
||||
return (
|
||||
domain === "fan" && supportsFeature(stateObj, FanEntityFeature.SET_SPEED)
|
||||
);
|
||||
return supportsFanSpeedCardFeatureFromState(stateObj);
|
||||
};
|
||||
|
||||
@customElement("hui-fan-speed-card-feature")
|
||||
class HuiFanSpeedCardFeature extends LitElement implements LovelaceCardFeature {
|
||||
@property({ attribute: false }) public hass?: HomeAssistant;
|
||||
|
||||
@property({ attribute: false }) public context?: LovelaceCardFeatureContext;
|
||||
|
||||
@state() private _config?: FanSpeedCardFeatureConfig;
|
||||
@state()
|
||||
@consumeEntityState({ entityIdPath: ["context", "entity_id"] })
|
||||
private _stateObj?: FanEntity;
|
||||
|
||||
private get _stateObj() {
|
||||
if (!this.hass || !this.context || !this.context.entity_id) {
|
||||
return undefined;
|
||||
}
|
||||
return this.hass.states[this.context.entity_id!] as FanEntity | undefined;
|
||||
}
|
||||
@state()
|
||||
@consumeLocalize()
|
||||
private _localize!: LocalizeFunc;
|
||||
|
||||
@state()
|
||||
@consume({ context: apiContext, subscribe: true })
|
||||
private _api!: HomeAssistantApi;
|
||||
|
||||
@state()
|
||||
@consume({ context: formattersContext, subscribe: true })
|
||||
private _formatters!: HomeAssistantFormatters;
|
||||
|
||||
@state()
|
||||
@consume({ context: entitiesContext, subscribe: true })
|
||||
private _entities!: HomeAssistant["entities"];
|
||||
|
||||
@state()
|
||||
@consume({ context: internationalizationContext, subscribe: true })
|
||||
@transform<HomeAssistantInternationalization, FrontendLocaleData>({
|
||||
transformer: ({ locale }) => locale,
|
||||
})
|
||||
private _locale?: FrontendLocaleData;
|
||||
|
||||
@state() private _config?: FanSpeedCardFeatureConfig;
|
||||
|
||||
static getStubConfig(): FanSpeedCardFeatureConfig {
|
||||
return {
|
||||
@@ -72,18 +114,17 @@ class HuiFanSpeedCardFeature extends LitElement implements LovelaceCardFeature {
|
||||
|
||||
private _localizeSpeed(speed: FanSpeed) {
|
||||
if (speed === "on" || speed === "off") {
|
||||
return this.hass!.formatEntityState(this._stateObj!, speed);
|
||||
return this._formatters.formatEntityState(this._stateObj!, speed);
|
||||
}
|
||||
return this.hass!.localize(`ui.card.fan.speed.${speed}`) || speed;
|
||||
return this._localize(`ui.card.fan.speed.${speed}`) || speed;
|
||||
}
|
||||
|
||||
protected render() {
|
||||
if (
|
||||
!this._config ||
|
||||
!this.hass ||
|
||||
!this.context ||
|
||||
!this._stateObj ||
|
||||
!supportsFanSpeedCardFeature(this.hass, this.context)
|
||||
!supportsFanSpeedCardFeatureFromState(this._stateObj)
|
||||
) {
|
||||
return nothing;
|
||||
}
|
||||
@@ -112,9 +153,9 @@ class HuiFanSpeedCardFeature extends LitElement implements LovelaceCardFeature {
|
||||
@value-changed=${this._speedValueChanged}
|
||||
hide-option-label
|
||||
.label=${computeAttributeNameDisplay(
|
||||
this.hass.localize,
|
||||
this._localize,
|
||||
this._stateObj,
|
||||
this.hass.entities,
|
||||
this._entities,
|
||||
"percentage"
|
||||
)}
|
||||
.disabled=${this._stateObj!.state === UNAVAILABLE}
|
||||
@@ -133,14 +174,14 @@ class HuiFanSpeedCardFeature extends LitElement implements LovelaceCardFeature {
|
||||
.step=${this._stateObj.attributes.percentage_step ?? 1}
|
||||
@value-changed=${this._valueChanged}
|
||||
.label=${computeAttributeNameDisplay(
|
||||
this.hass.localize,
|
||||
this._localize,
|
||||
this._stateObj,
|
||||
this.hass.entities,
|
||||
this._entities,
|
||||
"percentage"
|
||||
)}
|
||||
.disabled=${this._stateObj!.state === UNAVAILABLE}
|
||||
.unit=${DOMAIN_ATTRIBUTES_UNITS.fan.percentage}
|
||||
.locale=${this.hass.locale}
|
||||
.locale=${this._locale}
|
||||
></ha-control-slider>
|
||||
`;
|
||||
}
|
||||
@@ -150,7 +191,7 @@ class HuiFanSpeedCardFeature extends LitElement implements LovelaceCardFeature {
|
||||
|
||||
const percentage = fanSpeedToPercentage(this._stateObj!, speed);
|
||||
|
||||
this.hass!.callService("fan", "set_percentage", {
|
||||
this._api.callService("fan", "set_percentage", {
|
||||
entity_id: this._stateObj!.entity_id,
|
||||
percentage: percentage,
|
||||
});
|
||||
@@ -160,7 +201,7 @@ class HuiFanSpeedCardFeature extends LitElement implements LovelaceCardFeature {
|
||||
const { value } = ev.detail;
|
||||
if (typeof value !== "number" || isNaN(value)) return;
|
||||
|
||||
this.hass!.callService("fan", "set_percentage", {
|
||||
this._api.callService("fan", "set_percentage", {
|
||||
entity_id: this._stateObj!.entity_id,
|
||||
percentage: value,
|
||||
});
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { mdiTuneVariant } from "@mdi/js";
|
||||
import type { HassEntity } from "home-assistant-js-websocket";
|
||||
import { customElement } from "lit/decorators";
|
||||
import { computeDomain } from "../../../common/entity/compute_domain";
|
||||
import { supportsFeature } from "../../../common/entity/supports-feature";
|
||||
@@ -12,6 +13,14 @@ import type {
|
||||
LovelaceCardFeatureContext,
|
||||
} from "./types";
|
||||
|
||||
const supportsHumidifierModesCardFeatureFromState = (stateObj: HassEntity) => {
|
||||
const domain = computeDomain(stateObj.entity_id);
|
||||
return (
|
||||
domain === "humidifier" &&
|
||||
supportsFeature(stateObj, HumidifierEntityFeature.MODES)
|
||||
);
|
||||
};
|
||||
|
||||
export const supportsHumidifierModesCardFeature = (
|
||||
hass: HomeAssistant,
|
||||
context: LovelaceCardFeatureContext
|
||||
@@ -20,11 +29,7 @@ export const supportsHumidifierModesCardFeature = (
|
||||
? hass.states[context.entity_id]
|
||||
: undefined;
|
||||
if (!stateObj) return false;
|
||||
const domain = computeDomain(stateObj.entity_id);
|
||||
return (
|
||||
domain === "humidifier" &&
|
||||
supportsFeature(stateObj, HumidifierEntityFeature.MODES)
|
||||
);
|
||||
return supportsHumidifierModesCardFeatureFromState(stateObj);
|
||||
};
|
||||
|
||||
@customElement("hui-humidifier-modes-card-feature")
|
||||
@@ -63,9 +68,8 @@ class HuiHumidifierModesCardFeature
|
||||
|
||||
protected _isSupported(): boolean {
|
||||
return !!(
|
||||
this.hass &&
|
||||
this.context &&
|
||||
supportsHumidifierModesCardFeature(this.hass, this.context)
|
||||
this._stateObj &&
|
||||
supportsHumidifierModesCardFeatureFromState(this._stateObj)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,19 +1,31 @@
|
||||
import { consume } from "@lit/context";
|
||||
import { mdiPower, mdiWaterPercent } from "@mdi/js";
|
||||
import type { HassEntity } from "home-assistant-js-websocket";
|
||||
import type { PropertyValues, TemplateResult } from "lit";
|
||||
import { LitElement, html } from "lit";
|
||||
import { customElement, property, state } from "lit/decorators";
|
||||
import { styleMap } from "lit/directives/style-map";
|
||||
import {
|
||||
consumeEntityState,
|
||||
consumeLocalize,
|
||||
} from "../../../common/decorators/consume-context-entry";
|
||||
import { computeDomain } from "../../../common/entity/compute_domain";
|
||||
import type { HASSDomEvent } from "../../../common/dom/fire_event";
|
||||
import { stateColorCss } from "../../../common/entity/state_color";
|
||||
import type { LocalizeFunc } from "../../../common/translations/localize";
|
||||
import "../../../components/ha-control-select";
|
||||
import type { ControlSelectOption } from "../../../components/ha-control-select";
|
||||
import { apiContext, formattersContext } from "../../../data/context";
|
||||
import { UNAVAILABLE } from "../../../data/entity/entity";
|
||||
import type {
|
||||
HumidifierEntity,
|
||||
HumidifierState,
|
||||
} from "../../../data/humidifier";
|
||||
import type { HomeAssistant } from "../../../types";
|
||||
import type {
|
||||
HomeAssistant,
|
||||
HomeAssistantApi,
|
||||
HomeAssistantFormatters,
|
||||
} from "../../../types";
|
||||
import type { LovelaceCardFeature } from "../types";
|
||||
import { cardFeatureStyles } from "./common/card-feature-styles";
|
||||
import type {
|
||||
@@ -21,6 +33,11 @@ import type {
|
||||
LovelaceCardFeatureContext,
|
||||
} from "./types";
|
||||
|
||||
const supportsHumidifierToggleCardFeatureFromState = (stateObj: HassEntity) => {
|
||||
const domain = computeDomain(stateObj.entity_id);
|
||||
return domain === "humidifier";
|
||||
};
|
||||
|
||||
export const supportsHumidifierToggleCardFeature = (
|
||||
hass: HomeAssistant,
|
||||
context: LovelaceCardFeatureContext
|
||||
@@ -29,8 +46,7 @@ export const supportsHumidifierToggleCardFeature = (
|
||||
? hass.states[context.entity_id]
|
||||
: undefined;
|
||||
if (!stateObj) return false;
|
||||
const domain = computeDomain(stateObj.entity_id);
|
||||
return domain === "humidifier";
|
||||
return supportsHumidifierToggleCardFeatureFromState(stateObj);
|
||||
};
|
||||
|
||||
@customElement("hui-humidifier-toggle-card-feature")
|
||||
@@ -38,22 +54,28 @@ class HuiHumidifierToggleCardFeature
|
||||
extends LitElement
|
||||
implements LovelaceCardFeature
|
||||
{
|
||||
@property({ attribute: false }) public hass?: HomeAssistant;
|
||||
|
||||
@property({ attribute: false }) public context?: LovelaceCardFeatureContext;
|
||||
|
||||
@state()
|
||||
@consumeEntityState({ entityIdPath: ["context", "entity_id"] })
|
||||
private _stateObj?: HumidifierEntity;
|
||||
|
||||
@state()
|
||||
@consumeLocalize()
|
||||
private _localize!: LocalizeFunc;
|
||||
|
||||
@state()
|
||||
@consume({ context: apiContext, subscribe: true })
|
||||
private _api!: HomeAssistantApi;
|
||||
|
||||
@state()
|
||||
@consume({ context: formattersContext, subscribe: true })
|
||||
private _formatters!: HomeAssistantFormatters;
|
||||
|
||||
@state() private _config?: HumidifierToggleCardFeatureConfig;
|
||||
|
||||
@state() _currentState?: HumidifierState;
|
||||
|
||||
private get _stateObj() {
|
||||
if (!this.hass || !this.context || !this.context.entity_id) {
|
||||
return undefined;
|
||||
}
|
||||
return this.hass.states[this.context.entity_id!] as
|
||||
HumidifierEntity | undefined;
|
||||
}
|
||||
|
||||
static getStubConfig(): HumidifierToggleCardFeatureConfig {
|
||||
return {
|
||||
type: "humidifier-toggle",
|
||||
@@ -67,17 +89,10 @@ class HuiHumidifierToggleCardFeature
|
||||
this._config = config;
|
||||
}
|
||||
|
||||
protected willUpdate(changedProp: PropertyValues<this>): void {
|
||||
protected willUpdate(changedProp: PropertyValues): void {
|
||||
super.willUpdate(changedProp);
|
||||
if (
|
||||
(changedProp.has("hass") || changedProp.has("context")) &&
|
||||
this._stateObj
|
||||
) {
|
||||
const oldHass = changedProp.get("hass") as HomeAssistant | undefined;
|
||||
const oldStateObj = oldHass?.states[this.context!.entity_id!];
|
||||
if (oldStateObj !== this._stateObj) {
|
||||
this._currentState = this._stateObj.state as HumidifierState;
|
||||
}
|
||||
if (changedProp.has("_stateObj") && this._stateObj) {
|
||||
this._currentState = this._stateObj.state as HumidifierState;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -99,7 +114,7 @@ class HuiHumidifierToggleCardFeature
|
||||
}
|
||||
|
||||
private async _setState(newState: HumidifierState) {
|
||||
await this.hass!.callService(
|
||||
await this._api.callService(
|
||||
"humidifier",
|
||||
newState === "on" ? "turn_on" : "turn_off",
|
||||
{
|
||||
@@ -111,10 +126,9 @@ class HuiHumidifierToggleCardFeature
|
||||
protected render(): TemplateResult | null {
|
||||
if (
|
||||
!this._config ||
|
||||
!this.hass ||
|
||||
!this.context ||
|
||||
!this._stateObj ||
|
||||
!supportsHumidifierToggleCardFeature(this.hass, this.context)
|
||||
!supportsHumidifierToggleCardFeatureFromState(this._stateObj)
|
||||
) {
|
||||
return null;
|
||||
}
|
||||
@@ -123,7 +137,7 @@ class HuiHumidifierToggleCardFeature
|
||||
|
||||
const options = ["off", "on"].map<ControlSelectOption>((entityState) => ({
|
||||
value: entityState,
|
||||
label: this.hass!.formatEntityState(this._stateObj!, entityState),
|
||||
label: this._formatters.formatEntityState(this._stateObj!, entityState),
|
||||
path: entityState === "on" ? mdiWaterPercent : mdiPower,
|
||||
}));
|
||||
|
||||
@@ -133,7 +147,7 @@ class HuiHumidifierToggleCardFeature
|
||||
.value=${this._currentState}
|
||||
@value-changed=${this._valueChanged}
|
||||
hide-option-label
|
||||
.label=${this.hass.localize("ui.card.humidifier.state")}
|
||||
.label=${this._localize("ui.card.humidifier.state")}
|
||||
style=${styleMap({
|
||||
"--control-select-color": color,
|
||||
})}
|
||||
|
||||
@@ -1,16 +1,23 @@
|
||||
import { consume } from "@lit/context";
|
||||
import { mdiHomeImportOutline, mdiPause, mdiPlay } from "@mdi/js";
|
||||
import type { HassEntity } from "home-assistant-js-websocket";
|
||||
import { LitElement, html, nothing } from "lit";
|
||||
import { customElement, property, state } from "lit/decorators";
|
||||
import {
|
||||
consumeEntityState,
|
||||
consumeLocalize,
|
||||
} from "../../../common/decorators/consume-context-entry";
|
||||
import { computeDomain } from "../../../common/entity/compute_domain";
|
||||
import { supportsFeature } from "../../../common/entity/supports-feature";
|
||||
import type { LocalizeFunc } from "../../../common/translations/localize";
|
||||
import "../../../components/ha-control-button";
|
||||
import "../../../components/ha-control-button-group";
|
||||
import "../../../components/ha-svg-icon";
|
||||
import { apiContext } from "../../../data/context";
|
||||
import { UNAVAILABLE } from "../../../data/entity/entity";
|
||||
import type { LawnMowerEntity } from "../../../data/lawn_mower";
|
||||
import { LawnMowerEntityFeature, canDock } from "../../../data/lawn_mower";
|
||||
import type { HomeAssistant } from "../../../types";
|
||||
import type { HomeAssistant, HomeAssistantApi } from "../../../types";
|
||||
import type { LovelaceCardFeature, LovelaceCardFeatureEditor } from "../types";
|
||||
import { cardFeatureStyles } from "./common/card-feature-styles";
|
||||
import type {
|
||||
@@ -75,6 +82,14 @@ export const LAWN_MOWER_COMMANDS_BUTTONS: Record<
|
||||
}),
|
||||
};
|
||||
|
||||
const supportsLawnMowerCommandCardFeatureFromState = (stateObj: HassEntity) => {
|
||||
const domain = computeDomain(stateObj.entity_id);
|
||||
return (
|
||||
domain === "lawn_mower" &&
|
||||
LAWN_MOWER_COMMANDS.some((c) => supportsLawnMowerCommand(stateObj, c))
|
||||
);
|
||||
};
|
||||
|
||||
export const supportsLawnMowerCommandCardFeature = (
|
||||
hass: HomeAssistant,
|
||||
context: LovelaceCardFeatureContext
|
||||
@@ -83,11 +98,7 @@ export const supportsLawnMowerCommandCardFeature = (
|
||||
? hass.states[context.entity_id]
|
||||
: undefined;
|
||||
if (!stateObj) return false;
|
||||
const domain = computeDomain(stateObj.entity_id);
|
||||
return (
|
||||
domain === "lawn_mower" &&
|
||||
LAWN_MOWER_COMMANDS.some((c) => supportsLawnMowerCommand(stateObj, c))
|
||||
);
|
||||
return supportsLawnMowerCommandCardFeatureFromState(stateObj);
|
||||
};
|
||||
|
||||
@customElement("hui-lawn-mower-commands-card-feature")
|
||||
@@ -95,19 +106,21 @@ class HuiLawnMowerCommandCardFeature
|
||||
extends LitElement
|
||||
implements LovelaceCardFeature
|
||||
{
|
||||
@property({ attribute: false }) public hass?: HomeAssistant;
|
||||
|
||||
@property({ attribute: false }) public context?: LovelaceCardFeatureContext;
|
||||
|
||||
@state() private _config?: LawnMowerCommandsCardFeatureConfig;
|
||||
@state()
|
||||
@consumeEntityState({ entityIdPath: ["context", "entity_id"] })
|
||||
private _stateObj?: LawnMowerEntity;
|
||||
|
||||
private get _stateObj() {
|
||||
if (!this.hass || !this.context || !this.context.entity_id) {
|
||||
return undefined;
|
||||
}
|
||||
return this.hass.states[this.context.entity_id!] as
|
||||
LawnMowerEntity | undefined;
|
||||
}
|
||||
@state()
|
||||
@consumeLocalize()
|
||||
private _localize!: LocalizeFunc;
|
||||
|
||||
@state()
|
||||
@consume({ context: apiContext, subscribe: true })
|
||||
private _api!: HomeAssistantApi;
|
||||
|
||||
@state() private _config?: LawnMowerCommandsCardFeatureConfig;
|
||||
|
||||
static getStubConfig(): LawnMowerCommandsCardFeatureConfig {
|
||||
return {
|
||||
@@ -132,7 +145,7 @@ class HuiLawnMowerCommandCardFeature
|
||||
private _onCommandTap(ev): void {
|
||||
ev.stopPropagation();
|
||||
const entry = (ev.target! as any).entry as LawnMowerButton;
|
||||
this.hass!.callService("lawn_mower", entry.serviceName, {
|
||||
this._api.callService("lawn_mower", entry.serviceName, {
|
||||
entity_id: this._stateObj!.entity_id,
|
||||
});
|
||||
}
|
||||
@@ -140,10 +153,9 @@ class HuiLawnMowerCommandCardFeature
|
||||
protected render() {
|
||||
if (
|
||||
!this._config ||
|
||||
!this.hass ||
|
||||
!this.context ||
|
||||
!this._stateObj ||
|
||||
!supportsLawnMowerCommandCardFeature(this.hass, this.context)
|
||||
!supportsLawnMowerCommandCardFeatureFromState(this._stateObj)
|
||||
) {
|
||||
return nothing;
|
||||
}
|
||||
@@ -161,7 +173,7 @@ class HuiLawnMowerCommandCardFeature
|
||||
return html`
|
||||
<ha-control-button
|
||||
.entry=${button}
|
||||
.label=${this.hass!.localize(
|
||||
.label=${this._localize(
|
||||
// @ts-ignore
|
||||
`ui.dialogs.more_info_control.lawn_mower.${button.translationKey}`
|
||||
)}
|
||||
|
||||
@@ -1,11 +1,25 @@
|
||||
import { consume } from "@lit/context";
|
||||
import type { HassEntity } from "home-assistant-js-websocket";
|
||||
import { html, LitElement, nothing } from "lit";
|
||||
import { customElement, property, state } from "lit/decorators";
|
||||
import {
|
||||
consumeEntityState,
|
||||
consumeLocalize,
|
||||
} from "../../../common/decorators/consume-context-entry";
|
||||
import { transform } from "../../../common/decorators/transform";
|
||||
import { computeDomain } from "../../../common/entity/compute_domain";
|
||||
import { stateActive } from "../../../common/entity/state_active";
|
||||
import type { LocalizeFunc } from "../../../common/translations/localize";
|
||||
import "../../../components/ha-control-slider";
|
||||
import { apiContext, internationalizationContext } from "../../../data/context";
|
||||
import { UNAVAILABLE } from "../../../data/entity/entity";
|
||||
import { lightSupportsBrightness, type LightEntity } from "../../../data/light";
|
||||
import type { HomeAssistant } from "../../../types";
|
||||
import type { FrontendLocaleData } from "../../../data/translation";
|
||||
import type {
|
||||
HomeAssistant,
|
||||
HomeAssistantApi,
|
||||
HomeAssistantInternationalization,
|
||||
} from "../../../types";
|
||||
import type { LovelaceCardFeature } from "../types";
|
||||
import { cardFeatureStyles } from "./common/card-feature-styles";
|
||||
import type {
|
||||
@@ -13,6 +27,11 @@ import type {
|
||||
LovelaceCardFeatureContext,
|
||||
} from "./types";
|
||||
|
||||
const supportsLightBrightnessCardFeatureFromState = (stateObj: HassEntity) => {
|
||||
const domain = computeDomain(stateObj.entity_id);
|
||||
return domain === "light" && lightSupportsBrightness(stateObj);
|
||||
};
|
||||
|
||||
export const supportsLightBrightnessCardFeature = (
|
||||
hass: HomeAssistant,
|
||||
context: LovelaceCardFeatureContext
|
||||
@@ -21,8 +40,7 @@ export const supportsLightBrightnessCardFeature = (
|
||||
? hass.states[context.entity_id]
|
||||
: undefined;
|
||||
if (!stateObj) return false;
|
||||
const domain = computeDomain(stateObj.entity_id);
|
||||
return domain === "light" && lightSupportsBrightness(stateObj);
|
||||
return supportsLightBrightnessCardFeatureFromState(stateObj);
|
||||
};
|
||||
|
||||
@customElement("hui-light-brightness-card-feature")
|
||||
@@ -30,18 +48,28 @@ class HuiLightBrightnessCardFeature
|
||||
extends LitElement
|
||||
implements LovelaceCardFeature
|
||||
{
|
||||
@property({ attribute: false }) public hass?: HomeAssistant;
|
||||
|
||||
@property({ attribute: false }) public context?: LovelaceCardFeatureContext;
|
||||
|
||||
@state() private _config?: LightBrightnessCardFeatureConfig;
|
||||
@state()
|
||||
@consumeEntityState({ entityIdPath: ["context", "entity_id"] })
|
||||
private _stateObj?: LightEntity;
|
||||
|
||||
private get _stateObj() {
|
||||
if (!this.hass || !this.context || !this.context.entity_id) {
|
||||
return undefined;
|
||||
}
|
||||
return this.hass.states[this.context.entity_id] as LightEntity | undefined;
|
||||
}
|
||||
@state()
|
||||
@consumeLocalize()
|
||||
private _localize!: LocalizeFunc;
|
||||
|
||||
@state()
|
||||
@consume({ context: apiContext, subscribe: true })
|
||||
private _api!: HomeAssistantApi;
|
||||
|
||||
@state()
|
||||
@consume({ context: internationalizationContext, subscribe: true })
|
||||
@transform<HomeAssistantInternationalization, FrontendLocaleData>({
|
||||
transformer: ({ locale }) => locale,
|
||||
})
|
||||
private _locale?: FrontendLocaleData;
|
||||
|
||||
@state() private _config?: LightBrightnessCardFeatureConfig;
|
||||
|
||||
static getStubConfig(): LightBrightnessCardFeatureConfig {
|
||||
return {
|
||||
@@ -59,10 +87,9 @@ class HuiLightBrightnessCardFeature
|
||||
protected render() {
|
||||
if (
|
||||
!this._config ||
|
||||
!this.hass ||
|
||||
!this.context ||
|
||||
!this._stateObj ||
|
||||
!supportsLightBrightnessCardFeature(this.hass, this.context)
|
||||
!supportsLightBrightnessCardFeatureFromState(this._stateObj)
|
||||
) {
|
||||
return nothing;
|
||||
}
|
||||
@@ -83,9 +110,9 @@ class HuiLightBrightnessCardFeature
|
||||
.showHandle=${stateActive(this._stateObj)}
|
||||
.disabled=${this._stateObj!.state === UNAVAILABLE}
|
||||
@value-changed=${this._valueChanged}
|
||||
.label=${this.hass.localize("ui.card.light.brightness")}
|
||||
.label=${this._localize("ui.card.light.brightness")}
|
||||
unit="%"
|
||||
.locale=${this.hass.locale}
|
||||
.locale=${this._locale}
|
||||
></ha-control-slider>
|
||||
`;
|
||||
}
|
||||
@@ -94,7 +121,7 @@ class HuiLightBrightnessCardFeature
|
||||
ev.stopPropagation();
|
||||
const value = ev.detail.value;
|
||||
|
||||
this.hass!.callService("light", "turn_on", {
|
||||
this._api.callService("light", "turn_on", {
|
||||
entity_id: this._stateObj!.entity_id,
|
||||
brightness_pct: value,
|
||||
});
|
||||
|
||||
@@ -1,9 +1,21 @@
|
||||
import { consume } from "@lit/context";
|
||||
import { ResizeController } from "@lit-labs/observers/resize-controller";
|
||||
import type { PropertyValues } from "lit";
|
||||
import { css, html, LitElement, nothing, unsafeCSS } from "lit";
|
||||
import { customElement, property, state } from "lit/decorators";
|
||||
import type { UnsubscribeFunc } from "home-assistant-js-websocket";
|
||||
import type {
|
||||
Connection,
|
||||
UnsubscribeFunc,
|
||||
HassEntity,
|
||||
} from "home-assistant-js-websocket";
|
||||
import {
|
||||
consumeEntityState,
|
||||
consumeLocalize,
|
||||
} from "../../../common/decorators/consume-context-entry";
|
||||
import { transform } from "../../../common/decorators/transform";
|
||||
import { computeDomain } from "../../../common/entity/compute_domain";
|
||||
import type { LocalizeFunc } from "../../../common/translations/localize";
|
||||
import { apiContext, connectionContext } from "../../../data/context";
|
||||
import { UNAVAILABLE } from "../../../data/entity/entity";
|
||||
import {
|
||||
computeDefaultFavoriteColors,
|
||||
@@ -11,7 +23,11 @@ import {
|
||||
type LightColor,
|
||||
lightSupportsFavoriteColors,
|
||||
} from "../../../data/light";
|
||||
import type { HomeAssistant } from "../../../types";
|
||||
import type {
|
||||
HomeAssistant,
|
||||
HomeAssistantApi,
|
||||
HomeAssistantConnection,
|
||||
} from "../../../types";
|
||||
import type { LovelaceCardFeature } from "../types";
|
||||
import { cardFeatureStyles } from "./common/card-feature-styles";
|
||||
import type {
|
||||
@@ -29,6 +45,13 @@ import { getMoreInfoHintCardFeatureEditor } from "./get-more-info-hint-card-feat
|
||||
const PILL_GAP = 8;
|
||||
const PILL_MIN_SIZE = 32;
|
||||
|
||||
const supportsLightColorFavoritesCardFeatureFromState = (
|
||||
stateObj: HassEntity
|
||||
) => {
|
||||
const domain = computeDomain(stateObj.entity_id);
|
||||
return domain === "light" && lightSupportsFavoriteColors(stateObj);
|
||||
};
|
||||
|
||||
export const supportsLightColorFavoritesCardFeature = (
|
||||
hass: HomeAssistant,
|
||||
context: LovelaceCardFeatureContext
|
||||
@@ -37,8 +60,7 @@ export const supportsLightColorFavoritesCardFeature = (
|
||||
? hass.states[context.entity_id]
|
||||
: undefined;
|
||||
if (!stateObj) return false;
|
||||
const domain = computeDomain(stateObj.entity_id);
|
||||
return domain === "light" && lightSupportsFavoriteColors(stateObj);
|
||||
return supportsLightColorFavoritesCardFeatureFromState(stateObj);
|
||||
};
|
||||
|
||||
@customElement("hui-light-color-favorites-card-feature")
|
||||
@@ -46,10 +68,27 @@ class HuiLightColorFavoritesCardFeature
|
||||
extends LitElement
|
||||
implements LovelaceCardFeature
|
||||
{
|
||||
@property({ attribute: false }) public hass?: HomeAssistant;
|
||||
|
||||
@property({ attribute: false }) public context?: LovelaceCardFeatureContext;
|
||||
|
||||
@state()
|
||||
@consumeEntityState({ entityIdPath: ["context", "entity_id"] })
|
||||
private _stateObj?: LightEntity;
|
||||
|
||||
@state()
|
||||
@consumeLocalize()
|
||||
private _localize!: LocalizeFunc;
|
||||
|
||||
@state()
|
||||
@consume({ context: apiContext, subscribe: true })
|
||||
private _api!: HomeAssistantApi;
|
||||
|
||||
@state()
|
||||
@consume({ context: connectionContext, subscribe: true })
|
||||
@transform<HomeAssistantConnection, Connection>({
|
||||
transformer: ({ connection }) => connection,
|
||||
})
|
||||
private _connection?: Connection;
|
||||
|
||||
@state() private _config?: LightColorFavoritesCardFeatureConfig;
|
||||
|
||||
@state() private _entry?: EntityRegistryEntry | null;
|
||||
@@ -86,11 +125,11 @@ class HuiLightColorFavoritesCardFeature
|
||||
}
|
||||
|
||||
private _subscribeEntityEntry() {
|
||||
if (this.hass && this.context?.entity_id) {
|
||||
if (this._connection && this.context?.entity_id) {
|
||||
const id = this.context.entity_id;
|
||||
try {
|
||||
this._unsubEntityRegistry = subscribeEntityRegistry(
|
||||
this.hass!.connection,
|
||||
this._connection,
|
||||
(entries) => {
|
||||
const entry = entries.find((e) => e.entity_id === id);
|
||||
if (entry) {
|
||||
@@ -108,15 +147,8 @@ class HuiLightColorFavoritesCardFeature
|
||||
return this._resizeController.value ?? 0;
|
||||
}
|
||||
|
||||
private get _stateObj() {
|
||||
if (!this.hass || !this.context || !this.context.entity_id) {
|
||||
return undefined;
|
||||
}
|
||||
return this.hass.states[this.context.entity_id] as LightEntity | undefined;
|
||||
}
|
||||
|
||||
protected updated(changedProps: PropertyValues): void {
|
||||
if (changedProps.has("context")) {
|
||||
if (changedProps.has("context") || changedProps.has("_connection")) {
|
||||
this._unsubscribeEntityRegistry();
|
||||
this._subscribeEntityEntry();
|
||||
}
|
||||
@@ -150,10 +182,9 @@ class HuiLightColorFavoritesCardFeature
|
||||
protected render() {
|
||||
if (
|
||||
!this._config ||
|
||||
!this.hass ||
|
||||
!this.context ||
|
||||
!this._stateObj ||
|
||||
!supportsLightColorFavoritesCardFeature(this.hass, this.context)
|
||||
!supportsLightColorFavoritesCardFeatureFromState(this._stateObj)
|
||||
) {
|
||||
return nothing;
|
||||
}
|
||||
@@ -165,7 +196,7 @@ class HuiLightColorFavoritesCardFeature
|
||||
${visibleColors.map(
|
||||
(color, index) => html`
|
||||
<ha-favorite-color-button
|
||||
.label=${this.hass!.localize(
|
||||
.label=${this._localize(
|
||||
`ui.dialogs.more_info_control.light.favorite_color.set`,
|
||||
{ number: index }
|
||||
)}
|
||||
@@ -189,7 +220,7 @@ class HuiLightColorFavoritesCardFeature
|
||||
const index = (ev.target! as any).index!;
|
||||
|
||||
const favorite = this._favoriteColors[index];
|
||||
this.hass!.callService("light", "turn_on", {
|
||||
this._api.callService("light", "turn_on", {
|
||||
entity_id: this._stateObj!.entity_id,
|
||||
...favorite,
|
||||
});
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import { consume } from "@lit/context";
|
||||
import type { HassEntity } from "home-assistant-js-websocket";
|
||||
import { css, html, LitElement, nothing } from "lit";
|
||||
import { customElement, property, state } from "lit/decorators";
|
||||
import { styleMap } from "lit/directives/style-map";
|
||||
@@ -6,9 +8,16 @@ import {
|
||||
DEFAULT_MAX_KELVIN,
|
||||
DEFAULT_MIN_KELVIN,
|
||||
} from "../../../common/color/convert-light-color";
|
||||
import {
|
||||
consumeEntityState,
|
||||
consumeLocalize,
|
||||
} from "../../../common/decorators/consume-context-entry";
|
||||
import { transform } from "../../../common/decorators/transform";
|
||||
import { computeDomain } from "../../../common/entity/compute_domain";
|
||||
import { stateActive } from "../../../common/entity/state_active";
|
||||
import type { LocalizeFunc } from "../../../common/translations/localize";
|
||||
import "../../../components/ha-control-slider";
|
||||
import { apiContext, internationalizationContext } from "../../../data/context";
|
||||
import { UNAVAILABLE } from "../../../data/entity/entity";
|
||||
import { DOMAIN_ATTRIBUTES_UNITS } from "../../../data/entity/entity_attributes";
|
||||
import {
|
||||
@@ -16,8 +25,13 @@ import {
|
||||
lightSupportsColorMode,
|
||||
type LightEntity,
|
||||
} from "../../../data/light";
|
||||
import type { FrontendLocaleData } from "../../../data/translation";
|
||||
import { generateColorTemperatureGradient } from "../../../dialogs/more-info/components/lights/light-color-temp-picker";
|
||||
import type { HomeAssistant } from "../../../types";
|
||||
import type {
|
||||
HomeAssistant,
|
||||
HomeAssistantApi,
|
||||
HomeAssistantInternationalization,
|
||||
} from "../../../types";
|
||||
import type { LovelaceCardFeature } from "../types";
|
||||
import { cardFeatureStyles } from "./common/card-feature-styles";
|
||||
import type {
|
||||
@@ -25,6 +39,14 @@ import type {
|
||||
LovelaceCardFeatureContext,
|
||||
} from "./types";
|
||||
|
||||
const supportsLightColorTempCardFeatureFromState = (stateObj: HassEntity) => {
|
||||
const domain = computeDomain(stateObj.entity_id);
|
||||
return (
|
||||
domain === "light" &&
|
||||
lightSupportsColorMode(stateObj, LightColorMode.COLOR_TEMP)
|
||||
);
|
||||
};
|
||||
|
||||
export const supportsLightColorTempCardFeature = (
|
||||
hass: HomeAssistant,
|
||||
context: LovelaceCardFeatureContext
|
||||
@@ -33,11 +55,7 @@ export const supportsLightColorTempCardFeature = (
|
||||
? hass.states[context.entity_id]
|
||||
: undefined;
|
||||
if (!stateObj) return false;
|
||||
const domain = computeDomain(stateObj.entity_id);
|
||||
return (
|
||||
domain === "light" &&
|
||||
lightSupportsColorMode(stateObj, LightColorMode.COLOR_TEMP)
|
||||
);
|
||||
return supportsLightColorTempCardFeatureFromState(stateObj);
|
||||
};
|
||||
|
||||
@customElement("hui-light-color-temp-card-feature")
|
||||
@@ -45,18 +63,28 @@ class HuiLightColorTempCardFeature
|
||||
extends LitElement
|
||||
implements LovelaceCardFeature
|
||||
{
|
||||
@property({ attribute: false }) public hass?: HomeAssistant;
|
||||
|
||||
@property({ attribute: false }) public context?: LovelaceCardFeatureContext;
|
||||
|
||||
@state() private _config?: LightColorTempCardFeatureConfig;
|
||||
@state()
|
||||
@consumeEntityState({ entityIdPath: ["context", "entity_id"] })
|
||||
private _stateObj?: LightEntity;
|
||||
|
||||
private get _stateObj() {
|
||||
if (!this.hass || !this.context || !this.context.entity_id) {
|
||||
return undefined;
|
||||
}
|
||||
return this.hass.states[this.context.entity_id!] as LightEntity | undefined;
|
||||
}
|
||||
@state()
|
||||
@consumeLocalize()
|
||||
private _localize!: LocalizeFunc;
|
||||
|
||||
@state()
|
||||
@consume({ context: apiContext, subscribe: true })
|
||||
private _api!: HomeAssistantApi;
|
||||
|
||||
@state()
|
||||
@consume({ context: internationalizationContext, subscribe: true })
|
||||
@transform<HomeAssistantInternationalization, FrontendLocaleData>({
|
||||
transformer: ({ locale }) => locale,
|
||||
})
|
||||
private _locale?: FrontendLocaleData;
|
||||
|
||||
@state() private _config?: LightColorTempCardFeatureConfig;
|
||||
|
||||
static getStubConfig(): LightColorTempCardFeatureConfig {
|
||||
return {
|
||||
@@ -74,10 +102,9 @@ class HuiLightColorTempCardFeature
|
||||
protected render() {
|
||||
if (
|
||||
!this._config ||
|
||||
!this.hass ||
|
||||
!this.context ||
|
||||
!this._stateObj ||
|
||||
!supportsLightColorTempCardFeature(this.hass, this.context)
|
||||
!supportsLightColorTempCardFeatureFromState(this._stateObj)
|
||||
) {
|
||||
return nothing;
|
||||
}
|
||||
@@ -101,14 +128,14 @@ class HuiLightColorTempCardFeature
|
||||
.showHandle=${stateActive(this._stateObj)}
|
||||
.disabled=${this._stateObj!.state === UNAVAILABLE}
|
||||
@value-changed=${this._valueChanged}
|
||||
.label=${this.hass.localize("ui.card.light.color_temperature")}
|
||||
.label=${this._localize("ui.card.light.color_temperature")}
|
||||
.min=${minKelvin}
|
||||
.max=${maxKelvin}
|
||||
style=${styleMap({
|
||||
"--gradient": gradient,
|
||||
})}
|
||||
.unit=${DOMAIN_ATTRIBUTES_UNITS.light.color_temp_kelvin}
|
||||
.locale=${this.hass.locale}
|
||||
.locale=${this._locale}
|
||||
></ha-control-slider>
|
||||
`;
|
||||
}
|
||||
@@ -121,7 +148,7 @@ class HuiLightColorTempCardFeature
|
||||
ev.stopPropagation();
|
||||
const value = ev.detail.value;
|
||||
|
||||
this.hass!.callService("light", "turn_on", {
|
||||
this._api.callService("light", "turn_on", {
|
||||
entity_id: this._stateObj!.entity_id,
|
||||
color_temp_kelvin: value,
|
||||
});
|
||||
|
||||
@@ -1,10 +1,18 @@
|
||||
import { consume } from "@lit/context";
|
||||
import { mdiLock, mdiLockOpenVariant } from "@mdi/js";
|
||||
import type { HassEntity } from "home-assistant-js-websocket";
|
||||
import type { CSSResultGroup } from "lit";
|
||||
import { LitElement, html, nothing } from "lit";
|
||||
import { customElement, property, state } from "lit/decorators";
|
||||
import {
|
||||
consumeEntityState,
|
||||
consumeLocalize,
|
||||
} from "../../../common/decorators/consume-context-entry";
|
||||
import { computeDomain } from "../../../common/entity/compute_domain";
|
||||
import type { LocalizeFunc } from "../../../common/translations/localize";
|
||||
import "../../../components/ha-control-button";
|
||||
import "../../../components/ha-control-button-group";
|
||||
import { apiContext } from "../../../data/context";
|
||||
import { forwardHaptic } from "../../../data/haptics";
|
||||
import {
|
||||
callProtectedLockService,
|
||||
@@ -12,7 +20,7 @@ import {
|
||||
canUnlock,
|
||||
type LockEntity,
|
||||
} from "../../../data/lock";
|
||||
import type { HomeAssistant } from "../../../types";
|
||||
import type { HomeAssistant, HomeAssistantApi } from "../../../types";
|
||||
import type { LovelaceCardFeature } from "../types";
|
||||
import { cardFeatureStyles } from "./common/card-feature-styles";
|
||||
import type {
|
||||
@@ -20,6 +28,11 @@ import type {
|
||||
LovelaceCardFeatureContext,
|
||||
} from "./types";
|
||||
|
||||
const supportsLockCommandsCardFeatureFromState = (stateObj: HassEntity) => {
|
||||
const domain = computeDomain(stateObj.entity_id);
|
||||
return domain === "lock";
|
||||
};
|
||||
|
||||
export const supportsLockCommandsCardFeature = (
|
||||
hass: HomeAssistant,
|
||||
context: LovelaceCardFeatureContext
|
||||
@@ -28,8 +41,7 @@ export const supportsLockCommandsCardFeature = (
|
||||
? hass.states[context.entity_id]
|
||||
: undefined;
|
||||
if (!stateObj) return false;
|
||||
const domain = computeDomain(stateObj.entity_id);
|
||||
return domain === "lock";
|
||||
return supportsLockCommandsCardFeatureFromState(stateObj);
|
||||
};
|
||||
|
||||
@customElement("hui-lock-commands-card-feature")
|
||||
@@ -37,18 +49,21 @@ class HuiLockCommandsCardFeature
|
||||
extends LitElement
|
||||
implements LovelaceCardFeature
|
||||
{
|
||||
@property({ attribute: false }) public hass?: HomeAssistant;
|
||||
|
||||
@property({ attribute: false }) public context?: LovelaceCardFeatureContext;
|
||||
|
||||
@state() private _config?: LockCommandsCardFeatureConfig;
|
||||
@state()
|
||||
@consumeEntityState({ entityIdPath: ["context", "entity_id"] })
|
||||
private _stateObj?: LockEntity;
|
||||
|
||||
private get _stateObj() {
|
||||
if (!this.hass || !this.context || !this.context.entity_id) {
|
||||
return undefined;
|
||||
}
|
||||
return this.hass.states[this.context.entity_id!] as LockEntity | undefined;
|
||||
}
|
||||
@state()
|
||||
@consumeLocalize()
|
||||
private _localize!: LocalizeFunc;
|
||||
|
||||
@state()
|
||||
@consume({ context: apiContext, subscribe: true })
|
||||
private _api!: HomeAssistantApi;
|
||||
|
||||
@state() private _config?: LockCommandsCardFeatureConfig;
|
||||
|
||||
static getStubConfig(): LockCommandsCardFeatureConfig {
|
||||
return {
|
||||
@@ -66,20 +81,28 @@ class HuiLockCommandsCardFeature
|
||||
private _onTap(ev): void {
|
||||
ev.stopPropagation();
|
||||
const service = ev.target.dataset.service;
|
||||
if (!this.hass || !this._stateObj || !service) {
|
||||
if (!this._stateObj || !service) {
|
||||
return;
|
||||
}
|
||||
forwardHaptic(this, "light");
|
||||
callProtectedLockService(this, this.hass, this._stateObj, service);
|
||||
callProtectedLockService(
|
||||
this,
|
||||
{
|
||||
callService: this._api.callService,
|
||||
callWS: this._api.callWS,
|
||||
localize: this._localize,
|
||||
},
|
||||
this._stateObj,
|
||||
service
|
||||
);
|
||||
}
|
||||
|
||||
protected render() {
|
||||
if (
|
||||
!this._config ||
|
||||
!this.hass ||
|
||||
!this.context ||
|
||||
!this._stateObj ||
|
||||
!supportsLockCommandsCardFeature(this.hass, this.context)
|
||||
!supportsLockCommandsCardFeatureFromState(this._stateObj)
|
||||
) {
|
||||
return nothing;
|
||||
}
|
||||
@@ -87,7 +110,7 @@ class HuiLockCommandsCardFeature
|
||||
return html`
|
||||
<ha-control-button-group>
|
||||
<ha-control-button
|
||||
.label=${this.hass.localize("ui.card.lock.lock")}
|
||||
.label=${this._localize("ui.card.lock.lock")}
|
||||
.disabled=${!canLock(this._stateObj)}
|
||||
@click=${this._onTap}
|
||||
data-service="lock"
|
||||
@@ -95,7 +118,7 @@ class HuiLockCommandsCardFeature
|
||||
<ha-svg-icon .path=${mdiLock}></ha-svg-icon>
|
||||
</ha-control-button>
|
||||
<ha-control-button
|
||||
.label=${this.hass.localize("ui.card.lock.unlock")}
|
||||
.label=${this._localize("ui.card.lock.unlock")}
|
||||
.disabled=${!canUnlock(this._stateObj)}
|
||||
@click=${this._onTap}
|
||||
data-service="unlock"
|
||||
|
||||
@@ -1,18 +1,26 @@
|
||||
import { consume } from "@lit/context";
|
||||
import { mdiCheck } from "@mdi/js";
|
||||
import type { HassEntity } from "home-assistant-js-websocket";
|
||||
import type { CSSResultGroup } from "lit";
|
||||
import { css, html, LitElement, nothing } from "lit";
|
||||
import { customElement, property, state } from "lit/decorators";
|
||||
import {
|
||||
consumeEntityState,
|
||||
consumeLocalize,
|
||||
} from "../../../common/decorators/consume-context-entry";
|
||||
import { computeDomain } from "../../../common/entity/compute_domain";
|
||||
import { supportsFeature } from "../../../common/entity/supports-feature";
|
||||
import type { LocalizeFunc } from "../../../common/translations/localize";
|
||||
import "../../../components/ha-control-button";
|
||||
import "../../../components/ha-control-button-group";
|
||||
import { apiContext } from "../../../data/context";
|
||||
import {
|
||||
callProtectedLockService,
|
||||
canOpen,
|
||||
LockEntityFeature,
|
||||
type LockEntity,
|
||||
} from "../../../data/lock";
|
||||
import type { HomeAssistant } from "../../../types";
|
||||
import type { HomeAssistant, HomeAssistantApi } from "../../../types";
|
||||
import type { LovelaceCardFeature } from "../types";
|
||||
import { cardFeatureStyles } from "./common/card-feature-styles";
|
||||
import type {
|
||||
@@ -20,6 +28,11 @@ import type {
|
||||
LovelaceCardFeatureContext,
|
||||
} from "./types";
|
||||
|
||||
const supportsLockOpenDoorCardFeatureFromState = (stateObj: HassEntity) => {
|
||||
const domain = computeDomain(stateObj.entity_id);
|
||||
return domain === "lock" && supportsFeature(stateObj, LockEntityFeature.OPEN);
|
||||
};
|
||||
|
||||
export const supportsLockOpenDoorCardFeature = (
|
||||
hass: HomeAssistant,
|
||||
context: LovelaceCardFeatureContext
|
||||
@@ -28,8 +41,7 @@ export const supportsLockOpenDoorCardFeature = (
|
||||
? hass.states[context.entity_id]
|
||||
: undefined;
|
||||
if (!stateObj) return false;
|
||||
const domain = computeDomain(stateObj.entity_id);
|
||||
return domain === "lock" && supportsFeature(stateObj, LockEntityFeature.OPEN);
|
||||
return supportsLockOpenDoorCardFeatureFromState(stateObj);
|
||||
};
|
||||
|
||||
const CONFIRM_TIMEOUT_SECOND = 5;
|
||||
@@ -42,23 +54,26 @@ class HuiLockOpenDoorCardFeature
|
||||
extends LitElement
|
||||
implements LovelaceCardFeature
|
||||
{
|
||||
@property({ attribute: false }) public hass?: HomeAssistant;
|
||||
|
||||
@property({ attribute: false }) public context?: LovelaceCardFeatureContext;
|
||||
|
||||
@state()
|
||||
@consumeEntityState({ entityIdPath: ["context", "entity_id"] })
|
||||
private _stateObj?: LockEntity;
|
||||
|
||||
@state()
|
||||
@consumeLocalize()
|
||||
private _localize!: LocalizeFunc;
|
||||
|
||||
@state()
|
||||
@consume({ context: apiContext, subscribe: true })
|
||||
private _api!: HomeAssistantApi;
|
||||
|
||||
@state() public _buttonState: ButtonState = "normal";
|
||||
|
||||
@state() private _config?: LockOpenDoorCardFeatureConfig;
|
||||
|
||||
private _buttonTimeout?: number;
|
||||
|
||||
private get _stateObj() {
|
||||
if (!this.hass || !this.context || !this.context.entity_id) {
|
||||
return undefined;
|
||||
}
|
||||
return this.hass.states[this.context.entity_id!] as LockEntity | undefined;
|
||||
}
|
||||
|
||||
static getStubConfig(): LockOpenDoorCardFeatureConfig {
|
||||
return {
|
||||
type: "lock-open-door",
|
||||
@@ -87,10 +102,19 @@ class HuiLockOpenDoorCardFeature
|
||||
this._setButtonState("confirm", CONFIRM_TIMEOUT_SECOND);
|
||||
return;
|
||||
}
|
||||
if (!this.hass || !this._stateObj) {
|
||||
if (!this._stateObj) {
|
||||
return;
|
||||
}
|
||||
callProtectedLockService(this, this.hass, this._stateObj!, "open");
|
||||
callProtectedLockService(
|
||||
this,
|
||||
{
|
||||
callService: this._api.callService,
|
||||
callWS: this._api.callWS,
|
||||
localize: this._localize,
|
||||
},
|
||||
this._stateObj,
|
||||
"open"
|
||||
);
|
||||
|
||||
this._setButtonState("done", DONE_TIMEOUT_SECOND);
|
||||
}
|
||||
@@ -98,10 +122,9 @@ class HuiLockOpenDoorCardFeature
|
||||
protected render() {
|
||||
if (
|
||||
!this._config ||
|
||||
!this.hass ||
|
||||
!this.context ||
|
||||
!this._stateObj ||
|
||||
!supportsLockOpenDoorCardFeature(this.hass, this.context)
|
||||
!supportsLockOpenDoorCardFeatureFromState(this._stateObj)
|
||||
) {
|
||||
return nothing;
|
||||
}
|
||||
@@ -112,7 +135,7 @@ class HuiLockOpenDoorCardFeature
|
||||
? html`
|
||||
<p class="open-done">
|
||||
<ha-svg-icon path=${mdiCheck}></ha-svg-icon>
|
||||
${this.hass.localize("ui.card.lock.open_door_done")}
|
||||
${this._localize("ui.card.lock.open_door_done")}
|
||||
</p>
|
||||
`
|
||||
: html`
|
||||
@@ -124,8 +147,8 @@ class HuiLockOpenDoorCardFeature
|
||||
>
|
||||
${
|
||||
this._buttonState === "confirm"
|
||||
? this.hass.localize("ui.card.lock.open_door_confirm")
|
||||
: this.hass.localize("ui.card.lock.open_door")
|
||||
? this._localize("ui.card.lock.open_door_confirm")
|
||||
: this._localize("ui.card.lock.open_door")
|
||||
}
|
||||
</ha-control-button>
|
||||
</ha-control-button-group>
|
||||
|
||||
@@ -1,14 +1,22 @@
|
||||
import { consume } from "@lit/context";
|
||||
import type { HassEntity } from "home-assistant-js-websocket";
|
||||
import type { PropertyValues } from "lit";
|
||||
import { css, html, LitElement, nothing } from "lit";
|
||||
import { customElement, property, state } from "lit/decorators";
|
||||
import {
|
||||
consumeEntityState,
|
||||
consumeLocalize,
|
||||
} from "../../../common/decorators/consume-context-entry";
|
||||
import { computeDomain } from "../../../common/entity/compute_domain";
|
||||
import type { LocalizeFunc } from "../../../common/translations/localize";
|
||||
import "../../../components/ha-control-button";
|
||||
import "../../../components/ha-control-button-group";
|
||||
import { apiContext } from "../../../data/context";
|
||||
import type {
|
||||
ControlButton,
|
||||
MediaPlayerEntity,
|
||||
} from "../../../data/media-player";
|
||||
import type { HomeAssistant } from "../../../types";
|
||||
import type { HomeAssistant, HomeAssistantApi } from "../../../types";
|
||||
import { hasConfigChanged } from "../common/has-changed";
|
||||
import type { LovelaceCardFeature, LovelaceCardFeatureEditor } from "../types";
|
||||
import { cardFeatureStyles } from "./common/card-feature-styles";
|
||||
@@ -21,6 +29,13 @@ import type {
|
||||
MediaPlayerPlaybackCardFeatureConfig,
|
||||
} from "./types";
|
||||
|
||||
const supportsMediaPlayerPlaybackCardFeatureFromState = (
|
||||
stateObj: HassEntity
|
||||
) => {
|
||||
const domain = computeDomain(stateObj.entity_id);
|
||||
return domain === "media_player";
|
||||
};
|
||||
|
||||
export const supportsMediaPlayerPlaybackCardFeature = (
|
||||
hass: HomeAssistant,
|
||||
context: LovelaceCardFeatureContext
|
||||
@@ -29,8 +44,7 @@ export const supportsMediaPlayerPlaybackCardFeature = (
|
||||
? hass.states[context.entity_id]
|
||||
: undefined;
|
||||
if (!stateObj) return false;
|
||||
const domain = computeDomain(stateObj.entity_id);
|
||||
return domain === "media_player";
|
||||
return supportsMediaPlayerPlaybackCardFeatureFromState(stateObj);
|
||||
};
|
||||
|
||||
@customElement("hui-media-player-playback-card-feature")
|
||||
@@ -38,24 +52,26 @@ class HuiMediaPlayerPlaybackCardFeature
|
||||
extends LitElement
|
||||
implements LovelaceCardFeature
|
||||
{
|
||||
@property({ attribute: false }) public hass?: HomeAssistant;
|
||||
|
||||
@property({ attribute: false }) public context?: LovelaceCardFeatureContext;
|
||||
|
||||
@property({ attribute: false }) public color?: string;
|
||||
|
||||
@state()
|
||||
@consumeEntityState({ entityIdPath: ["context", "entity_id"] })
|
||||
private _stateObj?: MediaPlayerEntity;
|
||||
|
||||
@state()
|
||||
@consumeLocalize()
|
||||
private _localize!: LocalizeFunc;
|
||||
|
||||
@state()
|
||||
@consume({ context: apiContext, subscribe: true })
|
||||
private _api!: HomeAssistantApi;
|
||||
|
||||
@state() private _config?: MediaPlayerPlaybackCardFeatureConfig;
|
||||
|
||||
@state() private _narrow?: boolean = false;
|
||||
|
||||
private get _stateObj() {
|
||||
if (!this.hass || !this.context || !this.context.entity_id) {
|
||||
return undefined;
|
||||
}
|
||||
return this.hass.states[this.context.entity_id] as
|
||||
MediaPlayerEntity | undefined;
|
||||
}
|
||||
|
||||
static getStubConfig(): MediaPlayerPlaybackCardFeatureConfig {
|
||||
return {
|
||||
type: "media-player-playback",
|
||||
@@ -82,25 +98,18 @@ class HuiMediaPlayerPlaybackCardFeature
|
||||
}
|
||||
}
|
||||
|
||||
protected shouldUpdate(changedProps: PropertyValues<this>): boolean {
|
||||
const oldHass = changedProps.get("hass") as HomeAssistant | undefined;
|
||||
const entityId = this.context?.entity_id;
|
||||
protected shouldUpdate(changedProps: PropertyValues): boolean {
|
||||
return (
|
||||
hasConfigChanged(this, changedProps) ||
|
||||
(changedProps.has("hass") &&
|
||||
(!oldHass ||
|
||||
!entityId ||
|
||||
oldHass.states[entityId] !== this.hass!.states[entityId]))
|
||||
hasConfigChanged(this, changedProps) || changedProps.has("_stateObj")
|
||||
);
|
||||
}
|
||||
|
||||
protected render() {
|
||||
if (
|
||||
!this._config ||
|
||||
!this.hass ||
|
||||
!this.context ||
|
||||
!supportsMediaPlayerPlaybackCardFeature(this.hass, this.context) ||
|
||||
!this._stateObj
|
||||
!this._stateObj ||
|
||||
!supportsMediaPlayerPlaybackCardFeatureFromState(this._stateObj)
|
||||
) {
|
||||
return nothing;
|
||||
}
|
||||
@@ -113,9 +122,7 @@ class HuiMediaPlayerPlaybackCardFeature
|
||||
(button) => html`
|
||||
<ha-control-button
|
||||
key=${button.action}
|
||||
.label=${this.hass?.localize(
|
||||
`ui.card.media_player.${button.action}`
|
||||
)}
|
||||
.label=${this._localize(`ui.card.media_player.${button.action}`)}
|
||||
.disabled=${button.disabled}
|
||||
@click=${this._action}
|
||||
>
|
||||
@@ -166,7 +173,7 @@ class HuiMediaPlayerPlaybackCardFeature
|
||||
if (!action) return;
|
||||
|
||||
if (action === "volume_mute") {
|
||||
this.hass!.callService("media_player", "volume_mute", {
|
||||
this._api.callService("media_player", "volume_mute", {
|
||||
entity_id: this._stateObj.entity_id,
|
||||
is_volume_muted: !this._stateObj.attributes.is_volume_muted,
|
||||
});
|
||||
@@ -174,7 +181,7 @@ class HuiMediaPlayerPlaybackCardFeature
|
||||
}
|
||||
|
||||
if (action === "shuffle") {
|
||||
this.hass!.callService("media_player", "shuffle_set", {
|
||||
this._api.callService("media_player", "shuffle_set", {
|
||||
entity_id: this._stateObj.entity_id,
|
||||
shuffle: !this._stateObj.attributes.shuffle,
|
||||
});
|
||||
@@ -183,14 +190,14 @@ class HuiMediaPlayerPlaybackCardFeature
|
||||
|
||||
if (action === "repeat") {
|
||||
const repeat = this._stateObj.attributes.repeat ?? "off";
|
||||
this.hass!.callService("media_player", "repeat_set", {
|
||||
this._api.callService("media_player", "repeat_set", {
|
||||
entity_id: this._stateObj.entity_id,
|
||||
repeat: repeat === "off" ? "one" : repeat === "one" ? "all" : "off",
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
this.hass!.callService("media_player", action, {
|
||||
this._api.callService("media_player", action, {
|
||||
entity_id: this._stateObj.entity_id,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import type { PropertyValues } from "lit";
|
||||
import type { HassEntity } from "home-assistant-js-websocket";
|
||||
import { customElement } from "lit/decorators";
|
||||
import { computeDomain } from "../../../common/entity/compute_domain";
|
||||
import { supportsFeature } from "../../../common/entity/supports-feature";
|
||||
@@ -15,6 +16,17 @@ import type {
|
||||
MediaPlayerSoundModeCardFeatureConfig,
|
||||
} from "./types";
|
||||
|
||||
const supportsMediaPlayerSoundModeCardFeatureFromState = (
|
||||
stateObj: HassEntity
|
||||
) => {
|
||||
const domain = computeDomain(stateObj.entity_id);
|
||||
return (
|
||||
domain === "media_player" &&
|
||||
supportsFeature(stateObj, MediaPlayerEntityFeature.SELECT_SOUND_MODE) &&
|
||||
!!stateObj.attributes.sound_mode_list?.length
|
||||
);
|
||||
};
|
||||
|
||||
export const supportsMediaPlayerSoundModeCardFeature = (
|
||||
hass: HomeAssistant,
|
||||
context: LovelaceCardFeatureContext
|
||||
@@ -23,12 +35,7 @@ export const supportsMediaPlayerSoundModeCardFeature = (
|
||||
? hass.states[context.entity_id]
|
||||
: undefined;
|
||||
if (!stateObj) return false;
|
||||
const domain = computeDomain(stateObj.entity_id);
|
||||
return (
|
||||
domain === "media_player" &&
|
||||
supportsFeature(stateObj, MediaPlayerEntityFeature.SELECT_SOUND_MODE) &&
|
||||
!!stateObj.attributes.sound_mode_list?.length
|
||||
);
|
||||
return supportsMediaPlayerSoundModeCardFeatureFromState(stateObj);
|
||||
};
|
||||
|
||||
@customElement("hui-media-player-sound-mode-card-feature")
|
||||
@@ -48,7 +55,7 @@ class HuiMediaPlayerSoundModeCardFeature
|
||||
protected readonly _serviceAction = "select_sound_mode";
|
||||
|
||||
protected get _label(): string {
|
||||
return this.hass!.localize("ui.card.media_player.sound_mode");
|
||||
return this._localize("ui.card.media_player.sound_mode");
|
||||
}
|
||||
|
||||
protected readonly _hideLabel = false;
|
||||
@@ -76,25 +83,18 @@ class HuiMediaPlayerSoundModeCardFeature
|
||||
}
|
||||
|
||||
protected shouldUpdate(changedProps: PropertyValues): boolean {
|
||||
const entityId = this.context?.entity_id;
|
||||
const oldHass = changedProps.get("hass") as HomeAssistant | undefined;
|
||||
|
||||
return (
|
||||
changedProps.has("_currentValue") ||
|
||||
changedProps.has("context") ||
|
||||
hasConfigChanged(this, changedProps) ||
|
||||
(changedProps.has("hass") &&
|
||||
(!oldHass ||
|
||||
!entityId ||
|
||||
oldHass.states[entityId] !== this.hass?.states[entityId]))
|
||||
changedProps.has("_stateObj") ||
|
||||
hasConfigChanged(this, changedProps)
|
||||
);
|
||||
}
|
||||
|
||||
protected _isSupported(): boolean {
|
||||
return !!(
|
||||
this.hass &&
|
||||
this.context &&
|
||||
supportsMediaPlayerSoundModeCardFeature(this.hass, this.context)
|
||||
this._stateObj &&
|
||||
supportsMediaPlayerSoundModeCardFeatureFromState(this._stateObj)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import type { PropertyValues } from "lit";
|
||||
import type { HassEntity } from "home-assistant-js-websocket";
|
||||
import { customElement } from "lit/decorators";
|
||||
import { computeDomain } from "../../../common/entity/compute_domain";
|
||||
import { supportsFeature } from "../../../common/entity/supports-feature";
|
||||
@@ -15,6 +16,16 @@ import type {
|
||||
MediaPlayerSourceCardFeatureConfig,
|
||||
} from "./types";
|
||||
|
||||
const supportsMediaPlayerSourceCardFeatureFromState = (
|
||||
stateObj: HassEntity
|
||||
) => {
|
||||
const domain = computeDomain(stateObj.entity_id);
|
||||
return (
|
||||
domain === "media_player" &&
|
||||
supportsFeature(stateObj, MediaPlayerEntityFeature.SELECT_SOURCE)
|
||||
);
|
||||
};
|
||||
|
||||
export const supportsMediaPlayerSourceCardFeature = (
|
||||
hass: HomeAssistant,
|
||||
context: LovelaceCardFeatureContext
|
||||
@@ -23,11 +34,7 @@ export const supportsMediaPlayerSourceCardFeature = (
|
||||
? hass.states[context.entity_id]
|
||||
: undefined;
|
||||
if (!stateObj) return false;
|
||||
const domain = computeDomain(stateObj.entity_id);
|
||||
return (
|
||||
domain === "media_player" &&
|
||||
supportsFeature(stateObj, MediaPlayerEntityFeature.SELECT_SOURCE)
|
||||
);
|
||||
return supportsMediaPlayerSourceCardFeatureFromState(stateObj);
|
||||
};
|
||||
|
||||
@customElement("hui-media-player-source-card-feature")
|
||||
@@ -52,7 +59,7 @@ class HuiMediaPlayerSourceCardFeature
|
||||
protected readonly _serviceAction = "select_source";
|
||||
|
||||
protected get _label(): string {
|
||||
return this.hass!.localize("ui.card.media_player.source");
|
||||
return this._localize("ui.card.media_player.source");
|
||||
}
|
||||
|
||||
protected readonly _hideLabel = false;
|
||||
@@ -75,25 +82,18 @@ class HuiMediaPlayerSourceCardFeature
|
||||
}
|
||||
|
||||
protected shouldUpdate(changedProps: PropertyValues): boolean {
|
||||
const entityId = this.context?.entity_id;
|
||||
const oldHass = changedProps.get("hass") as HomeAssistant | undefined;
|
||||
|
||||
return (
|
||||
changedProps.has("_currentValue") ||
|
||||
changedProps.has("context") ||
|
||||
hasConfigChanged(this, changedProps) ||
|
||||
(changedProps.has("hass") &&
|
||||
(!oldHass ||
|
||||
!entityId ||
|
||||
oldHass.states[entityId] !== this.hass?.states[entityId]))
|
||||
changedProps.has("_stateObj") ||
|
||||
hasConfigChanged(this, changedProps)
|
||||
);
|
||||
}
|
||||
|
||||
protected _isSupported(): boolean {
|
||||
return !!(
|
||||
this.hass &&
|
||||
this.context &&
|
||||
supportsMediaPlayerSourceCardFeature(this.hass, this.context)
|
||||
this._stateObj &&
|
||||
supportsMediaPlayerSourceCardFeatureFromState(this._stateObj)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,15 +1,29 @@
|
||||
import { consume } from "@lit/context";
|
||||
import type { HassEntity } from "home-assistant-js-websocket";
|
||||
import { css, html, LitElement, nothing } from "lit";
|
||||
import { customElement, property, state } from "lit/decorators";
|
||||
import {
|
||||
consumeEntityState,
|
||||
consumeLocalize,
|
||||
} from "../../../common/decorators/consume-context-entry";
|
||||
import { transform } from "../../../common/decorators/transform";
|
||||
import { computeDomain } from "../../../common/entity/compute_domain";
|
||||
import { supportsFeature } from "../../../common/entity/supports-feature";
|
||||
import { clamp } from "../../../common/number/clamp";
|
||||
import type { LocalizeFunc } from "../../../common/translations/localize";
|
||||
import "../../../components/ha-control-number-buttons";
|
||||
import { apiContext, internationalizationContext } from "../../../data/context";
|
||||
import { UNAVAILABLE } from "../../../data/entity/entity";
|
||||
import {
|
||||
MediaPlayerEntityFeature,
|
||||
type MediaPlayerEntity,
|
||||
} from "../../../data/media-player";
|
||||
import type { HomeAssistant } from "../../../types";
|
||||
import type { FrontendLocaleData } from "../../../data/translation";
|
||||
import type {
|
||||
HomeAssistant,
|
||||
HomeAssistantApi,
|
||||
HomeAssistantInternationalization,
|
||||
} from "../../../types";
|
||||
import type { LovelaceCardFeature, LovelaceCardFeatureEditor } from "../types";
|
||||
import { cardFeatureStyles } from "./common/card-feature-styles";
|
||||
import {
|
||||
@@ -21,6 +35,16 @@ import type {
|
||||
MediaPlayerVolumeButtonsCardFeatureConfig,
|
||||
} from "./types";
|
||||
|
||||
const supportsMediaPlayerVolumeButtonsCardFeatureFromState = (
|
||||
stateObj: HassEntity
|
||||
) => {
|
||||
const domain = computeDomain(stateObj.entity_id);
|
||||
return (
|
||||
domain === "media_player" &&
|
||||
supportsFeature(stateObj, MediaPlayerEntityFeature.VOLUME_SET)
|
||||
);
|
||||
};
|
||||
|
||||
export const supportsMediaPlayerVolumeButtonsCardFeature = (
|
||||
hass: HomeAssistant,
|
||||
context: LovelaceCardFeatureContext
|
||||
@@ -29,11 +53,7 @@ export const supportsMediaPlayerVolumeButtonsCardFeature = (
|
||||
? hass.states[context.entity_id]
|
||||
: undefined;
|
||||
if (!stateObj) return false;
|
||||
const domain = computeDomain(stateObj.entity_id);
|
||||
return (
|
||||
domain === "media_player" &&
|
||||
supportsFeature(stateObj, MediaPlayerEntityFeature.VOLUME_SET)
|
||||
);
|
||||
return supportsMediaPlayerVolumeButtonsCardFeatureFromState(stateObj);
|
||||
};
|
||||
|
||||
@customElement("hui-media-player-volume-buttons-card-feature")
|
||||
@@ -41,19 +61,28 @@ class HuiMediaPlayerVolumeButtonsCardFeature
|
||||
extends LitElement
|
||||
implements LovelaceCardFeature
|
||||
{
|
||||
@property({ attribute: false }) public hass?: HomeAssistant;
|
||||
|
||||
@property({ attribute: false }) public context?: LovelaceCardFeatureContext;
|
||||
|
||||
@state() private _config?: MediaPlayerVolumeButtonsCardFeatureConfig;
|
||||
@state()
|
||||
@consumeEntityState({ entityIdPath: ["context", "entity_id"] })
|
||||
private _stateObj?: MediaPlayerEntity;
|
||||
|
||||
private get _stateObj() {
|
||||
if (!this.hass || !this.context || !this.context.entity_id) {
|
||||
return undefined;
|
||||
}
|
||||
return this.hass.states[this.context.entity_id] as
|
||||
MediaPlayerEntity | undefined;
|
||||
}
|
||||
@state()
|
||||
@consumeLocalize()
|
||||
private _localize!: LocalizeFunc;
|
||||
|
||||
@state()
|
||||
@consume({ context: apiContext, subscribe: true })
|
||||
private _api!: HomeAssistantApi;
|
||||
|
||||
@state()
|
||||
@consume({ context: internationalizationContext, subscribe: true })
|
||||
@transform<HomeAssistantInternationalization, FrontendLocaleData>({
|
||||
transformer: ({ locale }) => locale,
|
||||
})
|
||||
private _locale?: FrontendLocaleData;
|
||||
|
||||
@state() private _config?: MediaPlayerVolumeButtonsCardFeatureConfig;
|
||||
|
||||
static getStubConfig(): MediaPlayerVolumeButtonsCardFeatureConfig {
|
||||
return {
|
||||
@@ -79,10 +108,9 @@ class HuiMediaPlayerVolumeButtonsCardFeature
|
||||
protected render() {
|
||||
if (
|
||||
!this._config ||
|
||||
!this.hass ||
|
||||
!this.context ||
|
||||
!this._stateObj ||
|
||||
!supportsMediaPlayerVolumeButtonsCardFeature(this.hass, this.context)
|
||||
!supportsMediaPlayerVolumeButtonsCardFeatureFromState(this._stateObj)
|
||||
) {
|
||||
return nothing;
|
||||
}
|
||||
@@ -98,7 +126,7 @@ class HuiMediaPlayerVolumeButtonsCardFeature
|
||||
return html`
|
||||
<ha-control-number-buttons
|
||||
.disabled=${disabled}
|
||||
.locale=${this.hass.locale}
|
||||
.locale=${this._locale}
|
||||
min="0"
|
||||
max="100"
|
||||
.step=${this._config.step ?? 5}
|
||||
@@ -107,7 +135,7 @@ class HuiMediaPlayerVolumeButtonsCardFeature
|
||||
@value-changed=${this._valueChanged}
|
||||
></ha-control-number-buttons>
|
||||
${renderMuteButton(
|
||||
this.hass,
|
||||
this._localize,
|
||||
stateObj,
|
||||
this._config.show_mute_button,
|
||||
disabled,
|
||||
@@ -119,14 +147,14 @@ class HuiMediaPlayerVolumeButtonsCardFeature
|
||||
private _valueChanged(ev: CustomEvent) {
|
||||
ev.stopPropagation();
|
||||
|
||||
this.hass!.callService("media_player", "volume_set", {
|
||||
this._api.callService("media_player", "volume_set", {
|
||||
entity_id: this._stateObj!.entity_id,
|
||||
volume_level: clamp(ev.detail.value, 0, 100) / 100,
|
||||
});
|
||||
}
|
||||
|
||||
private _toggleMute = (ev: Event) => {
|
||||
toggleMediaPlayerMute(ev, this.hass!, this._stateObj!, this);
|
||||
toggleMediaPlayerMute(ev, this._api!.callService, this._stateObj!, this);
|
||||
};
|
||||
|
||||
static get styles() {
|
||||
|
||||
@@ -1,15 +1,29 @@
|
||||
import { consume } from "@lit/context";
|
||||
import type { HassEntity } from "home-assistant-js-websocket";
|
||||
import { css, html, LitElement, nothing } from "lit";
|
||||
import { customElement, property, state } from "lit/decorators";
|
||||
import {
|
||||
consumeEntityState,
|
||||
consumeLocalize,
|
||||
} from "../../../common/decorators/consume-context-entry";
|
||||
import { transform } from "../../../common/decorators/transform";
|
||||
import { computeDomain } from "../../../common/entity/compute_domain";
|
||||
import { stateActive } from "../../../common/entity/state_active";
|
||||
import { supportsFeature } from "../../../common/entity/supports-feature";
|
||||
import type { LocalizeFunc } from "../../../common/translations/localize";
|
||||
import "../../../components/ha-control-slider";
|
||||
import { apiContext, internationalizationContext } from "../../../data/context";
|
||||
import { UNAVAILABLE } from "../../../data/entity/entity";
|
||||
import {
|
||||
MediaPlayerEntityFeature,
|
||||
type MediaPlayerEntity,
|
||||
} from "../../../data/media-player";
|
||||
import type { HomeAssistant } from "../../../types";
|
||||
import type { FrontendLocaleData } from "../../../data/translation";
|
||||
import type {
|
||||
HomeAssistant,
|
||||
HomeAssistantApi,
|
||||
HomeAssistantInternationalization,
|
||||
} from "../../../types";
|
||||
import type { LovelaceCardFeature, LovelaceCardFeatureEditor } from "../types";
|
||||
import { cardFeatureStyles } from "./common/card-feature-styles";
|
||||
import {
|
||||
@@ -21,6 +35,16 @@ import type {
|
||||
MediaPlayerVolumeSliderCardFeatureConfig,
|
||||
} from "./types";
|
||||
|
||||
const supportsMediaPlayerVolumeSliderCardFeatureFromState = (
|
||||
stateObj: HassEntity
|
||||
) => {
|
||||
const domain = computeDomain(stateObj.entity_id);
|
||||
return (
|
||||
domain === "media_player" &&
|
||||
supportsFeature(stateObj, MediaPlayerEntityFeature.VOLUME_SET)
|
||||
);
|
||||
};
|
||||
|
||||
export const supportsMediaPlayerVolumeSliderCardFeature = (
|
||||
hass: HomeAssistant,
|
||||
context: LovelaceCardFeatureContext
|
||||
@@ -29,11 +53,7 @@ export const supportsMediaPlayerVolumeSliderCardFeature = (
|
||||
? hass.states[context.entity_id]
|
||||
: undefined;
|
||||
if (!stateObj) return false;
|
||||
const domain = computeDomain(stateObj.entity_id);
|
||||
return (
|
||||
domain === "media_player" &&
|
||||
supportsFeature(stateObj, MediaPlayerEntityFeature.VOLUME_SET)
|
||||
);
|
||||
return supportsMediaPlayerVolumeSliderCardFeatureFromState(stateObj);
|
||||
};
|
||||
|
||||
@customElement("hui-media-player-volume-slider-card-feature")
|
||||
@@ -41,19 +61,28 @@ class HuiMediaPlayerVolumeSliderCardFeature
|
||||
extends LitElement
|
||||
implements LovelaceCardFeature
|
||||
{
|
||||
@property({ attribute: false }) public hass?: HomeAssistant;
|
||||
|
||||
@property({ attribute: false }) public context?: LovelaceCardFeatureContext;
|
||||
|
||||
@state() private _config?: MediaPlayerVolumeSliderCardFeatureConfig;
|
||||
@state()
|
||||
@consumeEntityState({ entityIdPath: ["context", "entity_id"] })
|
||||
private _stateObj?: MediaPlayerEntity;
|
||||
|
||||
private get _stateObj() {
|
||||
if (!this.hass || !this.context || !this.context.entity_id) {
|
||||
return undefined;
|
||||
}
|
||||
return this.hass.states[this.context.entity_id!] as
|
||||
MediaPlayerEntity | undefined;
|
||||
}
|
||||
@state()
|
||||
@consumeLocalize()
|
||||
private _localize!: LocalizeFunc;
|
||||
|
||||
@state()
|
||||
@consume({ context: apiContext, subscribe: true })
|
||||
private _api!: HomeAssistantApi;
|
||||
|
||||
@state()
|
||||
@consume({ context: internationalizationContext, subscribe: true })
|
||||
@transform<HomeAssistantInternationalization, FrontendLocaleData>({
|
||||
transformer: ({ locale }) => locale,
|
||||
})
|
||||
private _locale?: FrontendLocaleData;
|
||||
|
||||
@state() private _config?: MediaPlayerVolumeSliderCardFeatureConfig;
|
||||
|
||||
static getStubConfig(): MediaPlayerVolumeSliderCardFeatureConfig {
|
||||
return {
|
||||
@@ -78,10 +107,9 @@ class HuiMediaPlayerVolumeSliderCardFeature
|
||||
protected render() {
|
||||
if (
|
||||
!this._config ||
|
||||
!this.hass ||
|
||||
!this.context ||
|
||||
!this._stateObj ||
|
||||
!supportsMediaPlayerVolumeSliderCardFeature(this.hass, this.context)
|
||||
!supportsMediaPlayerVolumeSliderCardFeatureFromState(this._stateObj)
|
||||
) {
|
||||
return nothing;
|
||||
}
|
||||
@@ -103,10 +131,10 @@ class HuiMediaPlayerVolumeSliderCardFeature
|
||||
.disabled=${disabled}
|
||||
@value-changed=${this._valueChanged}
|
||||
unit="%"
|
||||
.locale=${this.hass.locale}
|
||||
.locale=${this._locale}
|
||||
></ha-control-slider>
|
||||
${renderMuteButton(
|
||||
this.hass,
|
||||
this._localize,
|
||||
stateObj,
|
||||
this._config.show_mute_button,
|
||||
disabled,
|
||||
@@ -119,14 +147,14 @@ class HuiMediaPlayerVolumeSliderCardFeature
|
||||
ev.stopPropagation();
|
||||
const value = ev.detail.value;
|
||||
|
||||
this.hass!.callService("media_player", "volume_set", {
|
||||
this._api.callService("media_player", "volume_set", {
|
||||
entity_id: this._stateObj!.entity_id,
|
||||
volume_level: value / 100,
|
||||
});
|
||||
}
|
||||
|
||||
private _toggleMute = (ev: Event) => {
|
||||
toggleMediaPlayerMute(ev, this.hass!, this._stateObj!, this);
|
||||
toggleMediaPlayerMute(ev, this._api!.callService, this._stateObj!, this);
|
||||
};
|
||||
|
||||
static get styles() {
|
||||
|
||||
@@ -1,14 +1,21 @@
|
||||
import { consume } from "@lit/context";
|
||||
import type { HassEntity } from "home-assistant-js-websocket";
|
||||
import type { PropertyValues, TemplateResult } from "lit";
|
||||
import { html, LitElement, nothing } from "lit";
|
||||
import { property, state } from "lit/decorators";
|
||||
import { styleMap } from "lit/directives/style-map";
|
||||
import {
|
||||
consumeEntityState,
|
||||
consumeLocalize,
|
||||
} from "../../../common/decorators/consume-context-entry";
|
||||
import type { LocalizeFunc } from "../../../common/translations/localize";
|
||||
import "../../../components/ha-attribute-icon";
|
||||
import "../../../components/ha-control-select";
|
||||
import "../../../components/ha-control-select-menu";
|
||||
import "../../../components/ha-svg-icon";
|
||||
import { apiContext, formattersContext } from "../../../data/context";
|
||||
import { UNAVAILABLE } from "../../../data/entity/entity";
|
||||
import type { HomeAssistant } from "../../../types";
|
||||
import type { HomeAssistantApi, HomeAssistantFormatters } from "../../../types";
|
||||
import type { LovelaceCardFeature } from "../types";
|
||||
import { cardFeatureStyles } from "./common/card-feature-styles";
|
||||
import { filterModes } from "./common/filter-modes";
|
||||
@@ -38,10 +45,24 @@ export abstract class HuiModeSelectCardFeatureBase<
|
||||
extends LitElement
|
||||
implements LovelaceCardFeature
|
||||
{
|
||||
@property({ attribute: false }) public hass?: HomeAssistant;
|
||||
|
||||
@property({ attribute: false }) public context?: LovelaceCardFeatureContext;
|
||||
|
||||
@state()
|
||||
@consumeEntityState({ entityIdPath: ["context", "entity_id"] })
|
||||
protected _stateObj?: TEntity;
|
||||
|
||||
@state()
|
||||
@consumeLocalize()
|
||||
protected _localize!: LocalizeFunc;
|
||||
|
||||
@state()
|
||||
@consume({ context: apiContext, subscribe: true })
|
||||
protected _api!: HomeAssistantApi;
|
||||
|
||||
@state()
|
||||
@consume({ context: formattersContext, subscribe: true })
|
||||
protected _formatters!: HomeAssistantFormatters;
|
||||
|
||||
@state() protected _config?: TConfig;
|
||||
|
||||
@state() protected _currentValue?: string;
|
||||
@@ -63,7 +84,7 @@ export abstract class HuiModeSelectCardFeatureBase<
|
||||
protected abstract _isSupported(): boolean;
|
||||
|
||||
protected get _label(): string {
|
||||
return this.hass!.formatEntityAttributeName(
|
||||
return this._formatters.formatEntityAttributeName(
|
||||
this._stateObj!,
|
||||
this._attribute
|
||||
);
|
||||
@@ -90,14 +111,6 @@ export abstract class HuiModeSelectCardFeatureBase<
|
||||
return true;
|
||||
}
|
||||
|
||||
protected get _stateObj(): TEntity | undefined {
|
||||
if (!this.hass || !this.context?.entity_id) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
return this.hass.states[this.context.entity_id] as TEntity | undefined;
|
||||
}
|
||||
|
||||
public setConfig(config: TConfig): void {
|
||||
if (!config) {
|
||||
throw new Error("Invalid configuration");
|
||||
@@ -106,28 +119,17 @@ export abstract class HuiModeSelectCardFeatureBase<
|
||||
this._config = config;
|
||||
}
|
||||
|
||||
protected willUpdate(changedProps: PropertyValues<this>): void {
|
||||
protected willUpdate(changedProps: PropertyValues): void {
|
||||
super.willUpdate(changedProps);
|
||||
|
||||
if (
|
||||
(changedProps.has("hass") || changedProps.has("context")) &&
|
||||
this._stateObj
|
||||
) {
|
||||
const oldHass = changedProps.get("hass") as HomeAssistant | undefined;
|
||||
const oldStateObj = this.context?.entity_id
|
||||
? (oldHass?.states[this.context.entity_id] as TEntity | undefined)
|
||||
: undefined;
|
||||
|
||||
if (oldStateObj !== this._stateObj) {
|
||||
this._currentValue = this._getValue(this._stateObj);
|
||||
}
|
||||
if (changedProps.has("_stateObj") && this._stateObj) {
|
||||
this._currentValue = this._getValue(this._stateObj);
|
||||
}
|
||||
}
|
||||
|
||||
protected render(): TemplateResult | null {
|
||||
if (
|
||||
!this._config ||
|
||||
!this.hass ||
|
||||
!this.context ||
|
||||
!this._stateObj ||
|
||||
!this._isSupported()
|
||||
@@ -191,7 +193,7 @@ export abstract class HuiModeSelectCardFeatureBase<
|
||||
}
|
||||
|
||||
protected _getOptions(): HuiModeSelectOption[] {
|
||||
if (!this._stateObj || !this.hass) {
|
||||
if (!this._stateObj) {
|
||||
return [];
|
||||
}
|
||||
|
||||
@@ -200,7 +202,7 @@ export abstract class HuiModeSelectCardFeatureBase<
|
||||
this._configuredModes
|
||||
).map((mode) => ({
|
||||
value: mode,
|
||||
label: this.hass!.formatEntityAttributeValue(
|
||||
label: this._formatters.formatEntityAttributeValue(
|
||||
this._stateObj!,
|
||||
this._attribute,
|
||||
mode
|
||||
@@ -225,7 +227,7 @@ export abstract class HuiModeSelectCardFeatureBase<
|
||||
></ha-attribute-icon>`;
|
||||
|
||||
private async _valueChanged(ev: AttributeModeChangeEvent) {
|
||||
if (!this.hass || !this._stateObj) {
|
||||
if (!this._stateObj) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -243,7 +245,7 @@ export abstract class HuiModeSelectCardFeatureBase<
|
||||
this._currentValue = value;
|
||||
|
||||
try {
|
||||
await this.hass.callService(
|
||||
await this._api.callService(
|
||||
this._getServiceDomain(this._stateObj),
|
||||
this._serviceAction,
|
||||
{
|
||||
|
||||
@@ -1,22 +1,40 @@
|
||||
import { consume } from "@lit/context";
|
||||
import { ResizeController } from "@lit-labs/observers/resize-controller";
|
||||
import type { HassEntity, UnsubscribeFunc } from "home-assistant-js-websocket";
|
||||
import type {
|
||||
Connection,
|
||||
HassEntity,
|
||||
UnsubscribeFunc,
|
||||
} from "home-assistant-js-websocket";
|
||||
import type { PropertyValues, TemplateResult } from "lit";
|
||||
import { css, html, LitElement } from "lit";
|
||||
import { property, state } from "lit/decorators";
|
||||
import { styleMap } from "lit/directives/style-map";
|
||||
import { computeCssColor } from "../../../common/color/compute-color";
|
||||
import {
|
||||
consumeEntityState,
|
||||
consumeLocalize,
|
||||
} from "../../../common/decorators/consume-context-entry";
|
||||
import { transform } from "../../../common/decorators/transform";
|
||||
import type { HASSDomEvent } from "../../../common/dom/fire_event";
|
||||
import { computeDomain } from "../../../common/entity/compute_domain";
|
||||
import { stateColorCss } from "../../../common/entity/state_color";
|
||||
import type { LocalizeKeys } from "../../../common/translations/localize";
|
||||
import type {
|
||||
LocalizeFunc,
|
||||
LocalizeKeys,
|
||||
} from "../../../common/translations/localize";
|
||||
import "../../../components/ha-control-select";
|
||||
import { apiContext, connectionContext } from "../../../data/context";
|
||||
import { UNAVAILABLE } from "../../../data/entity/entity";
|
||||
import type { ExtEntityRegistryEntry } from "../../../data/entity/entity_registry";
|
||||
import {
|
||||
getExtendedEntityRegistryEntry,
|
||||
subscribeEntityRegistry,
|
||||
} from "../../../data/entity/entity_registry";
|
||||
import type { HomeAssistant } from "../../../types";
|
||||
import type {
|
||||
HomeAssistant,
|
||||
HomeAssistantApi,
|
||||
HomeAssistantConnection,
|
||||
} from "../../../types";
|
||||
import type { LovelaceCardFeature } from "../types";
|
||||
import { cardFeatureStyles } from "./common/card-feature-styles";
|
||||
import type {
|
||||
@@ -50,6 +68,15 @@ export interface NumericFavoriteCardFeatureDefinition<
|
||||
featureLabelKey: LocalizeKeys;
|
||||
}
|
||||
|
||||
const supportsNumericFavoriteCardFeatureFromState = <
|
||||
TEntity extends NumericFavoriteEntity,
|
||||
>(
|
||||
stateObj: TEntity,
|
||||
definition: NumericFavoriteCardFeatureDefinition<TEntity>
|
||||
) =>
|
||||
computeDomain(stateObj.entity_id) === definition.domain &&
|
||||
definition.supportsPosition(stateObj);
|
||||
|
||||
export const supportsNumericFavoriteCardFeature = <
|
||||
TEntity extends NumericFavoriteEntity,
|
||||
>(
|
||||
@@ -65,10 +92,7 @@ export const supportsNumericFavoriteCardFeature = <
|
||||
return false;
|
||||
}
|
||||
|
||||
return (
|
||||
computeDomain(stateObj.entity_id) === definition.domain &&
|
||||
definition.supportsPosition(stateObj)
|
||||
);
|
||||
return supportsNumericFavoriteCardFeatureFromState(stateObj, definition);
|
||||
};
|
||||
|
||||
export abstract class HuiNumericFavoriteCardFeatureBase<
|
||||
@@ -78,12 +102,29 @@ export abstract class HuiNumericFavoriteCardFeatureBase<
|
||||
extends LitElement
|
||||
implements LovelaceCardFeature
|
||||
{
|
||||
@property({ attribute: false }) public hass?: HomeAssistant;
|
||||
|
||||
@property({ attribute: false }) public context?: LovelaceCardFeatureContext;
|
||||
|
||||
@property({ attribute: false }) public color?: string;
|
||||
|
||||
@state()
|
||||
@consumeEntityState({ entityIdPath: ["context", "entity_id"] })
|
||||
protected _stateObj?: TEntity;
|
||||
|
||||
@state()
|
||||
@consumeLocalize()
|
||||
protected _localize!: LocalizeFunc;
|
||||
|
||||
@state()
|
||||
@consume({ context: apiContext, subscribe: true })
|
||||
protected _api!: HomeAssistantApi;
|
||||
|
||||
@state()
|
||||
@consume({ context: connectionContext, subscribe: true })
|
||||
@transform<HomeAssistantConnection, Connection>({
|
||||
transformer: ({ connection }) => connection,
|
||||
})
|
||||
protected _connection?: Connection;
|
||||
|
||||
@state() protected _config?: TConfig;
|
||||
|
||||
@state() protected _entry?: ExtEntityRegistryEntry | null;
|
||||
@@ -108,14 +149,6 @@ export abstract class HuiNumericFavoriteCardFeatureBase<
|
||||
|
||||
protected abstract get _definition(): NumericFavoriteCardFeatureDefinition<TEntity>;
|
||||
|
||||
protected get _stateObj(): TEntity | undefined {
|
||||
if (!this.hass || !this.context?.entity_id) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
return this.hass.states[this.context.entity_id] as TEntity | undefined;
|
||||
}
|
||||
|
||||
public connectedCallback() {
|
||||
super.connectedCallback();
|
||||
this._refreshEntitySubscription();
|
||||
@@ -134,38 +167,14 @@ export abstract class HuiNumericFavoriteCardFeatureBase<
|
||||
this._config = config as TConfig;
|
||||
}
|
||||
|
||||
protected willUpdate(changedProp: PropertyValues<this>): void {
|
||||
protected willUpdate(changedProp: PropertyValues): void {
|
||||
super.willUpdate(changedProp);
|
||||
|
||||
if (
|
||||
(changedProp.has("hass") || changedProp.has("context")) &&
|
||||
this._stateObj
|
||||
) {
|
||||
const oldHass = changedProp.get("hass") as HomeAssistant | undefined;
|
||||
const oldStateObj = this.context?.entity_id
|
||||
? (oldHass?.states[this.context.entity_id] as TEntity | undefined)
|
||||
: undefined;
|
||||
|
||||
if (oldStateObj !== this._stateObj) {
|
||||
this._currentPosition = this._definition.getCurrentValue(
|
||||
this._stateObj
|
||||
);
|
||||
}
|
||||
if (changedProp.has("_stateObj") && this._stateObj) {
|
||||
this._currentPosition = this._definition.getCurrentValue(this._stateObj);
|
||||
}
|
||||
|
||||
if (
|
||||
changedProp.has("context") &&
|
||||
(changedProp.get("context") as LovelaceCardFeatureContext | undefined)
|
||||
?.entity_id !== this.context?.entity_id
|
||||
) {
|
||||
this._refreshEntitySubscription();
|
||||
}
|
||||
|
||||
if (
|
||||
changedProp.has("hass") &&
|
||||
(changedProp.get("hass") as HomeAssistant | undefined)?.connection !==
|
||||
this.hass?.connection
|
||||
) {
|
||||
if (changedProp.has("context") || changedProp.has("_connection")) {
|
||||
this._refreshEntitySubscription();
|
||||
}
|
||||
}
|
||||
@@ -182,12 +191,8 @@ export abstract class HuiNumericFavoriteCardFeatureBase<
|
||||
}
|
||||
|
||||
private async _loadEntityEntry(entityId: string): Promise<void> {
|
||||
if (!this.hass) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const entry = await getExtendedEntityRegistryEntry(this.hass, entityId);
|
||||
const entry = await getExtendedEntityRegistryEntry(this._api, entityId);
|
||||
|
||||
if (this.context?.entity_id === entityId) {
|
||||
this._entry = entry;
|
||||
@@ -206,7 +211,7 @@ export abstract class HuiNumericFavoriteCardFeatureBase<
|
||||
|
||||
try {
|
||||
this._unsubEntityRegistry = subscribeEntityRegistry(
|
||||
this.hass!.connection,
|
||||
this._connection!,
|
||||
async (entries) => {
|
||||
if (this.context?.entity_id !== entityId) {
|
||||
return;
|
||||
@@ -227,9 +232,9 @@ export abstract class HuiNumericFavoriteCardFeatureBase<
|
||||
|
||||
private async _ensureEntitySubscription(): Promise<void> {
|
||||
const entityId = this.context?.entity_id;
|
||||
const connection = this.hass?.connection;
|
||||
const connection = this._connection;
|
||||
|
||||
if (!this.hass || !entityId || !connection) {
|
||||
if (!entityId || !connection) {
|
||||
this._unsubscribeEntityRegistry();
|
||||
this._subscribedEntityId = undefined;
|
||||
this._subscribedConnection = undefined;
|
||||
@@ -256,7 +261,7 @@ export abstract class HuiNumericFavoriteCardFeatureBase<
|
||||
) {
|
||||
const value = ev.detail.value;
|
||||
|
||||
if (value == null || !this.hass || !this._stateObj) {
|
||||
if (value == null || !this._stateObj) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -275,7 +280,7 @@ export abstract class HuiNumericFavoriteCardFeatureBase<
|
||||
this._currentPosition = position;
|
||||
|
||||
try {
|
||||
await this.hass.callService(
|
||||
await this._api.callService(
|
||||
this._definition.domain,
|
||||
this._definition.setPositionService,
|
||||
{
|
||||
@@ -291,12 +296,10 @@ export abstract class HuiNumericFavoriteCardFeatureBase<
|
||||
protected render(): TemplateResult | null {
|
||||
if (
|
||||
!this._config ||
|
||||
!this.hass ||
|
||||
!this.context ||
|
||||
!this._stateObj ||
|
||||
!supportsNumericFavoriteCardFeature(
|
||||
this.hass,
|
||||
this.context,
|
||||
!supportsNumericFavoriteCardFeatureFromState(
|
||||
this._stateObj,
|
||||
this._definition
|
||||
)
|
||||
) {
|
||||
@@ -308,9 +311,7 @@ export abstract class HuiNumericFavoriteCardFeatureBase<
|
||||
this._definition.defaultFavoritePositions
|
||||
);
|
||||
|
||||
const hass = this.hass;
|
||||
|
||||
if (positions.length === 0 || !hass) {
|
||||
if (positions.length === 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -321,7 +322,7 @@ export abstract class HuiNumericFavoriteCardFeatureBase<
|
||||
const options = visiblePositions.map((position) => ({
|
||||
value: String(position),
|
||||
label: `${position}%`,
|
||||
ariaLabel: hass.localize(this._definition.setPositionLabelKey, {
|
||||
ariaLabel: this._localize(this._definition.setPositionLabelKey, {
|
||||
value: `${position}%`,
|
||||
}),
|
||||
}));
|
||||
@@ -339,7 +340,7 @@ export abstract class HuiNumericFavoriteCardFeatureBase<
|
||||
.options=${options}
|
||||
.value=${currentValue}
|
||||
@value-changed=${this._valueChanged}
|
||||
.label=${hass.localize(this._definition.featureLabelKey)}
|
||||
.label=${this._localize(this._definition.featureLabelKey)}
|
||||
.disabled=${this._stateObj.state === UNAVAILABLE}
|
||||
>
|
||||
</ha-control-select>
|
||||
|
||||
@@ -1,15 +1,24 @@
|
||||
import { consume } from "@lit/context";
|
||||
import type { HassEntity } from "home-assistant-js-websocket";
|
||||
import type { PropertyValues } from "lit";
|
||||
import { html, LitElement, nothing } from "lit";
|
||||
import { customElement, property, state } from "lit/decorators";
|
||||
import { consumeEntityState } from "../../../common/decorators/consume-context-entry";
|
||||
import { transform } from "../../../common/decorators/transform";
|
||||
import { computeDomain } from "../../../common/entity/compute_domain";
|
||||
import "../../../components/ha-control-button";
|
||||
import "../../../components/ha-control-button-group";
|
||||
import "../../../components/ha-control-number-buttons";
|
||||
import "../../../components/ha-control-slider";
|
||||
import "../../../components/ha-icon";
|
||||
import { apiContext, internationalizationContext } from "../../../data/context";
|
||||
import { UNAVAILABLE } from "../../../data/entity/entity";
|
||||
import type { HomeAssistant } from "../../../types";
|
||||
import type { FrontendLocaleData } from "../../../data/translation";
|
||||
import type {
|
||||
HomeAssistant,
|
||||
HomeAssistantApi,
|
||||
HomeAssistantInternationalization,
|
||||
} from "../../../types";
|
||||
import type { LovelaceCardFeature, LovelaceCardFeatureEditor } from "../types";
|
||||
import { cardFeatureStyles } from "./common/card-feature-styles";
|
||||
import type {
|
||||
@@ -17,6 +26,11 @@ import type {
|
||||
NumericInputCardFeatureConfig,
|
||||
} from "./types";
|
||||
|
||||
const supportsNumericInputCardFeatureFromState = (stateObj: HassEntity) => {
|
||||
const domain = computeDomain(stateObj.entity_id);
|
||||
return domain === "input_number" || domain === "number";
|
||||
};
|
||||
|
||||
export const supportsNumericInputCardFeature = (
|
||||
hass: HomeAssistant,
|
||||
context: LovelaceCardFeatureContext
|
||||
@@ -25,8 +39,7 @@ export const supportsNumericInputCardFeature = (
|
||||
? hass.states[context.entity_id]
|
||||
: undefined;
|
||||
if (!stateObj) return false;
|
||||
const domain = computeDomain(stateObj.entity_id);
|
||||
return domain === "input_number" || domain === "number";
|
||||
return supportsNumericInputCardFeatureFromState(stateObj);
|
||||
};
|
||||
|
||||
@customElement("hui-numeric-input-card-feature")
|
||||
@@ -34,10 +47,23 @@ class HuiNumericInputCardFeature
|
||||
extends LitElement
|
||||
implements LovelaceCardFeature
|
||||
{
|
||||
@property({ attribute: false }) public hass?: HomeAssistant;
|
||||
|
||||
@property({ attribute: false }) public context?: LovelaceCardFeatureContext;
|
||||
|
||||
@state()
|
||||
@consumeEntityState({ entityIdPath: ["context", "entity_id"] })
|
||||
private _stateObj?: HassEntity;
|
||||
|
||||
@state()
|
||||
@consume({ context: apiContext, subscribe: true })
|
||||
private _api!: HomeAssistantApi;
|
||||
|
||||
@state()
|
||||
@consume({ context: internationalizationContext, subscribe: true })
|
||||
@transform<HomeAssistantInternationalization, FrontendLocaleData>({
|
||||
transformer: ({ locale }) => locale,
|
||||
})
|
||||
private _locale?: FrontendLocaleData;
|
||||
|
||||
@state() private _config?: NumericInputCardFeatureConfig;
|
||||
|
||||
@state() _currentState?: string;
|
||||
@@ -49,13 +75,6 @@ class HuiNumericInputCardFeature
|
||||
};
|
||||
}
|
||||
|
||||
private get _stateObj() {
|
||||
if (!this.hass || !this.context || !this.context.entity_id) {
|
||||
return undefined;
|
||||
}
|
||||
return this.hass.states[this.context.entity_id!] as HassEntity | undefined;
|
||||
}
|
||||
|
||||
public static async getConfigElement(): Promise<LovelaceCardFeatureEditor> {
|
||||
await import("../editor/config-elements/hui-numeric-input-card-feature-editor");
|
||||
return document.createElement("hui-numeric-input-card-feature-editor");
|
||||
@@ -68,17 +87,10 @@ class HuiNumericInputCardFeature
|
||||
this._config = config;
|
||||
}
|
||||
|
||||
protected willUpdate(changedProp: PropertyValues<this>): void {
|
||||
protected willUpdate(changedProp: PropertyValues): void {
|
||||
super.willUpdate(changedProp);
|
||||
if (
|
||||
(changedProp.has("hass") || changedProp.has("context")) &&
|
||||
this._stateObj
|
||||
) {
|
||||
const oldHass = changedProp.get("hass") as HomeAssistant | undefined;
|
||||
const oldStateObj = oldHass?.states[this.context!.entity_id!];
|
||||
if (oldStateObj !== this._stateObj) {
|
||||
this._currentState = this._stateObj.state;
|
||||
}
|
||||
if (changedProp.has("_stateObj") && this._stateObj) {
|
||||
this._currentState = this._stateObj.state;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -87,7 +99,7 @@ class HuiNumericInputCardFeature
|
||||
|
||||
const domain = computeDomain(stateObj.entity_id);
|
||||
|
||||
await this.hass!.callService(domain, "set_value", {
|
||||
await this._api.callService(domain, "set_value", {
|
||||
entity_id: stateObj.entity_id,
|
||||
value: ev.detail.value,
|
||||
});
|
||||
@@ -96,10 +108,9 @@ class HuiNumericInputCardFeature
|
||||
protected render() {
|
||||
if (
|
||||
!this._config ||
|
||||
!this.hass ||
|
||||
!this.context ||
|
||||
!this._stateObj ||
|
||||
!supportsNumericInputCardFeature(this.hass, this.context)
|
||||
!supportsNumericInputCardFeatureFromState(this._stateObj)
|
||||
) {
|
||||
return nothing;
|
||||
}
|
||||
@@ -119,7 +130,7 @@ class HuiNumericInputCardFeature
|
||||
@value-changed=${this._setValue}
|
||||
.disabled=${stateObj.state === UNAVAILABLE}
|
||||
.unit=${stateObj.attributes.unit_of_measurement}
|
||||
.locale=${this.hass.locale}
|
||||
.locale=${this._locale}
|
||||
></ha-control-number-buttons>
|
||||
`;
|
||||
}
|
||||
@@ -132,7 +143,7 @@ class HuiNumericInputCardFeature
|
||||
@value-changed=${this._setValue}
|
||||
.disabled=${stateObj.state === UNAVAILABLE}
|
||||
.unit=${stateObj.attributes.unit_of_measurement}
|
||||
.locale=${this.hass.locale}
|
||||
.locale=${this._locale}
|
||||
></ha-control-slider>
|
||||
`;
|
||||
}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import type { HassEntity } from "home-assistant-js-websocket";
|
||||
import { customElement } from "lit/decorators";
|
||||
import { computeDomain } from "../../../common/entity/compute_domain";
|
||||
import type { InputSelectEntity } from "../../../data/input_select";
|
||||
@@ -16,6 +17,11 @@ import type {
|
||||
|
||||
type SelectOptionEntity = SelectEntity | InputSelectEntity;
|
||||
|
||||
const supportsSelectOptionsCardFeatureFromState = (stateObj: HassEntity) => {
|
||||
const domain = computeDomain(stateObj.entity_id);
|
||||
return domain === "select" || domain === "input_select";
|
||||
};
|
||||
|
||||
export const supportsSelectOptionsCardFeature = (
|
||||
hass: HomeAssistant,
|
||||
context: LovelaceCardFeatureContext
|
||||
@@ -24,8 +30,7 @@ export const supportsSelectOptionsCardFeature = (
|
||||
? hass.states[context.entity_id]
|
||||
: undefined;
|
||||
if (!stateObj) return false;
|
||||
const domain = computeDomain(stateObj.entity_id);
|
||||
return domain === "select" || domain === "input_select";
|
||||
return supportsSelectOptionsCardFeatureFromState(stateObj);
|
||||
};
|
||||
|
||||
@customElement("hui-select-options-card-feature")
|
||||
@@ -49,7 +54,7 @@ class HuiSelectOptionsCardFeature
|
||||
protected readonly _serviceAction = "select_option";
|
||||
|
||||
protected get _label(): string {
|
||||
return this.hass!.localize("ui.card.select.option");
|
||||
return this._localize("ui.card.select.option");
|
||||
}
|
||||
|
||||
protected readonly _allowIconsStyle = false;
|
||||
@@ -72,7 +77,7 @@ class HuiSelectOptionsCardFeature
|
||||
}
|
||||
|
||||
protected _getOptions(): HuiModeSelectOption[] {
|
||||
if (!this._stateObj || !this.hass) {
|
||||
if (!this._stateObj) {
|
||||
return [];
|
||||
}
|
||||
|
||||
@@ -81,7 +86,7 @@ class HuiSelectOptionsCardFeature
|
||||
this._config?.options
|
||||
).map((option) => ({
|
||||
value: option,
|
||||
label: this.hass!.formatEntityState(this._stateObj!, option),
|
||||
label: this._formatters.formatEntityState(this._stateObj!, option),
|
||||
}));
|
||||
}
|
||||
|
||||
@@ -98,9 +103,8 @@ class HuiSelectOptionsCardFeature
|
||||
|
||||
protected _isSupported(): boolean {
|
||||
return !!(
|
||||
this.hass &&
|
||||
this.context &&
|
||||
supportsSelectOptionsCardFeature(this.hass, this.context)
|
||||
this._stateObj &&
|
||||
supportsSelectOptionsCardFeatureFromState(this._stateObj)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,12 +1,27 @@
|
||||
import { consume } from "@lit/context";
|
||||
import type { HassEntity } from "home-assistant-js-websocket";
|
||||
import type { PropertyValues } from "lit";
|
||||
import { html, LitElement, nothing } from "lit";
|
||||
import { customElement, property, state } from "lit/decorators";
|
||||
import { consumeEntityState } from "../../../common/decorators/consume-context-entry";
|
||||
import { transform } from "../../../common/decorators/transform";
|
||||
import { computeDomain } from "../../../common/entity/compute_domain";
|
||||
import type { HASSDomEvent } from "../../../common/dom/fire_event";
|
||||
import "../../../components/ha-control-slider";
|
||||
import {
|
||||
apiContext,
|
||||
formattersContext,
|
||||
internationalizationContext,
|
||||
} from "../../../data/context";
|
||||
import { UNAVAILABLE } from "../../../data/entity/entity";
|
||||
import type { HumidifierEntity } from "../../../data/humidifier";
|
||||
import type { HomeAssistant } from "../../../types";
|
||||
import type { FrontendLocaleData } from "../../../data/translation";
|
||||
import type {
|
||||
HomeAssistant,
|
||||
HomeAssistantApi,
|
||||
HomeAssistantFormatters,
|
||||
HomeAssistantInternationalization,
|
||||
} from "../../../types";
|
||||
import type { LovelaceCardFeature } from "../types";
|
||||
import { cardFeatureStyles } from "./common/card-feature-styles";
|
||||
import type {
|
||||
@@ -14,6 +29,11 @@ import type {
|
||||
TargetHumidityCardFeatureConfig,
|
||||
} from "./types";
|
||||
|
||||
const supportsTargetHumidityCardFeatureFromState = (stateObj: HassEntity) => {
|
||||
const domain = computeDomain(stateObj.entity_id);
|
||||
return domain === "humidifier";
|
||||
};
|
||||
|
||||
export const supportsTargetHumidityCardFeature = (
|
||||
hass: HomeAssistant,
|
||||
context: LovelaceCardFeatureContext
|
||||
@@ -22,8 +42,7 @@ export const supportsTargetHumidityCardFeature = (
|
||||
? hass.states[context.entity_id]
|
||||
: undefined;
|
||||
if (!stateObj) return false;
|
||||
const domain = computeDomain(stateObj.entity_id);
|
||||
return domain === "humidifier";
|
||||
return supportsTargetHumidityCardFeatureFromState(stateObj);
|
||||
};
|
||||
|
||||
@customElement("hui-target-humidity-card-feature")
|
||||
@@ -31,22 +50,31 @@ class HuiTargetHumidityCardFeature
|
||||
extends LitElement
|
||||
implements LovelaceCardFeature
|
||||
{
|
||||
@property({ attribute: false }) public hass?: HomeAssistant;
|
||||
|
||||
@property({ attribute: false }) public context?: LovelaceCardFeatureContext;
|
||||
|
||||
@state()
|
||||
@consumeEntityState({ entityIdPath: ["context", "entity_id"] })
|
||||
private _stateObj?: HumidifierEntity;
|
||||
|
||||
@state()
|
||||
@consume({ context: apiContext, subscribe: true })
|
||||
private _api!: HomeAssistantApi;
|
||||
|
||||
@state()
|
||||
@consume({ context: formattersContext, subscribe: true })
|
||||
private _formatters!: HomeAssistantFormatters;
|
||||
|
||||
@state()
|
||||
@consume({ context: internationalizationContext, subscribe: true })
|
||||
@transform<HomeAssistantInternationalization, FrontendLocaleData>({
|
||||
transformer: ({ locale }) => locale,
|
||||
})
|
||||
private _locale?: FrontendLocaleData;
|
||||
|
||||
@state() private _config?: TargetHumidityCardFeatureConfig;
|
||||
|
||||
@state() private _targetHumidity?: number;
|
||||
|
||||
private get _stateObj() {
|
||||
if (!this.hass || !this.context || !this.context.entity_id) {
|
||||
return undefined;
|
||||
}
|
||||
return this.hass.states[this.context.entity_id!] as
|
||||
HumidifierEntity | undefined;
|
||||
}
|
||||
|
||||
static getStubConfig(): TargetHumidityCardFeatureConfig {
|
||||
return {
|
||||
type: "target-humidity",
|
||||
@@ -60,17 +88,10 @@ class HuiTargetHumidityCardFeature
|
||||
this._config = config;
|
||||
}
|
||||
|
||||
protected willUpdate(changedProp: PropertyValues<this>): void {
|
||||
protected willUpdate(changedProp: PropertyValues): void {
|
||||
super.willUpdate(changedProp);
|
||||
if (
|
||||
(changedProp.has("hass") || changedProp.has("context")) &&
|
||||
this._stateObj
|
||||
) {
|
||||
const oldHass = changedProp.get("hass") as HomeAssistant | undefined;
|
||||
const oldStateObj = oldHass?.states[this.context!.entity_id!];
|
||||
if (oldStateObj !== this._stateObj) {
|
||||
this._targetHumidity = this._stateObj!.attributes.humidity;
|
||||
}
|
||||
if (changedProp.has("_stateObj") && this._stateObj) {
|
||||
this._targetHumidity = this._stateObj.attributes.humidity;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -92,7 +113,7 @@ class HuiTargetHumidityCardFeature
|
||||
}
|
||||
|
||||
private _callService() {
|
||||
this.hass!.callService("humidifier", "set_humidity", {
|
||||
this._api.callService("humidifier", "set_humidity", {
|
||||
entity_id: this._stateObj!.entity_id,
|
||||
humidity: this._targetHumidity,
|
||||
});
|
||||
@@ -101,10 +122,9 @@ class HuiTargetHumidityCardFeature
|
||||
protected render() {
|
||||
if (
|
||||
!this._config ||
|
||||
!this.hass ||
|
||||
!this.context ||
|
||||
!this._stateObj ||
|
||||
!supportsTargetHumidityCardFeature(this.hass, this.context)
|
||||
!supportsTargetHumidityCardFeatureFromState(this._stateObj)
|
||||
) {
|
||||
return nothing;
|
||||
}
|
||||
@@ -117,12 +137,12 @@ class HuiTargetHumidityCardFeature
|
||||
.step=${this._step}
|
||||
.disabled=${this._stateObj!.state === UNAVAILABLE}
|
||||
@value-changed=${this._valueChanged}
|
||||
.label=${this.hass.formatEntityAttributeName(
|
||||
.label=${this._formatters.formatEntityAttributeName(
|
||||
this._stateObj,
|
||||
"humidity"
|
||||
)}
|
||||
unit="%"
|
||||
.locale=${this.hass.locale}
|
||||
.locale=${this._locale}
|
||||
></ha-control-slider>
|
||||
`;
|
||||
}
|
||||
|
||||
@@ -1,8 +1,12 @@
|
||||
import { consume } from "@lit/context";
|
||||
import type { HassConfig, HassEntity } from "home-assistant-js-websocket";
|
||||
import type { PropertyValues } from "lit";
|
||||
import { html, LitElement, nothing } from "lit";
|
||||
import { customElement, property, state } from "lit/decorators";
|
||||
import { styleMap } from "lit/directives/style-map";
|
||||
import { UNIT_F } from "../../../common/const";
|
||||
import { consumeEntityState } from "../../../common/decorators/consume-context-entry";
|
||||
import { transform } from "../../../common/decorators/transform";
|
||||
import type { HASSDomEvent } from "../../../common/dom/fire_event";
|
||||
import { computeDomain } from "../../../common/entity/compute_domain";
|
||||
import { computeStateDomain } from "../../../common/entity/compute_state_domain";
|
||||
@@ -13,10 +17,23 @@ import "../../../components/ha-control-button-group";
|
||||
import "../../../components/ha-control-number-buttons";
|
||||
import type { ClimateEntity } from "../../../data/climate";
|
||||
import { ClimateEntityFeature } from "../../../data/climate";
|
||||
import {
|
||||
apiContext,
|
||||
configContext,
|
||||
formattersContext,
|
||||
internationalizationContext,
|
||||
} from "../../../data/context";
|
||||
import { UNAVAILABLE } from "../../../data/entity/entity";
|
||||
import type { FrontendLocaleData } from "../../../data/translation";
|
||||
import type { WaterHeaterEntity } from "../../../data/water_heater";
|
||||
import { WaterHeaterEntityFeature } from "../../../data/water_heater";
|
||||
import type { HomeAssistant } from "../../../types";
|
||||
import type {
|
||||
HomeAssistant,
|
||||
HomeAssistantApi,
|
||||
HomeAssistantConfig,
|
||||
HomeAssistantFormatters,
|
||||
HomeAssistantInternationalization,
|
||||
} from "../../../types";
|
||||
import type { LovelaceCardFeature } from "../types";
|
||||
import { cardFeatureStyles } from "./common/card-feature-styles";
|
||||
import type {
|
||||
@@ -26,14 +43,9 @@ import type {
|
||||
|
||||
type Target = "value" | "low" | "high";
|
||||
|
||||
export const supportsTargetTemperatureCardFeature = (
|
||||
hass: HomeAssistant,
|
||||
context: LovelaceCardFeatureContext
|
||||
const supportsTargetTemperatureCardFeatureFromState = (
|
||||
stateObj: HassEntity
|
||||
) => {
|
||||
const stateObj = context.entity_id
|
||||
? hass.states[context.entity_id]
|
||||
: undefined;
|
||||
if (!stateObj) return false;
|
||||
const domain = computeDomain(stateObj.entity_id);
|
||||
return (
|
||||
(domain === "climate" &&
|
||||
@@ -47,27 +59,54 @@ export const supportsTargetTemperatureCardFeature = (
|
||||
);
|
||||
};
|
||||
|
||||
export const supportsTargetTemperatureCardFeature = (
|
||||
hass: HomeAssistant,
|
||||
context: LovelaceCardFeatureContext
|
||||
) => {
|
||||
const stateObj = context.entity_id
|
||||
? hass.states[context.entity_id]
|
||||
: undefined;
|
||||
if (!stateObj) return false;
|
||||
return supportsTargetTemperatureCardFeatureFromState(stateObj);
|
||||
};
|
||||
|
||||
@customElement("hui-target-temperature-card-feature")
|
||||
class HuiTargetTemperatureCardFeature
|
||||
extends LitElement
|
||||
implements LovelaceCardFeature
|
||||
{
|
||||
@property({ attribute: false }) public hass?: HomeAssistant;
|
||||
|
||||
@property({ attribute: false }) public context?: LovelaceCardFeatureContext;
|
||||
|
||||
@state()
|
||||
@consumeEntityState({ entityIdPath: ["context", "entity_id"] })
|
||||
private _stateObj?: WaterHeaterEntity | ClimateEntity;
|
||||
|
||||
@state()
|
||||
@consume({ context: apiContext, subscribe: true })
|
||||
private _api!: HomeAssistantApi;
|
||||
|
||||
@state()
|
||||
@consume({ context: formattersContext, subscribe: true })
|
||||
private _formatters!: HomeAssistantFormatters;
|
||||
|
||||
@state()
|
||||
@consume({ context: internationalizationContext, subscribe: true })
|
||||
@transform<HomeAssistantInternationalization, FrontendLocaleData>({
|
||||
transformer: ({ locale }) => locale,
|
||||
})
|
||||
private _locale?: FrontendLocaleData;
|
||||
|
||||
@state()
|
||||
@consume({ context: configContext, subscribe: true })
|
||||
@transform<HomeAssistantConfig, HassConfig>({
|
||||
transformer: ({ config }) => config,
|
||||
})
|
||||
private _hassConfig?: HassConfig;
|
||||
|
||||
@state() private _config?: TargetTemperatureCardFeatureConfig;
|
||||
|
||||
@state() private _targetTemperature: Partial<Record<Target, number>> = {};
|
||||
|
||||
private get _stateObj() {
|
||||
if (!this.hass || !this.context || !this.context.entity_id) {
|
||||
return undefined;
|
||||
}
|
||||
return this.hass.states[this.context.entity_id!] as
|
||||
WaterHeaterEntity | ClimateEntity | undefined;
|
||||
}
|
||||
|
||||
static getStubConfig(): TargetTemperatureCardFeatureConfig {
|
||||
return {
|
||||
type: "target-temperature",
|
||||
@@ -81,34 +120,27 @@ class HuiTargetTemperatureCardFeature
|
||||
this._config = config;
|
||||
}
|
||||
|
||||
protected willUpdate(changedProp: PropertyValues<this>): void {
|
||||
protected willUpdate(changedProp: PropertyValues): void {
|
||||
super.willUpdate(changedProp);
|
||||
if (
|
||||
(changedProp.has("hass") || changedProp.has("context")) &&
|
||||
this._stateObj
|
||||
) {
|
||||
const oldHass = changedProp.get("hass") as HomeAssistant | undefined;
|
||||
const oldStateObj = oldHass?.states[this.context!.entity_id!];
|
||||
if (oldStateObj !== this._stateObj) {
|
||||
this._targetTemperature = {
|
||||
value: this._stateObj!.attributes.temperature,
|
||||
low:
|
||||
"target_temp_low" in this._stateObj!.attributes
|
||||
? this._stateObj!.attributes.target_temp_low
|
||||
: undefined,
|
||||
high:
|
||||
"target_temp_high" in this._stateObj!.attributes
|
||||
? this._stateObj!.attributes.target_temp_high
|
||||
: undefined,
|
||||
};
|
||||
}
|
||||
if (changedProp.has("_stateObj") && this._stateObj) {
|
||||
this._targetTemperature = {
|
||||
value: this._stateObj.attributes.temperature,
|
||||
low:
|
||||
"target_temp_low" in this._stateObj.attributes
|
||||
? this._stateObj.attributes.target_temp_low
|
||||
: undefined,
|
||||
high:
|
||||
"target_temp_high" in this._stateObj.attributes
|
||||
? this._stateObj.attributes.target_temp_high
|
||||
: undefined,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
private get _step() {
|
||||
return (
|
||||
this._stateObj!.attributes.target_temp_step ||
|
||||
(this.hass!.config.unit_system.temperature === UNIT_F ? 1 : 0.5)
|
||||
(this._hassConfig?.unit_system.temperature === UNIT_F ? 1 : 0.5)
|
||||
);
|
||||
}
|
||||
|
||||
@@ -143,14 +175,14 @@ class HuiTargetTemperatureCardFeature
|
||||
private _callService(type: string) {
|
||||
const domain = computeStateDomain(this._stateObj!);
|
||||
if (type === "high" || type === "low") {
|
||||
this.hass!.callService(domain, "set_temperature", {
|
||||
this._api.callService(domain, "set_temperature", {
|
||||
entity_id: this._stateObj!.entity_id,
|
||||
target_temp_low: this._targetTemperature.low,
|
||||
target_temp_high: this._targetTemperature.high,
|
||||
});
|
||||
return;
|
||||
}
|
||||
this.hass!.callService(domain, "set_temperature", {
|
||||
this._api.callService(domain, "set_temperature", {
|
||||
entity_id: this._stateObj!.entity_id,
|
||||
temperature: this._targetTemperature.value,
|
||||
});
|
||||
@@ -186,10 +218,9 @@ class HuiTargetTemperatureCardFeature
|
||||
protected render() {
|
||||
if (
|
||||
!this._config ||
|
||||
!this.hass ||
|
||||
!this.context ||
|
||||
!this._stateObj ||
|
||||
!supportsTargetTemperatureCardFeature(this.hass, this.context)
|
||||
!supportsTargetTemperatureCardFeatureFromState(this._stateObj)
|
||||
) {
|
||||
return nothing;
|
||||
}
|
||||
@@ -213,12 +244,12 @@ class HuiTargetTemperatureCardFeature
|
||||
.formatOptions=${options}
|
||||
.target=${"value"}
|
||||
.value=${this._stateObj.attributes.temperature}
|
||||
.unit=${this.hass.config.unit_system.temperature}
|
||||
.unit=${this._hassConfig?.unit_system.temperature}
|
||||
.min=${this._min}
|
||||
.max=${this._max}
|
||||
.step=${this._step}
|
||||
@value-changed=${this._valueChanged}
|
||||
.label=${this.hass.formatEntityAttributeName(
|
||||
.label=${this._formatters.formatEntityAttributeName(
|
||||
this._stateObj,
|
||||
"temperature"
|
||||
)}
|
||||
@@ -226,7 +257,7 @@ class HuiTargetTemperatureCardFeature
|
||||
"--control-number-buttons-focus-color": stateColor,
|
||||
})}
|
||||
.disabled=${this._stateObj!.state === UNAVAILABLE}
|
||||
.locale=${this.hass.locale}
|
||||
.locale=${this._locale}
|
||||
>
|
||||
</ha-control-number-buttons>
|
||||
</ha-control-button-group>
|
||||
@@ -245,7 +276,7 @@ class HuiTargetTemperatureCardFeature
|
||||
.formatOptions=${options}
|
||||
.target=${"low"}
|
||||
.value=${this._targetTemperature.low}
|
||||
.unit=${this.hass.config.unit_system.temperature}
|
||||
.unit=${this._hassConfig?.unit_system.temperature}
|
||||
.min=${this._min}
|
||||
.max=${Math.min(
|
||||
this._max,
|
||||
@@ -253,7 +284,7 @@ class HuiTargetTemperatureCardFeature
|
||||
)}
|
||||
.step=${this._step}
|
||||
@value-changed=${this._valueChanged}
|
||||
.label=${this.hass.formatEntityAttributeName(
|
||||
.label=${this._formatters.formatEntityAttributeName(
|
||||
this._stateObj,
|
||||
"target_temp_low"
|
||||
)}
|
||||
@@ -261,14 +292,14 @@ class HuiTargetTemperatureCardFeature
|
||||
"--control-number-buttons-focus-color": stateColor,
|
||||
})}
|
||||
.disabled=${this._stateObj!.state === UNAVAILABLE}
|
||||
.locale=${this.hass.locale}
|
||||
.locale=${this._locale}
|
||||
>
|
||||
</ha-control-number-buttons>
|
||||
<ha-control-number-buttons
|
||||
.formatOptions=${options}
|
||||
.target=${"high"}
|
||||
.value=${this._targetTemperature.high}
|
||||
.unit=${this.hass.config.unit_system.temperature}
|
||||
.unit=${this._hassConfig?.unit_system.temperature}
|
||||
.min=${Math.max(
|
||||
this._min,
|
||||
this._targetTemperature.low ?? this._min
|
||||
@@ -276,7 +307,7 @@ class HuiTargetTemperatureCardFeature
|
||||
.max=${this._max}
|
||||
.step=${this._step}
|
||||
@value-changed=${this._valueChanged}
|
||||
.label=${this.hass.formatEntityAttributeName(
|
||||
.label=${this._formatters.formatEntityAttributeName(
|
||||
this._stateObj,
|
||||
"target_temp_high"
|
||||
)}
|
||||
@@ -284,7 +315,7 @@ class HuiTargetTemperatureCardFeature
|
||||
"--control-number-buttons-focus-color": stateColor,
|
||||
})}
|
||||
.disabled=${this._stateObj!.state === UNAVAILABLE}
|
||||
.locale=${this.hass.locale}
|
||||
.locale=${this._locale}
|
||||
>
|
||||
</ha-control-number-buttons>
|
||||
</ha-control-button-group>
|
||||
@@ -295,15 +326,15 @@ class HuiTargetTemperatureCardFeature
|
||||
<ha-control-button-group>
|
||||
<ha-control-number-buttons
|
||||
.disabled=${this._stateObj!.state === UNAVAILABLE}
|
||||
.unit=${this.hass.config.unit_system.temperature}
|
||||
.label=${this.hass.formatEntityAttributeName(
|
||||
.unit=${this._hassConfig?.unit_system.temperature}
|
||||
.label=${this._formatters.formatEntityAttributeName(
|
||||
this._stateObj,
|
||||
"temperature"
|
||||
)}
|
||||
style=${styleMap({
|
||||
"--control-number-buttons-focus-color": stateColor,
|
||||
})}
|
||||
.locale=${this.hass.locale}
|
||||
.locale=${this._locale}
|
||||
>
|
||||
</ha-control-number-buttons>
|
||||
</ha-control-button-group>
|
||||
|
||||
@@ -8,19 +8,26 @@ import {
|
||||
mdiVolumeHigh,
|
||||
mdiVolumeOff,
|
||||
} from "@mdi/js";
|
||||
import { consume } from "@lit/context";
|
||||
import type { HassEntity } from "home-assistant-js-websocket";
|
||||
import { LitElement, css, html, nothing } from "lit";
|
||||
import { customElement, property, state } from "lit/decorators";
|
||||
import { classMap } from "lit/directives/class-map";
|
||||
import { styleMap } from "lit/directives/style-map";
|
||||
import {
|
||||
consumeEntityState,
|
||||
consumeLocalize,
|
||||
} from "../../../common/decorators/consume-context-entry";
|
||||
import { computeDomain } from "../../../common/entity/compute_domain";
|
||||
import { stateColorCss } from "../../../common/entity/state_color";
|
||||
import type { LocalizeFunc } from "../../../common/translations/localize";
|
||||
import "../../../components/ha-control-button";
|
||||
import "../../../components/ha-control-button-group";
|
||||
import "../../../components/ha-control-switch";
|
||||
import { apiContext } from "../../../data/context";
|
||||
import { UNAVAILABLE, UNKNOWN } from "../../../data/entity/entity";
|
||||
import { forwardHaptic } from "../../../data/haptics";
|
||||
import type { HomeAssistant } from "../../../types";
|
||||
import type { HomeAssistant, HomeAssistantApi } from "../../../types";
|
||||
import type { LovelaceCardFeature } from "../types";
|
||||
import { cardFeatureStyles } from "./common/card-feature-styles";
|
||||
import type {
|
||||
@@ -28,14 +35,7 @@ import type {
|
||||
ToggleCardFeatureConfig,
|
||||
} from "./types";
|
||||
|
||||
export const supportsToggleCardFeature = (
|
||||
hass: HomeAssistant,
|
||||
context: LovelaceCardFeatureContext
|
||||
) => {
|
||||
const stateObj = context.entity_id
|
||||
? hass.states[context.entity_id]
|
||||
: undefined;
|
||||
if (!stateObj) return false;
|
||||
const supportsToggleCardFeatureFromState = (stateObj: HassEntity) => {
|
||||
const domain = computeDomain(stateObj.entity_id);
|
||||
return [
|
||||
"switch",
|
||||
@@ -47,6 +47,17 @@ export const supportsToggleCardFeature = (
|
||||
].includes(domain);
|
||||
};
|
||||
|
||||
export const supportsToggleCardFeature = (
|
||||
hass: HomeAssistant,
|
||||
context: LovelaceCardFeatureContext
|
||||
) => {
|
||||
const stateObj = context.entity_id
|
||||
? hass.states[context.entity_id]
|
||||
: undefined;
|
||||
if (!stateObj) return false;
|
||||
return supportsToggleCardFeatureFromState(stateObj);
|
||||
};
|
||||
|
||||
const DOMAIN_ICONS: Record<string, { on: string; off: string }> = {
|
||||
siren: {
|
||||
on: mdiVolumeHigh,
|
||||
@@ -64,18 +75,21 @@ const DOMAIN_ICONS: Record<string, { on: string; off: string }> = {
|
||||
|
||||
@customElement("hui-toggle-card-feature")
|
||||
class HuiToggleCardFeature extends LitElement implements LovelaceCardFeature {
|
||||
@property({ attribute: false }) public hass?: HomeAssistant;
|
||||
|
||||
@property({ attribute: false }) public context?: LovelaceCardFeatureContext;
|
||||
|
||||
@state() private _config?: ToggleCardFeatureConfig;
|
||||
@state()
|
||||
@consumeEntityState({ entityIdPath: ["context", "entity_id"] })
|
||||
private _stateObj?: HassEntity;
|
||||
|
||||
private get _stateObj() {
|
||||
if (!this.hass || !this.context || !this.context.entity_id) {
|
||||
return undefined;
|
||||
}
|
||||
return this.hass.states[this.context.entity_id!] as HassEntity | undefined;
|
||||
}
|
||||
@state()
|
||||
@consumeLocalize()
|
||||
private _localize!: LocalizeFunc;
|
||||
|
||||
@state()
|
||||
@consume({ context: apiContext, subscribe: true })
|
||||
private _api!: HomeAssistantApi;
|
||||
|
||||
@state() private _config?: ToggleCardFeatureConfig;
|
||||
|
||||
static getStubConfig(): ToggleCardFeatureConfig {
|
||||
return {
|
||||
@@ -109,7 +123,7 @@ class HuiToggleCardFeature extends LitElement implements LovelaceCardFeature {
|
||||
}
|
||||
|
||||
private async _callService(turnOn): Promise<void> {
|
||||
if (!this.hass || !this._stateObj) {
|
||||
if (!this._stateObj) {
|
||||
return;
|
||||
}
|
||||
forwardHaptic(this, "light");
|
||||
@@ -117,7 +131,7 @@ class HuiToggleCardFeature extends LitElement implements LovelaceCardFeature {
|
||||
const serviceDomain = stateDomain;
|
||||
const service = turnOn ? "turn_on" : "turn_off";
|
||||
|
||||
await this.hass.callService(serviceDomain, service, {
|
||||
await this._api.callService(serviceDomain, service, {
|
||||
entity_id: this._stateObj.entity_id,
|
||||
});
|
||||
}
|
||||
@@ -125,10 +139,9 @@ class HuiToggleCardFeature extends LitElement implements LovelaceCardFeature {
|
||||
protected render() {
|
||||
if (
|
||||
!this._config ||
|
||||
!this.hass ||
|
||||
!this.context ||
|
||||
!this._stateObj ||
|
||||
!supportsToggleCardFeature(this.hass, this.context)
|
||||
!supportsToggleCardFeatureFromState(this._stateObj)
|
||||
) {
|
||||
return nothing;
|
||||
}
|
||||
@@ -150,7 +163,7 @@ class HuiToggleCardFeature extends LitElement implements LovelaceCardFeature {
|
||||
return html`
|
||||
<ha-control-button-group>
|
||||
<ha-control-button
|
||||
.label=${this.hass.localize("ui.card.common.turn_off")}
|
||||
.label=${this._localize("ui.card.common.turn_off")}
|
||||
@click=${this._turnOff}
|
||||
.disabled=${this._stateObj.state === UNAVAILABLE}
|
||||
class=${classMap({
|
||||
@@ -163,7 +176,7 @@ class HuiToggleCardFeature extends LitElement implements LovelaceCardFeature {
|
||||
<ha-svg-icon .path=${offIcon}></ha-svg-icon>
|
||||
</ha-control-button>
|
||||
<ha-control-button
|
||||
.label=${this.hass.localize("ui.card.common.turn_on")}
|
||||
.label=${this._localize("ui.card.common.turn_on")}
|
||||
@click=${this._turnOn}
|
||||
.disabled=${this._stateObj.state === UNAVAILABLE}
|
||||
class=${classMap({
|
||||
@@ -185,7 +198,7 @@ class HuiToggleCardFeature extends LitElement implements LovelaceCardFeature {
|
||||
.pathOff=${offIcon}
|
||||
.checked=${isOn}
|
||||
@change=${this._valueChanged}
|
||||
.label=${this.hass.localize("ui.card.common.toggle")}
|
||||
.label=${this._localize("ui.card.common.toggle")}
|
||||
.disabled=${this._stateObj.state === UNAVAILABLE}
|
||||
>
|
||||
</ha-control-switch>
|
||||
|
||||
@@ -1,16 +1,24 @@
|
||||
import { consume } from "@lit/context";
|
||||
import { mdiCancel, mdiCellphoneArrowDown } from "@mdi/js";
|
||||
import type { HassEntity } from "home-assistant-js-websocket";
|
||||
import { LitElement, html, nothing } from "lit";
|
||||
import { customElement, property, state } from "lit/decorators";
|
||||
import {
|
||||
consumeEntityState,
|
||||
consumeLocalize,
|
||||
} from "../../../common/decorators/consume-context-entry";
|
||||
import { computeDomain } from "../../../common/entity/compute_domain";
|
||||
import { stateActive } from "../../../common/entity/state_active";
|
||||
import { supportsFeature } from "../../../common/entity/supports-feature";
|
||||
import type { LocalizeFunc } from "../../../common/translations/localize";
|
||||
import "../../../components/ha-control-button";
|
||||
import "../../../components/ha-control-button-group";
|
||||
import { apiContext } from "../../../data/context";
|
||||
import { UNAVAILABLE } from "../../../data/entity/entity";
|
||||
import type { UpdateEntity } from "../../../data/update";
|
||||
import { UpdateEntityFeature, updateIsInstalling } from "../../../data/update";
|
||||
import { showUpdateBackupDialogParams } from "../../../dialogs/update_backup/show-update-backup-dialog";
|
||||
import type { HomeAssistant } from "../../../types";
|
||||
import type { HomeAssistant, HomeAssistantApi } from "../../../types";
|
||||
import type { LovelaceCardFeature, LovelaceCardFeatureEditor } from "../types";
|
||||
import { cardFeatureStyles } from "./common/card-feature-styles";
|
||||
import type {
|
||||
@@ -20,6 +28,14 @@ import type {
|
||||
|
||||
export const DEFAULT_UPDATE_BACKUP_OPTION = "no";
|
||||
|
||||
const supportsUpdateActionsCardFeatureFromState = (stateObj: HassEntity) => {
|
||||
const domain = computeDomain(stateObj.entity_id);
|
||||
return (
|
||||
domain === "update" &&
|
||||
supportsFeature(stateObj, UpdateEntityFeature.INSTALL)
|
||||
);
|
||||
};
|
||||
|
||||
export const supportsUpdateActionsCardFeature = (
|
||||
hass: HomeAssistant,
|
||||
context: LovelaceCardFeatureContext
|
||||
@@ -28,11 +44,7 @@ export const supportsUpdateActionsCardFeature = (
|
||||
? hass.states[context.entity_id]
|
||||
: undefined;
|
||||
if (!stateObj) return false;
|
||||
const domain = computeDomain(stateObj.entity_id);
|
||||
return (
|
||||
domain === "update" &&
|
||||
supportsFeature(stateObj, UpdateEntityFeature.INSTALL)
|
||||
);
|
||||
return supportsUpdateActionsCardFeatureFromState(stateObj);
|
||||
};
|
||||
|
||||
@customElement("hui-update-actions-card-feature")
|
||||
@@ -40,19 +52,21 @@ class HuiUpdateActionsCardFeature
|
||||
extends LitElement
|
||||
implements LovelaceCardFeature
|
||||
{
|
||||
@property({ attribute: false }) public hass?: HomeAssistant;
|
||||
|
||||
@property({ attribute: false }) public context?: LovelaceCardFeatureContext;
|
||||
|
||||
@state() private _config?: UpdateActionsCardFeatureConfig;
|
||||
@state()
|
||||
@consumeEntityState({ entityIdPath: ["context", "entity_id"] })
|
||||
private _stateObj?: UpdateEntity;
|
||||
|
||||
private get _stateObj() {
|
||||
if (!this.hass || !this.context || !this.context.entity_id) {
|
||||
return undefined;
|
||||
}
|
||||
return this.hass.states[this.context.entity_id!] as
|
||||
UpdateEntity | undefined;
|
||||
}
|
||||
@state()
|
||||
@consumeLocalize()
|
||||
private _localize!: LocalizeFunc;
|
||||
|
||||
@state()
|
||||
@consume({ context: apiContext, subscribe: true })
|
||||
private _api!: HomeAssistantApi;
|
||||
|
||||
@state() private _config?: UpdateActionsCardFeatureConfig;
|
||||
|
||||
public static async getConfigElement(): Promise<LovelaceCardFeatureEditor> {
|
||||
await import("../editor/config-elements/hui-update-actions-card-feature-editor");
|
||||
@@ -115,14 +129,14 @@ class HuiUpdateActionsCardFeature
|
||||
backup = response;
|
||||
}
|
||||
|
||||
this.hass!.callService("update", "install", {
|
||||
this._api.callService("update", "install", {
|
||||
entity_id: this._stateObj!.entity_id,
|
||||
backup: backup,
|
||||
});
|
||||
}
|
||||
|
||||
private async _skip(): Promise<void> {
|
||||
this.hass!.callService("update", "skip", {
|
||||
this._api.callService("update", "skip", {
|
||||
entity_id: this._stateObj!.entity_id,
|
||||
});
|
||||
}
|
||||
@@ -130,10 +144,9 @@ class HuiUpdateActionsCardFeature
|
||||
protected render() {
|
||||
if (
|
||||
!this._config ||
|
||||
!this.hass ||
|
||||
!this.context ||
|
||||
!this._stateObj ||
|
||||
!supportsUpdateActionsCardFeature(this.hass, this.context)
|
||||
!supportsUpdateActionsCardFeatureFromState(this._stateObj)
|
||||
) {
|
||||
return nothing;
|
||||
}
|
||||
@@ -141,16 +154,14 @@ class HuiUpdateActionsCardFeature
|
||||
return html`
|
||||
<ha-control-button-group>
|
||||
<ha-control-button
|
||||
.label=${this.hass.localize(
|
||||
"ui.dialogs.more_info_control.update.skip"
|
||||
)}
|
||||
.label=${this._localize("ui.dialogs.more_info_control.update.skip")}
|
||||
@click=${this._skip}
|
||||
.disabled=${this._skipDisabled}
|
||||
>
|
||||
<ha-svg-icon .path=${mdiCancel}></ha-svg-icon>
|
||||
</ha-control-button>
|
||||
<ha-control-button
|
||||
.label=${this.hass.localize(
|
||||
.label=${this._localize(
|
||||
"ui.dialogs.more_info_control.update.install"
|
||||
)}
|
||||
@click=${this._install}
|
||||
|
||||
@@ -7,14 +7,21 @@ import {
|
||||
mdiStop,
|
||||
mdiTargetVariant,
|
||||
} from "@mdi/js";
|
||||
import { consume } from "@lit/context";
|
||||
import type { HassEntity } from "home-assistant-js-websocket";
|
||||
import { LitElement, html, nothing } from "lit";
|
||||
import { customElement, property, state } from "lit/decorators";
|
||||
import {
|
||||
consumeEntityState,
|
||||
consumeLocalize,
|
||||
} from "../../../common/decorators/consume-context-entry";
|
||||
import { computeDomain } from "../../../common/entity/compute_domain";
|
||||
import { supportsFeature } from "../../../common/entity/supports-feature";
|
||||
import type { LocalizeFunc } from "../../../common/translations/localize";
|
||||
import "../../../components/ha-control-button";
|
||||
import "../../../components/ha-control-button-group";
|
||||
import "../../../components/ha-svg-icon";
|
||||
import { apiContext } from "../../../data/context";
|
||||
import { UNAVAILABLE } from "../../../data/entity/entity";
|
||||
import type { VacuumEntity } from "../../../data/vacuum";
|
||||
import {
|
||||
@@ -24,7 +31,7 @@ import {
|
||||
canStop,
|
||||
isCleaning,
|
||||
} from "../../../data/vacuum";
|
||||
import type { HomeAssistant } from "../../../types";
|
||||
import type { HomeAssistant, HomeAssistantApi } from "../../../types";
|
||||
import type { LovelaceCardFeature, LovelaceCardFeatureEditor } from "../types";
|
||||
import { cardFeatureStyles } from "./common/card-feature-styles";
|
||||
import type {
|
||||
@@ -125,6 +132,14 @@ export const VACUUM_COMMANDS_BUTTONS: Record<
|
||||
}),
|
||||
};
|
||||
|
||||
const supportsVacuumCommandsCardFeatureFromState = (stateObj: HassEntity) => {
|
||||
const domain = computeDomain(stateObj.entity_id);
|
||||
return (
|
||||
domain === "vacuum" &&
|
||||
VACUUM_COMMANDS.some((c) => supportsVacuumCommand(stateObj, c))
|
||||
);
|
||||
};
|
||||
|
||||
export const supportsVacuumCommandsCardFeature = (
|
||||
hass: HomeAssistant,
|
||||
context: LovelaceCardFeatureContext
|
||||
@@ -133,11 +148,7 @@ export const supportsVacuumCommandsCardFeature = (
|
||||
? hass.states[context.entity_id]
|
||||
: undefined;
|
||||
if (!stateObj) return false;
|
||||
const domain = computeDomain(stateObj.entity_id);
|
||||
return (
|
||||
domain === "vacuum" &&
|
||||
VACUUM_COMMANDS.some((c) => supportsVacuumCommand(stateObj, c))
|
||||
);
|
||||
return supportsVacuumCommandsCardFeatureFromState(stateObj);
|
||||
};
|
||||
|
||||
@customElement("hui-vacuum-commands-card-feature")
|
||||
@@ -145,19 +156,21 @@ class HuiVacuumCommandCardFeature
|
||||
extends LitElement
|
||||
implements LovelaceCardFeature
|
||||
{
|
||||
@property({ attribute: false }) public hass?: HomeAssistant;
|
||||
|
||||
@property({ attribute: false }) public context?: LovelaceCardFeatureContext;
|
||||
|
||||
@state() private _config?: VacuumCommandsCardFeatureConfig;
|
||||
@state()
|
||||
@consumeEntityState({ entityIdPath: ["context", "entity_id"] })
|
||||
private _stateObj?: VacuumEntity;
|
||||
|
||||
private get _stateObj() {
|
||||
if (!this.hass || !this.context || !this.context.entity_id) {
|
||||
return undefined;
|
||||
}
|
||||
return this.hass.states[this.context.entity_id!] as
|
||||
VacuumEntity | undefined;
|
||||
}
|
||||
@state()
|
||||
@consumeLocalize()
|
||||
private _localize!: LocalizeFunc;
|
||||
|
||||
@state()
|
||||
@consume({ context: apiContext, subscribe: true })
|
||||
private _api!: HomeAssistantApi;
|
||||
|
||||
@state() private _config?: VacuumCommandsCardFeatureConfig;
|
||||
|
||||
static getStubConfig(): VacuumCommandsCardFeatureConfig {
|
||||
return {
|
||||
@@ -180,7 +193,7 @@ class HuiVacuumCommandCardFeature
|
||||
private _onCommandTap(ev): void {
|
||||
ev.stopPropagation();
|
||||
const entry = (ev.target! as any).entry as VacuumButton;
|
||||
this.hass!.callService("vacuum", entry.serviceName, {
|
||||
this._api.callService("vacuum", entry.serviceName, {
|
||||
entity_id: this._stateObj!.entity_id,
|
||||
});
|
||||
}
|
||||
@@ -188,10 +201,9 @@ class HuiVacuumCommandCardFeature
|
||||
protected render() {
|
||||
if (
|
||||
!this._config ||
|
||||
!this.hass ||
|
||||
!this.context ||
|
||||
!this._stateObj ||
|
||||
!supportsVacuumCommandsCardFeature(this.hass, this.context)
|
||||
!supportsVacuumCommandsCardFeatureFromState(this._stateObj)
|
||||
) {
|
||||
return nothing;
|
||||
}
|
||||
@@ -209,7 +221,7 @@ class HuiVacuumCommandCardFeature
|
||||
return html`
|
||||
<ha-control-button
|
||||
.entry=${button}
|
||||
.label=${this.hass!.localize(
|
||||
.label=${this._localize(
|
||||
// @ts-ignore
|
||||
`ui.dialogs.more_info_control.vacuum.${button.translationKey}`
|
||||
)}
|
||||
|
||||
@@ -1,15 +1,23 @@
|
||||
import { consume } from "@lit/context";
|
||||
import { mdiStop, mdiValveClosed, mdiValveOpen } from "@mdi/js";
|
||||
import type { HassEntity } from "home-assistant-js-websocket";
|
||||
import { css, html, LitElement, nothing } from "lit";
|
||||
import { customElement, property, state } from "lit/decorators";
|
||||
import { classMap } from "lit/directives/class-map";
|
||||
import { styleMap } from "lit/directives/style-map";
|
||||
import {
|
||||
consumeEntityState,
|
||||
consumeLocalize,
|
||||
} from "../../../common/decorators/consume-context-entry";
|
||||
import { computeDomain } from "../../../common/entity/compute_domain";
|
||||
import { stateColorCss } from "../../../common/entity/state_color";
|
||||
import { supportsFeature } from "../../../common/entity/supports-feature";
|
||||
import type { LocalizeFunc } from "../../../common/translations/localize";
|
||||
import "../../../components/ha-control-button";
|
||||
import "../../../components/ha-control-button-group";
|
||||
import "../../../components/ha-control-switch";
|
||||
import "../../../components/ha-svg-icon";
|
||||
import { apiContext } from "../../../data/context";
|
||||
import { UNAVAILABLE, UNKNOWN } from "../../../data/entity/entity";
|
||||
import {
|
||||
canClose,
|
||||
@@ -18,7 +26,7 @@ import {
|
||||
ValveEntityFeature,
|
||||
type ValveEntity,
|
||||
} from "../../../data/valve";
|
||||
import type { HomeAssistant } from "../../../types";
|
||||
import type { HomeAssistant, HomeAssistantApi } from "../../../types";
|
||||
import type { LovelaceCardFeature } from "../types";
|
||||
import { cardFeatureStyles } from "./common/card-feature-styles";
|
||||
import type {
|
||||
@@ -26,6 +34,15 @@ import type {
|
||||
ValveOpenCloseCardFeatureConfig,
|
||||
} from "./types";
|
||||
|
||||
const supportsValveOpenCloseCardFeatureFromState = (stateObj: HassEntity) => {
|
||||
const domain = computeDomain(stateObj.entity_id);
|
||||
return (
|
||||
domain === "valve" &&
|
||||
(supportsFeature(stateObj, ValveEntityFeature.OPEN) ||
|
||||
supportsFeature(stateObj, ValveEntityFeature.CLOSE))
|
||||
);
|
||||
};
|
||||
|
||||
export const supportsValveOpenCloseCardFeature = (
|
||||
hass: HomeAssistant,
|
||||
context: LovelaceCardFeatureContext
|
||||
@@ -34,12 +51,7 @@ export const supportsValveOpenCloseCardFeature = (
|
||||
? hass.states[context.entity_id]
|
||||
: undefined;
|
||||
if (!stateObj) return false;
|
||||
const domain = computeDomain(stateObj.entity_id);
|
||||
return (
|
||||
domain === "valve" &&
|
||||
(supportsFeature(stateObj, ValveEntityFeature.OPEN) ||
|
||||
supportsFeature(stateObj, ValveEntityFeature.CLOSE))
|
||||
);
|
||||
return supportsValveOpenCloseCardFeatureFromState(stateObj);
|
||||
};
|
||||
|
||||
@customElement("hui-valve-open-close-card-feature")
|
||||
@@ -47,18 +59,21 @@ class HuiValveOpenCloseCardFeature
|
||||
extends LitElement
|
||||
implements LovelaceCardFeature
|
||||
{
|
||||
@property({ attribute: false }) public hass?: HomeAssistant;
|
||||
|
||||
@property({ attribute: false }) public context?: LovelaceCardFeatureContext;
|
||||
|
||||
@state() private _config?: ValveOpenCloseCardFeatureConfig;
|
||||
@state()
|
||||
@consumeEntityState({ entityIdPath: ["context", "entity_id"] })
|
||||
private _stateObj?: ValveEntity;
|
||||
|
||||
private get _stateObj() {
|
||||
if (!this.hass || !this.context || !this.context.entity_id) {
|
||||
return undefined;
|
||||
}
|
||||
return this.hass.states[this.context.entity_id!] as ValveEntity | undefined;
|
||||
}
|
||||
@state()
|
||||
@consumeLocalize()
|
||||
private _localize!: LocalizeFunc;
|
||||
|
||||
@state()
|
||||
@consume({ context: apiContext, subscribe: true })
|
||||
private _api!: HomeAssistantApi;
|
||||
|
||||
@state() private _config?: ValveOpenCloseCardFeatureConfig;
|
||||
|
||||
static getStubConfig(): ValveOpenCloseCardFeatureConfig {
|
||||
return {
|
||||
@@ -74,13 +89,13 @@ class HuiValveOpenCloseCardFeature
|
||||
}
|
||||
|
||||
private _onOpenValve(): void {
|
||||
this.hass!.callService("valve", "open_valve", {
|
||||
this._api.callService("valve", "open_valve", {
|
||||
entity_id: this._stateObj!.entity_id,
|
||||
});
|
||||
}
|
||||
|
||||
private _onCloseValve(): void {
|
||||
this.hass!.callService("valve", "close_valve", {
|
||||
this._api.callService("valve", "close_valve", {
|
||||
entity_id: this._stateObj!.entity_id,
|
||||
});
|
||||
}
|
||||
@@ -97,7 +112,7 @@ class HuiValveOpenCloseCardFeature
|
||||
|
||||
private _onStopTap(ev): void {
|
||||
ev.stopPropagation();
|
||||
this.hass!.callService("valve", "stop_valve", {
|
||||
this._api.callService("valve", "stop_valve", {
|
||||
entity_id: this._stateObj!.entity_id,
|
||||
});
|
||||
}
|
||||
@@ -116,10 +131,9 @@ class HuiValveOpenCloseCardFeature
|
||||
protected render() {
|
||||
if (
|
||||
!this._config ||
|
||||
!this.hass ||
|
||||
!this.context ||
|
||||
!this._stateObj ||
|
||||
!supportsValveOpenCloseCardFeature(this.hass, this.context)
|
||||
!supportsValveOpenCloseCardFeatureFromState(this._stateObj)
|
||||
) {
|
||||
return nothing;
|
||||
}
|
||||
@@ -146,7 +160,7 @@ class HuiValveOpenCloseCardFeature
|
||||
supportsFeature(this._stateObj, ValveEntityFeature.CLOSE)
|
||||
? html`
|
||||
<ha-control-button
|
||||
.label=${this.hass.localize("ui.card.valve.close_valve")}
|
||||
.label=${this._localize("ui.card.valve.close_valve")}
|
||||
@click=${this._onCloseTap}
|
||||
.disabled=${!canClose(this._stateObj)}
|
||||
class=${classMap({
|
||||
@@ -165,7 +179,7 @@ class HuiValveOpenCloseCardFeature
|
||||
supportsFeature(this._stateObj, ValveEntityFeature.STOP)
|
||||
? html`
|
||||
<ha-control-button
|
||||
.label=${this.hass.localize("ui.card.valve.stop_valve")}
|
||||
.label=${this._localize("ui.card.valve.stop_valve")}
|
||||
@click=${this._onStopTap}
|
||||
.disabled=${!canStop(this._stateObj)}
|
||||
>
|
||||
@@ -178,7 +192,7 @@ class HuiValveOpenCloseCardFeature
|
||||
supportsFeature(this._stateObj, ValveEntityFeature.OPEN)
|
||||
? html`
|
||||
<ha-control-button
|
||||
.label=${this.hass.localize("ui.card.valve.open_valve")}
|
||||
.label=${this._localize("ui.card.valve.open_valve")}
|
||||
@click=${this._onOpenTap}
|
||||
.disabled=${!canOpen(this._stateObj)}
|
||||
class=${classMap({
|
||||
@@ -203,7 +217,7 @@ class HuiValveOpenCloseCardFeature
|
||||
.pathOff=${closedIcon}
|
||||
.checked=${isOpen}
|
||||
@change=${this._valueChanged}
|
||||
.label=${this.hass.localize("ui.card.common.toggle")}
|
||||
.label=${this._localize("ui.card.common.toggle")}
|
||||
.disabled=${this._stateObj.state === UNAVAILABLE}
|
||||
>
|
||||
</ha-control-switch>
|
||||
|
||||
@@ -1,18 +1,36 @@
|
||||
import { consume } from "@lit/context";
|
||||
import type { HassEntity } from "home-assistant-js-websocket";
|
||||
import { html, LitElement, nothing } from "lit";
|
||||
import { customElement, property, state } from "lit/decorators";
|
||||
import { styleMap } from "lit/directives/style-map";
|
||||
import { computeCssColor } from "../../../common/color/compute-color";
|
||||
import {
|
||||
consumeEntityState,
|
||||
consumeLocalize,
|
||||
} from "../../../common/decorators/consume-context-entry";
|
||||
import { transform } from "../../../common/decorators/transform";
|
||||
import type { HASSDomEvent } from "../../../common/dom/fire_event";
|
||||
import { computeAttributeNameDisplay } from "../../../common/entity/compute_attribute_display";
|
||||
import { computeDomain } from "../../../common/entity/compute_domain";
|
||||
import { stateActive } from "../../../common/entity/state_active";
|
||||
import { stateColorCss } from "../../../common/entity/state_color";
|
||||
import { supportsFeature } from "../../../common/entity/supports-feature";
|
||||
import type { LocalizeFunc } from "../../../common/translations/localize";
|
||||
import "../../../components/ha-control-slider";
|
||||
import {
|
||||
apiContext,
|
||||
entitiesContext,
|
||||
internationalizationContext,
|
||||
} from "../../../data/context";
|
||||
import { UNAVAILABLE } from "../../../data/entity/entity";
|
||||
import { DOMAIN_ATTRIBUTES_UNITS } from "../../../data/entity/entity_attributes";
|
||||
import type { FrontendLocaleData } from "../../../data/translation";
|
||||
import { ValveEntityFeature, type ValveEntity } from "../../../data/valve";
|
||||
import type { HomeAssistant } from "../../../types";
|
||||
import type {
|
||||
HomeAssistant,
|
||||
HomeAssistantApi,
|
||||
HomeAssistantInternationalization,
|
||||
} from "../../../types";
|
||||
import type { LovelaceCardFeature } from "../types";
|
||||
import { cardFeatureStyles } from "./common/card-feature-styles";
|
||||
import type {
|
||||
@@ -20,6 +38,14 @@ import type {
|
||||
ValvePositionCardFeatureConfig,
|
||||
} from "./types";
|
||||
|
||||
const supportsValvePositionCardFeatureFromState = (stateObj: HassEntity) => {
|
||||
const domain = computeDomain(stateObj.entity_id);
|
||||
return (
|
||||
domain === "valve" &&
|
||||
supportsFeature(stateObj, ValveEntityFeature.SET_POSITION)
|
||||
);
|
||||
};
|
||||
|
||||
export const supportsValvePositionCardFeature = (
|
||||
hass: HomeAssistant,
|
||||
context: LovelaceCardFeatureContext
|
||||
@@ -28,11 +54,7 @@ export const supportsValvePositionCardFeature = (
|
||||
? hass.states[context.entity_id]
|
||||
: undefined;
|
||||
if (!stateObj) return false;
|
||||
const domain = computeDomain(stateObj.entity_id);
|
||||
return (
|
||||
domain === "valve" &&
|
||||
supportsFeature(stateObj, ValveEntityFeature.SET_POSITION)
|
||||
);
|
||||
return supportsValvePositionCardFeatureFromState(stateObj);
|
||||
};
|
||||
|
||||
@customElement("hui-valve-position-card-feature")
|
||||
@@ -40,20 +62,34 @@ class HuiValvePositionCardFeature
|
||||
extends LitElement
|
||||
implements LovelaceCardFeature
|
||||
{
|
||||
@property({ attribute: false }) public hass?: HomeAssistant;
|
||||
|
||||
@property({ attribute: false }) public context?: LovelaceCardFeatureContext;
|
||||
|
||||
@property({ attribute: false }) public color?: string;
|
||||
|
||||
@state() private _config?: ValvePositionCardFeatureConfig;
|
||||
@state()
|
||||
@consumeEntityState({ entityIdPath: ["context", "entity_id"] })
|
||||
private _stateObj?: ValveEntity;
|
||||
|
||||
private get _stateObj() {
|
||||
if (!this.hass || !this.context || !this.context.entity_id) {
|
||||
return undefined;
|
||||
}
|
||||
return this.hass.states[this.context.entity_id!] as ValveEntity | undefined;
|
||||
}
|
||||
@state()
|
||||
@consumeLocalize()
|
||||
private _localize!: LocalizeFunc;
|
||||
|
||||
@state()
|
||||
@consume({ context: apiContext, subscribe: true })
|
||||
private _api!: HomeAssistantApi;
|
||||
|
||||
@state()
|
||||
@consume({ context: entitiesContext, subscribe: true })
|
||||
private _entities!: HomeAssistant["entities"];
|
||||
|
||||
@state()
|
||||
@consume({ context: internationalizationContext, subscribe: true })
|
||||
@transform<HomeAssistantInternationalization, FrontendLocaleData>({
|
||||
transformer: ({ locale }) => locale,
|
||||
})
|
||||
private _locale?: FrontendLocaleData;
|
||||
|
||||
@state() private _config?: ValvePositionCardFeatureConfig;
|
||||
|
||||
static getStubConfig(): ValvePositionCardFeatureConfig {
|
||||
return {
|
||||
@@ -71,10 +107,9 @@ class HuiValvePositionCardFeature
|
||||
protected render() {
|
||||
if (
|
||||
!this._config ||
|
||||
!this.hass ||
|
||||
!this.context ||
|
||||
!this._stateObj ||
|
||||
!supportsValvePositionCardFeature(this.hass, this.context)
|
||||
!supportsValvePositionCardFeatureFromState(this._stateObj)
|
||||
) {
|
||||
return nothing;
|
||||
}
|
||||
@@ -108,14 +143,14 @@ class HuiValvePositionCardFeature
|
||||
show-handle
|
||||
@value-changed=${this._valueChanged}
|
||||
.label=${computeAttributeNameDisplay(
|
||||
this.hass.localize,
|
||||
this._localize,
|
||||
this._stateObj,
|
||||
this.hass.entities,
|
||||
this._entities,
|
||||
"current_position"
|
||||
)}
|
||||
.disabled=${this._stateObj!.state === UNAVAILABLE}
|
||||
.unit=${DOMAIN_ATTRIBUTES_UNITS.valve.current_position}
|
||||
.locale=${this.hass.locale}
|
||||
.locale=${this._locale}
|
||||
></ha-control-slider>
|
||||
`;
|
||||
}
|
||||
@@ -124,7 +159,7 @@ class HuiValvePositionCardFeature
|
||||
const { value } = ev.detail;
|
||||
if (typeof value !== "number" || isNaN(value)) return;
|
||||
|
||||
this.hass!.callService("valve", "set_valve_position", {
|
||||
this._api.callService("valve", "set_valve_position", {
|
||||
entity_id: this._stateObj!.entity_id,
|
||||
position: value,
|
||||
});
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { mdiWaterBoiler } from "@mdi/js";
|
||||
import type { HassEntity } from "home-assistant-js-websocket";
|
||||
import { customElement } from "lit/decorators";
|
||||
import { computeDomain } from "../../../common/entity/compute_domain";
|
||||
import { stateColorCss } from "../../../common/entity/state_color";
|
||||
@@ -13,6 +14,13 @@ import type {
|
||||
WaterHeaterOperationModesCardFeatureConfig,
|
||||
} from "./types";
|
||||
|
||||
const supportsWaterHeaterOperationModesCardFeatureFromState = (
|
||||
stateObj: HassEntity
|
||||
) => {
|
||||
const domain = computeDomain(stateObj.entity_id);
|
||||
return domain === "water_heater";
|
||||
};
|
||||
|
||||
export const supportsWaterHeaterOperationModesCardFeature = (
|
||||
hass: HomeAssistant,
|
||||
context: LovelaceCardFeatureContext
|
||||
@@ -21,8 +29,7 @@ export const supportsWaterHeaterOperationModesCardFeature = (
|
||||
? hass.states[context.entity_id]
|
||||
: undefined;
|
||||
if (!stateObj) return false;
|
||||
const domain = computeDomain(stateObj.entity_id);
|
||||
return domain === "water_heater";
|
||||
return supportsWaterHeaterOperationModesCardFeatureFromState(stateObj);
|
||||
};
|
||||
|
||||
@customElement("hui-water-heater-operation-modes-card-feature")
|
||||
@@ -48,7 +55,7 @@ class HuiWaterHeaterOperationModeCardFeature
|
||||
protected readonly _serviceAction = "set_operation_mode";
|
||||
|
||||
protected get _label(): string {
|
||||
return this.hass!.localize("ui.card.water_heater.mode");
|
||||
return this._localize("ui.card.water_heater.mode");
|
||||
}
|
||||
|
||||
protected readonly _defaultStyle = "icons";
|
||||
@@ -82,7 +89,7 @@ class HuiWaterHeaterOperationModeCardFeature
|
||||
}
|
||||
|
||||
protected _getOptions() {
|
||||
if (!this._stateObj || !this.hass) {
|
||||
if (!this._stateObj) {
|
||||
return [];
|
||||
}
|
||||
|
||||
@@ -94,16 +101,15 @@ class HuiWaterHeaterOperationModeCardFeature
|
||||
return filterModes(orderedModes, this._config?.operation_modes).map(
|
||||
(mode) => ({
|
||||
value: mode,
|
||||
label: this.hass!.formatEntityState(this._stateObj!, mode),
|
||||
label: this._formatters.formatEntityState(this._stateObj!, mode),
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
protected _isSupported(): boolean {
|
||||
return !!(
|
||||
this.hass &&
|
||||
this.context &&
|
||||
supportsWaterHeaterOperationModesCardFeature(this.hass, this.context)
|
||||
this._stateObj &&
|
||||
supportsWaterHeaterOperationModesCardFeatureFromState(this._stateObj)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -245,7 +245,7 @@ export class HuiEntityCard extends LitElement implements LovelaceCard {
|
||||
|
||||
protected shouldUpdate(changedProps: PropertyValues<this>): boolean {
|
||||
// Side Effect used to update footer hass while keeping optimizations
|
||||
if (this._footerElement) {
|
||||
if (this._footerElement && "hass" in this._footerElement) {
|
||||
this._footerElement.hass = this.hass;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,9 +1,12 @@
|
||||
import { mdiAlertCircleOutline, mdiAlertOutline } from "@mdi/js";
|
||||
import { consume, type ContextType } from "@lit/context";
|
||||
import { css, html, LitElement, nothing } from "lit";
|
||||
import { customElement, property, state } from "lit/decorators";
|
||||
import { consumeLocalize } from "../../../common/decorators/consume-context-entry";
|
||||
import type { LocalizeFunc } from "../../../common/translations/localize";
|
||||
import "../../../components/ha-card";
|
||||
import "../../../components/ha-svg-icon";
|
||||
import type { HomeAssistant } from "../../../types";
|
||||
import { configContext } from "../../../data/context";
|
||||
import type { LovelaceCard, LovelaceGridOptions } from "../types";
|
||||
import type { ErrorCardConfig } from "./types";
|
||||
|
||||
@@ -14,7 +17,13 @@ const ERROR_ICONS = {
|
||||
|
||||
@customElement("hui-error-card")
|
||||
export class HuiErrorCard extends LitElement implements LovelaceCard {
|
||||
@property({ attribute: false }) public hass?: HomeAssistant;
|
||||
@state()
|
||||
@consumeLocalize()
|
||||
private _localize?: LocalizeFunc;
|
||||
|
||||
@state()
|
||||
@consume({ context: configContext, subscribe: true })
|
||||
private _hassConfig?: ContextType<typeof configContext>;
|
||||
|
||||
@property({ attribute: false }) public preview = false;
|
||||
|
||||
@@ -45,10 +54,12 @@ export class HuiErrorCard extends LitElement implements LovelaceCard {
|
||||
const error =
|
||||
this._config?.error ||
|
||||
(this.severity === "warning" &&
|
||||
this.hass?.localize("ui.errors.config.configuration_warning")) ||
|
||||
this.hass?.localize("ui.errors.config.configuration_error");
|
||||
this._localize?.("ui.errors.config.configuration_warning")) ||
|
||||
this._localize?.("ui.errors.config.configuration_error");
|
||||
const showTitle =
|
||||
this.hass === undefined || this.hass?.user?.is_admin || this.preview;
|
||||
this._hassConfig === undefined ||
|
||||
this._hassConfig.user?.is_admin ||
|
||||
this.preview;
|
||||
const showMessage = this.preview;
|
||||
|
||||
return html`
|
||||
|
||||
@@ -68,9 +68,6 @@ export abstract class HuiStackCard<T extends StackCardConfig = StackCardConfig>
|
||||
this._cards.forEach((card) => {
|
||||
card.hass = this.hass;
|
||||
});
|
||||
if (this._errorCard) {
|
||||
this._errorCard.hass = this.hass;
|
||||
}
|
||||
}
|
||||
if (changedProperties.has("preview")) {
|
||||
this._cards.forEach((card) => {
|
||||
|
||||
@@ -254,7 +254,7 @@ export class HuiStatisticCard extends LitElement implements LovelaceCard {
|
||||
|
||||
protected shouldUpdate(changedProps: PropertyValues): boolean {
|
||||
// Side Effect used to update footer hass while keeping optimizations
|
||||
if (this._footerElement) {
|
||||
if (this._footerElement && "hass" in this._footerElement) {
|
||||
this._footerElement.hass = this.hass;
|
||||
}
|
||||
if (
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
import { STATE_NOT_RUNNING } from "home-assistant-js-websocket";
|
||||
import type { TemplateResult } from "lit";
|
||||
import { html, LitElement } from "lit";
|
||||
import { customElement, property } from "lit/decorators";
|
||||
import { customElement } from "lit/decorators";
|
||||
import "../../../components/ha-alert";
|
||||
import type { HomeAssistant } from "../../../types";
|
||||
import "../cards/hui-error-card";
|
||||
|
||||
export const createEntityNotFoundWarning = (
|
||||
hass: HomeAssistant,
|
||||
hass: Pick<HomeAssistant, "config" | "localize">,
|
||||
// left for backwards compatibility for custom cards
|
||||
_entityId: string
|
||||
) =>
|
||||
@@ -17,10 +17,8 @@ export const createEntityNotFoundWarning = (
|
||||
|
||||
@customElement("hui-warning")
|
||||
export class HuiWarning extends LitElement {
|
||||
@property({ attribute: false }) public hass?: HomeAssistant;
|
||||
|
||||
protected render(): TemplateResult {
|
||||
return html`<hui-error-card .hass=${this.hass} severity="warning"
|
||||
return html`<hui-error-card severity="warning"
|
||||
><slot></slot
|
||||
></hui-error-card>`;
|
||||
}
|
||||
|
||||
@@ -30,7 +30,9 @@ class EntityRowDirective extends Directive {
|
||||
}
|
||||
this._entityId = entityId;
|
||||
this._name = name;
|
||||
this._element.hass = hass;
|
||||
if ("hass" in this._element) {
|
||||
this._element.hass = hass;
|
||||
}
|
||||
return this._element;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,35 +25,65 @@ export const getMyRedirects = (): Redirects => ({
|
||||
application_credentials: {
|
||||
redirect: "/config/application_credentials",
|
||||
},
|
||||
tools_assist: {
|
||||
redirect: "/config/tools/assist",
|
||||
},
|
||||
tools_debug: {
|
||||
redirect: "/config/tools/debug",
|
||||
},
|
||||
tools_states: {
|
||||
redirect: "/config/tools/state",
|
||||
},
|
||||
tools_actions: {
|
||||
redirect: "/config/tools/action",
|
||||
},
|
||||
tools_perform_action: {
|
||||
redirect: "/config/tools/action",
|
||||
params: {
|
||||
service: "string",
|
||||
},
|
||||
},
|
||||
tools_template: {
|
||||
redirect: "/config/tools/template",
|
||||
},
|
||||
tools_events: {
|
||||
redirect: "/config/tools/event",
|
||||
},
|
||||
tools_statistics: {
|
||||
redirect: "/config/tools/statistics",
|
||||
},
|
||||
tools_yaml: {
|
||||
redirect: "/config/tools/yaml",
|
||||
},
|
||||
developer_assist: {
|
||||
redirect: "/config/developer-tools/assist",
|
||||
redirect: "/config/tools/assist",
|
||||
},
|
||||
developer_debug: {
|
||||
redirect: "/config/developer-tools/debug",
|
||||
redirect: "/config/tools/debug",
|
||||
},
|
||||
developer_states: {
|
||||
redirect: "/config/developer-tools/state",
|
||||
redirect: "/config/tools/state",
|
||||
},
|
||||
developer_services: {
|
||||
redirect: "/config/developer-tools/action",
|
||||
redirect: "/config/tools/action",
|
||||
},
|
||||
developer_call_service: {
|
||||
redirect: "/config/developer-tools/action",
|
||||
redirect: "/config/tools/action",
|
||||
params: {
|
||||
service: "string",
|
||||
},
|
||||
},
|
||||
developer_template: {
|
||||
redirect: "/config/developer-tools/template",
|
||||
redirect: "/config/tools/template",
|
||||
},
|
||||
developer_events: {
|
||||
redirect: "/config/developer-tools/event",
|
||||
redirect: "/config/tools/event",
|
||||
},
|
||||
developer_statistics: {
|
||||
redirect: "/config/developer-tools/statistics",
|
||||
redirect: "/config/tools/statistics",
|
||||
},
|
||||
server_controls: {
|
||||
redirect: "/config/developer-tools/yaml",
|
||||
redirect: "/config/tools/yaml",
|
||||
},
|
||||
calendar: {
|
||||
component: "calendar",
|
||||
|
||||
+51
-51
@@ -1459,7 +1459,7 @@
|
||||
"automations": "[%key:ui::panel::config::automation::caption%]",
|
||||
"scenes": "[%key:ui::panel::config::scene::caption%]",
|
||||
"scripts": "[%key:ui::panel::config::script::caption%]",
|
||||
"developer_tools": "[%key:ui::panel::config::dashboard::developer_tools::main%]",
|
||||
"tools": "[%key:ui::panel::config::dashboard::tools::main%]",
|
||||
"integrations": "[%key:ui::panel::config::integrations::caption%]",
|
||||
"devices": "[%key:ui::panel::config::devices::caption%]",
|
||||
"entities": "[%key:ui::panel::config::entities::caption%]"
|
||||
@@ -1485,45 +1485,45 @@
|
||||
"navigate_title": "Navigate",
|
||||
"commands": {
|
||||
"reload": {
|
||||
"all": "[%key:ui::panel::config::developer-tools::tabs::yaml::section::reloading::all%]",
|
||||
"reload": "[%key:ui::panel::config::developer-tools::tabs::yaml::section::reloading::reload%]",
|
||||
"core": "[%key:ui::panel::config::developer-tools::tabs::yaml::section::reloading::core%]",
|
||||
"group": "[%key:ui::panel::config::developer-tools::tabs::yaml::section::reloading::group%]",
|
||||
"automation": "[%key:ui::panel::config::developer-tools::tabs::yaml::section::reloading::automation%]",
|
||||
"script": "[%key:ui::panel::config::developer-tools::tabs::yaml::section::reloading::script%]",
|
||||
"scene": "[%key:ui::panel::config::developer-tools::tabs::yaml::section::reloading::scene%]",
|
||||
"person": "[%key:ui::panel::config::developer-tools::tabs::yaml::section::reloading::person%]",
|
||||
"zone": "[%key:ui::panel::config::developer-tools::tabs::yaml::section::reloading::zone%]",
|
||||
"input_boolean": "[%key:ui::panel::config::developer-tools::tabs::yaml::section::reloading::input_boolean%]",
|
||||
"input_button": "[%key:ui::panel::config::developer-tools::tabs::yaml::section::reloading::input_button%]",
|
||||
"input_text": "[%key:ui::panel::config::developer-tools::tabs::yaml::section::reloading::input_text%]",
|
||||
"input_number": "[%key:ui::panel::config::developer-tools::tabs::yaml::section::reloading::input_number%]",
|
||||
"input_datetime": "[%key:ui::panel::config::developer-tools::tabs::yaml::section::reloading::input_datetime%]",
|
||||
"input_select": "[%key:ui::panel::config::developer-tools::tabs::yaml::section::reloading::input_select%]",
|
||||
"template": "[%key:ui::panel::config::developer-tools::tabs::yaml::section::reloading::template%]",
|
||||
"universal": "[%key:ui::panel::config::developer-tools::tabs::yaml::section::reloading::universal%]",
|
||||
"rest": "[%key:ui::panel::config::developer-tools::tabs::yaml::section::reloading::rest%]",
|
||||
"command_line": "[%key:ui::panel::config::developer-tools::tabs::yaml::section::reloading::command_line%]",
|
||||
"filter": "[%key:ui::panel::config::developer-tools::tabs::yaml::section::reloading::filter%]",
|
||||
"statistics": "[%key:ui::panel::config::developer-tools::tabs::yaml::section::reloading::statistics%]",
|
||||
"generic": "[%key:ui::panel::config::developer-tools::tabs::yaml::section::reloading::generic%]",
|
||||
"generic_thermostat": "[%key:ui::panel::config::developer-tools::tabs::yaml::section::reloading::generic_thermostat%]",
|
||||
"homekit": "[%key:ui::panel::config::developer-tools::tabs::yaml::section::reloading::homekit%]",
|
||||
"min_max": "[%key:ui::panel::config::developer-tools::tabs::yaml::section::reloading::min_max%]",
|
||||
"history_stats": "[%key:ui::panel::config::developer-tools::tabs::yaml::section::reloading::history_stats%]",
|
||||
"trend": "[%key:ui::panel::config::developer-tools::tabs::yaml::section::reloading::trend%]",
|
||||
"ping": "[%key:ui::panel::config::developer-tools::tabs::yaml::section::reloading::ping%]",
|
||||
"filesize": "[%key:ui::panel::config::developer-tools::tabs::yaml::section::reloading::filesize%]",
|
||||
"telegram": "[%key:ui::panel::config::developer-tools::tabs::yaml::section::reloading::telegram%]",
|
||||
"smtp": "[%key:ui::panel::config::developer-tools::tabs::yaml::section::reloading::smtp%]",
|
||||
"mqtt": "[%key:ui::panel::config::developer-tools::tabs::yaml::section::reloading::mqtt%]",
|
||||
"rpi_gpio": "[%key:ui::panel::config::developer-tools::tabs::yaml::section::reloading::rpi_gpio%]",
|
||||
"themes": "[%key:ui::panel::config::developer-tools::tabs::yaml::section::reloading::themes%]"
|
||||
"all": "[%key:ui::panel::config::tools::tabs::yaml::section::reloading::all%]",
|
||||
"reload": "[%key:ui::panel::config::tools::tabs::yaml::section::reloading::reload%]",
|
||||
"core": "[%key:ui::panel::config::tools::tabs::yaml::section::reloading::core%]",
|
||||
"group": "[%key:ui::panel::config::tools::tabs::yaml::section::reloading::group%]",
|
||||
"automation": "[%key:ui::panel::config::tools::tabs::yaml::section::reloading::automation%]",
|
||||
"script": "[%key:ui::panel::config::tools::tabs::yaml::section::reloading::script%]",
|
||||
"scene": "[%key:ui::panel::config::tools::tabs::yaml::section::reloading::scene%]",
|
||||
"person": "[%key:ui::panel::config::tools::tabs::yaml::section::reloading::person%]",
|
||||
"zone": "[%key:ui::panel::config::tools::tabs::yaml::section::reloading::zone%]",
|
||||
"input_boolean": "[%key:ui::panel::config::tools::tabs::yaml::section::reloading::input_boolean%]",
|
||||
"input_button": "[%key:ui::panel::config::tools::tabs::yaml::section::reloading::input_button%]",
|
||||
"input_text": "[%key:ui::panel::config::tools::tabs::yaml::section::reloading::input_text%]",
|
||||
"input_number": "[%key:ui::panel::config::tools::tabs::yaml::section::reloading::input_number%]",
|
||||
"input_datetime": "[%key:ui::panel::config::tools::tabs::yaml::section::reloading::input_datetime%]",
|
||||
"input_select": "[%key:ui::panel::config::tools::tabs::yaml::section::reloading::input_select%]",
|
||||
"template": "[%key:ui::panel::config::tools::tabs::yaml::section::reloading::template%]",
|
||||
"universal": "[%key:ui::panel::config::tools::tabs::yaml::section::reloading::universal%]",
|
||||
"rest": "[%key:ui::panel::config::tools::tabs::yaml::section::reloading::rest%]",
|
||||
"command_line": "[%key:ui::panel::config::tools::tabs::yaml::section::reloading::command_line%]",
|
||||
"filter": "[%key:ui::panel::config::tools::tabs::yaml::section::reloading::filter%]",
|
||||
"statistics": "[%key:ui::panel::config::tools::tabs::yaml::section::reloading::statistics%]",
|
||||
"generic": "[%key:ui::panel::config::tools::tabs::yaml::section::reloading::generic%]",
|
||||
"generic_thermostat": "[%key:ui::panel::config::tools::tabs::yaml::section::reloading::generic_thermostat%]",
|
||||
"homekit": "[%key:ui::panel::config::tools::tabs::yaml::section::reloading::homekit%]",
|
||||
"min_max": "[%key:ui::panel::config::tools::tabs::yaml::section::reloading::min_max%]",
|
||||
"history_stats": "[%key:ui::panel::config::tools::tabs::yaml::section::reloading::history_stats%]",
|
||||
"trend": "[%key:ui::panel::config::tools::tabs::yaml::section::reloading::trend%]",
|
||||
"ping": "[%key:ui::panel::config::tools::tabs::yaml::section::reloading::ping%]",
|
||||
"filesize": "[%key:ui::panel::config::tools::tabs::yaml::section::reloading::filesize%]",
|
||||
"telegram": "[%key:ui::panel::config::tools::tabs::yaml::section::reloading::telegram%]",
|
||||
"smtp": "[%key:ui::panel::config::tools::tabs::yaml::section::reloading::smtp%]",
|
||||
"mqtt": "[%key:ui::panel::config::tools::tabs::yaml::section::reloading::mqtt%]",
|
||||
"rpi_gpio": "[%key:ui::panel::config::tools::tabs::yaml::section::reloading::rpi_gpio%]",
|
||||
"themes": "[%key:ui::panel::config::tools::tabs::yaml::section::reloading::themes%]"
|
||||
},
|
||||
"home_assistant_control": {
|
||||
"perform_action": "{action} Home Assistant",
|
||||
"restart": "[%key:ui::panel::config::developer-tools::tabs::yaml::section::server_management::restart%]",
|
||||
"stop": "[%key:ui::panel::config::developer-tools::tabs::yaml::section::server_management::stop%]"
|
||||
"restart": "[%key:ui::panel::config::tools::tabs::yaml::section::server_management::restart%]",
|
||||
"stop": "[%key:ui::panel::config::tools::tabs::yaml::section::server_management::stop%]"
|
||||
},
|
||||
"types": {
|
||||
"reload": "Reload",
|
||||
@@ -1559,14 +1559,14 @@
|
||||
"analytics": "[%key:ui::panel::config::analytics::caption%]",
|
||||
"system_health": "[%key:ui::panel::config::system_health::caption%]",
|
||||
"blueprint": "[%key:ui::panel::config::blueprint::caption%]",
|
||||
"server_control": "[%key:ui::panel::config::developer-tools::tabs::yaml::title%]",
|
||||
"server_control": "[%key:ui::panel::config::tools::tabs::yaml::title%]",
|
||||
"system": "[%key:ui::panel::config::dashboard::system::main%]",
|
||||
"apps": "Apps",
|
||||
"app_store": "App store",
|
||||
"app_info": "{app} info",
|
||||
"shortcuts": "[%key:ui::panel::config::info::shortcuts%]",
|
||||
"labs": "[%key:ui::panel::config::labs::caption%]",
|
||||
"developer-tools": "[%key:ui::panel::config::dashboard::developer_tools::main%]",
|
||||
"tools": "[%key:ui::panel::config::dashboard::tools::main%]",
|
||||
"matter": "[%key:ui::panel::config::dashboard::matter::main%]",
|
||||
"zha": "[%key:ui::panel::config::dashboard::zha::main%]",
|
||||
"zwave_js": "[%key:ui::panel::config::dashboard::zwave_js::main%]",
|
||||
@@ -2154,12 +2154,12 @@
|
||||
"data": "Additional data"
|
||||
},
|
||||
"template": {
|
||||
"time": "[%key:ui::panel::config::developer-tools::tabs::templates::time%]",
|
||||
"all_listeners": "[%key:ui::panel::config::developer-tools::tabs::templates::all_listeners%]",
|
||||
"no_listeners": "[%key:ui::panel::config::developer-tools::tabs::templates::no_listeners%]",
|
||||
"listeners": "[%key:ui::panel::config::developer-tools::tabs::templates::listeners%]",
|
||||
"entity": "[%key:ui::panel::config::developer-tools::tabs::templates::entity%]",
|
||||
"domain": "[%key:ui::panel::config::developer-tools::tabs::templates::domain%]"
|
||||
"time": "[%key:ui::panel::config::tools::tabs::templates::time%]",
|
||||
"all_listeners": "[%key:ui::panel::config::tools::tabs::templates::all_listeners%]",
|
||||
"no_listeners": "[%key:ui::panel::config::tools::tabs::templates::no_listeners%]",
|
||||
"listeners": "[%key:ui::panel::config::tools::tabs::templates::listeners%]",
|
||||
"entity": "[%key:ui::panel::config::tools::tabs::templates::entity%]",
|
||||
"domain": "[%key:ui::panel::config::tools::tabs::templates::domain%]"
|
||||
}
|
||||
},
|
||||
"options_flow": {
|
||||
@@ -2638,9 +2638,9 @@
|
||||
"main": "System",
|
||||
"secondary": "Create backups, check logs, or reboot your system"
|
||||
},
|
||||
"developer_tools": {
|
||||
"main": "Developer tools",
|
||||
"secondary": "Tools to inspect and debug your system"
|
||||
"tools": {
|
||||
"main": "Tools",
|
||||
"secondary": "Inspect and debug your system"
|
||||
},
|
||||
"about": {
|
||||
"main": "About",
|
||||
@@ -3786,7 +3786,7 @@
|
||||
"companion_apps": "Companion apps"
|
||||
}
|
||||
},
|
||||
"developer-tools": {
|
||||
"tools": {
|
||||
"tabs": {
|
||||
"assist": {
|
||||
"tab": "Assist",
|
||||
@@ -4819,7 +4819,7 @@
|
||||
"run_text_pipeline": "Run text pipeline",
|
||||
"run_audio_pipeline": "Run audio pipeline",
|
||||
"run_audio_with_wake": "Run audio pipeline with wake word detection",
|
||||
"response": "[%key:ui::panel::config::developer-tools::tabs::actions::response%]",
|
||||
"response": "[%key:ui::panel::config::tools::tabs::actions::response%]",
|
||||
"send": "Send",
|
||||
"continue_listening": "Continue listening for wake word",
|
||||
"continue_talking": "Continue talking",
|
||||
@@ -5120,7 +5120,7 @@
|
||||
"type_script_plural": "[%key:ui::panel::config::blueprint::overview::types_plural::script%]",
|
||||
"type_scene_plural": "scenes",
|
||||
"new_automation_setup_failed_title": "New {type} setup timed out",
|
||||
"new_automation_setup_failed_text": "Your new {type} was saved, but waiting for it to set up has timed out. This could be due to errors parsing your configuration.yaml, please check the configuration in developer tools. Your {type} will not be visible until this is corrected and {types} are reloaded. Changes to area, category, or labels were not saved and must be reapplied.",
|
||||
"new_automation_setup_failed_text": "Your new {type} was saved, but waiting for it to set up has timed out. This could be due to errors parsing your configuration.yaml, please check the configuration in the Tools panel. Your {type} will not be visible until this is corrected and {types} are reloaded. Changes to area, category, or labels were not saved and must be reapplied.",
|
||||
"new_automation_setup_keep_waiting": "You may continue to wait for a response from the server, in case it is just taking an unusually long time to process this {type}.",
|
||||
"new_automation_setup_timedout_success": "The server has responded and this has now set up successfully. You may now close this dialog.",
|
||||
"item_pasted": "{item} pasted",
|
||||
|
||||
+73
-8
@@ -167,14 +167,6 @@ test.describe("Panel navigation", () => {
|
||||
});
|
||||
});
|
||||
|
||||
test("navigates to developer-tools panel", async ({ page }) => {
|
||||
// Since 2026.2 developer-tools is part of the config panel
|
||||
await goToPanel(page, "/config/developer-tools");
|
||||
await expect(
|
||||
page.locator("ha-panel-config, developer-tools-main").first()
|
||||
).toBeAttached({ timeout: PANEL_TIMEOUT });
|
||||
});
|
||||
|
||||
test("navigates to profile panel", async ({ page }) => {
|
||||
await goToPanel(page, "/profile");
|
||||
await expect(
|
||||
@@ -183,6 +175,79 @@ test.describe("Panel navigation", () => {
|
||||
});
|
||||
});
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Tools panel (formerly Developer tools)
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Every tool sub-page reachable under /config/tools, mapped to the custom
|
||||
* element tools-router mounts for it (see tools-router.ts). Asserting on the
|
||||
* specific element proves the route actually rendered its tool, not just the
|
||||
* shared ha-panel-tools shell.
|
||||
*/
|
||||
const TOOLS_SUBPAGES: { route: string; element: string }[] = [
|
||||
{ route: "yaml", element: "tools-yaml-config" },
|
||||
{ route: "state", element: "tools-state" },
|
||||
{ route: "action", element: "tools-action" },
|
||||
{ route: "template", element: "tools-template" },
|
||||
{ route: "event", element: "tools-event" },
|
||||
{ route: "statistics", element: "tools-statistics" },
|
||||
{ route: "assist", element: "tools-assist" },
|
||||
{ route: "debug", element: "tools-debug" },
|
||||
];
|
||||
|
||||
test.describe("Tools panel", () => {
|
||||
test("base path renders the tools panel", async ({ page }) => {
|
||||
await goToPanel(page, "/config/tools");
|
||||
await expect(page.locator("ha-panel-tools")).toBeAttached({
|
||||
timeout: PANEL_TIMEOUT,
|
||||
});
|
||||
});
|
||||
|
||||
for (const { route, element } of TOOLS_SUBPAGES) {
|
||||
test(`renders the ${route} sub-page`, async ({ page }) => {
|
||||
await goToPanel(page, `/config/tools/${route}`);
|
||||
await expect(page.locator(element)).toBeAttached({
|
||||
timeout: PANEL_TIMEOUT,
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
test("service is an alias for the action tool", async ({ page }) => {
|
||||
await goToPanel(page, "/config/tools/service");
|
||||
await expect(page.locator("tools-action")).toBeAttached({
|
||||
timeout: PANEL_TIMEOUT,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Tools redirects (old developer-tools URLs)
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
test.describe("Tools redirects", () => {
|
||||
// The panel moved from top-level /developer-tools (pre-2026.2) to
|
||||
// /config/developer-tools (2026.2), then was renamed to /config/tools
|
||||
// (2026.8). Both old locations must redirect to the new one, and deep links
|
||||
// must keep their sub-page. See the updateRoute() redirect in
|
||||
// src/layouts/home-assistant.ts.
|
||||
for (const oldBase of ["/developer-tools", "/config/developer-tools"]) {
|
||||
test(`redirects ${oldBase} to the tools panel`, async ({ page }) => {
|
||||
await goToPanel(page, oldBase);
|
||||
await expect(page.locator("ha-panel-tools")).toBeAttached({
|
||||
timeout: PANEL_TIMEOUT,
|
||||
});
|
||||
});
|
||||
|
||||
test(`redirects ${oldBase}/state to the state tool`, async ({ page }) => {
|
||||
await goToPanel(page, `${oldBase}/state`);
|
||||
await expect(page.locator("tools-state")).toBeAttached({
|
||||
timeout: PANEL_TIMEOUT,
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Lovelace
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
@@ -43,11 +43,4 @@ export const e2eTestPanels: Panels = {
|
||||
config: null,
|
||||
url_path: "profile",
|
||||
},
|
||||
"developer-tools": {
|
||||
component_name: "developer-tools",
|
||||
icon: "mdi:hammer",
|
||||
title: "developer_tools",
|
||||
config: null,
|
||||
url_path: "developer-tools",
|
||||
},
|
||||
};
|
||||
|
||||
@@ -54,7 +54,7 @@ export class HaTest extends HomeAssistantAppEl {
|
||||
: scenarios.default;
|
||||
|
||||
const initial: Partial<MockHomeAssistant> = {
|
||||
// Use the full panel map (history + config + developer-tools enabled)
|
||||
// Use the full panel map (history + config enabled)
|
||||
panels: e2eTestPanels,
|
||||
panelUrl: (() => {
|
||||
const path = window.location.pathname;
|
||||
|
||||
@@ -8565,9 +8565,9 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"eslint-plugin-import-x@npm:4.17.0":
|
||||
version: 4.17.0
|
||||
resolution: "eslint-plugin-import-x@npm:4.17.0"
|
||||
"eslint-plugin-import-x@npm:4.17.1":
|
||||
version: 4.17.1
|
||||
resolution: "eslint-plugin-import-x@npm:4.17.1"
|
||||
dependencies:
|
||||
"@typescript-eslint/types": "npm:^8.56.0"
|
||||
comment-parser: "npm:^1.4.1"
|
||||
@@ -8587,7 +8587,7 @@ __metadata:
|
||||
optional: true
|
||||
eslint-import-resolver-node:
|
||||
optional: true
|
||||
checksum: 10/143081e0a2cb418990d5d61c08ad4dd46f4f10dd7664939cc4be8454c2f51cd69134746d2d8b7534786f3a13857d176456bb0c1d1ffc9c168830b4ce93d2c0a8
|
||||
checksum: 10/1cb95284765cf0ff937f7ab44cf965278939c25dedc72ac41d00d954f4c0bd607bcaffacdeb22a3796aa8f2775c63dd25f818c7f897f061f2339035826cbaf5c
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@@ -9817,7 +9817,7 @@ __metadata:
|
||||
eslint: "npm:10.6.0"
|
||||
eslint-config-prettier: "npm:10.1.8"
|
||||
eslint-import-resolver-webpack: "npm:0.13.11"
|
||||
eslint-plugin-import-x: "npm:4.17.0"
|
||||
eslint-plugin-import-x: "npm:4.17.1"
|
||||
eslint-plugin-lit: "npm:2.3.1"
|
||||
eslint-plugin-lit-a11y: "npm:5.1.1"
|
||||
eslint-plugin-unused-imports: "npm:4.4.1"
|
||||
|
||||
Reference in New Issue
Block a user