mirror of
https://github.com/home-assistant/frontend.git
synced 2025-09-28 22:39:33 +00:00
Compare commits
17 Commits
graph-samp
...
20250925.1
Author | SHA1 | Date | |
---|---|---|---|
![]() |
bab0391a19 | ||
![]() |
444123c47e | ||
![]() |
f123d34046 | ||
![]() |
1b40f99f68 | ||
![]() |
b314b3ed2b | ||
![]() |
59b8932969 | ||
![]() |
107af753ec | ||
![]() |
1f0acb3046 | ||
![]() |
431e533929 | ||
![]() |
02c845cbc6 | ||
![]() |
628111ed20 | ||
![]() |
e825a9c02f | ||
![]() |
7a35bddf36 | ||
![]() |
ad69270af8 | ||
![]() |
404edf9483 | ||
![]() |
a166b4e9b6 | ||
![]() |
7a285f11db |
@@ -5,17 +5,17 @@ const castContext = framework.CastReceiverContext.getInstance();
|
||||
const playerManager = castContext.getPlayerManager();
|
||||
|
||||
playerManager.setMessageInterceptor(
|
||||
"LOAD" as framework.messages.MessageType.LOAD,
|
||||
framework.messages.MessageType.LOAD,
|
||||
(loadRequestData) => {
|
||||
const media = loadRequestData.media;
|
||||
// Special handling if it came from Google Assistant
|
||||
if (media.entity) {
|
||||
media.contentId = media.entity;
|
||||
media.streamType = "LIVE" as framework.messages.StreamType.LIVE;
|
||||
media.streamType = framework.messages.StreamType.LIVE;
|
||||
media.contentType = "application/vnd.apple.mpegurl";
|
||||
// @ts-ignore
|
||||
media.hlsVideoSegmentFormat =
|
||||
"fmp4" as framework.messages.HlsVideoSegmentFormat.FMP4;
|
||||
framework.messages.HlsVideoSegmentFormat.FMP4;
|
||||
}
|
||||
return loadRequestData;
|
||||
}
|
||||
|
@@ -40,8 +40,7 @@ const playDummyMedia = (viewTitle?: string) => {
|
||||
loadRequestData.media.contentId =
|
||||
"https://cast.home-assistant.io/images/google-nest-hub.png";
|
||||
loadRequestData.media.contentType = "image/jpeg";
|
||||
loadRequestData.media.streamType =
|
||||
"NONE" as framework.messages.StreamType.NONE;
|
||||
loadRequestData.media.streamType = framework.messages.StreamType.NONE;
|
||||
const metadata = new framework.messages.GenericMediaMetadata();
|
||||
metadata.title = viewTitle;
|
||||
loadRequestData.media.metadata = metadata;
|
||||
@@ -90,7 +89,7 @@ const showMediaPlayer = () => {
|
||||
const options = new framework.CastReceiverOptions();
|
||||
options.disableIdleTimeout = true;
|
||||
options.customNamespaces = {
|
||||
[CAST_NS]: "json" as framework.system.MessageType.JSON,
|
||||
[CAST_NS]: framework.system.MessageType.JSON,
|
||||
};
|
||||
|
||||
castContext.addCustomMessageListener(
|
||||
@@ -98,7 +97,9 @@ castContext.addCustomMessageListener(
|
||||
// @ts-ignore
|
||||
(ev: ReceivedMessage<HassMessage>) => {
|
||||
// We received a show Lovelace command, stop media from playing, hide media player and show Lovelace controller
|
||||
if (playerManager.getPlayerState() !== "IDLE") {
|
||||
if (
|
||||
playerManager.getPlayerState() !== framework.messages.PlayerState.IDLE
|
||||
) {
|
||||
playerManager.stop();
|
||||
} else {
|
||||
showLovelaceController();
|
||||
@@ -112,7 +113,7 @@ castContext.addCustomMessageListener(
|
||||
const playerManager = castContext.getPlayerManager();
|
||||
|
||||
playerManager.setMessageInterceptor(
|
||||
"LOAD" as framework.messages.MessageType.LOAD,
|
||||
framework.messages.MessageType.LOAD,
|
||||
(loadRequestData) => {
|
||||
if (
|
||||
loadRequestData.media.contentId ===
|
||||
@@ -126,23 +127,24 @@ playerManager.setMessageInterceptor(
|
||||
// Special handling if it came from Google Assistant
|
||||
if (media.entity) {
|
||||
media.contentId = media.entity;
|
||||
media.streamType = "LIVE" as framework.messages.StreamType.LIVE;
|
||||
media.streamType = framework.messages.StreamType.LIVE;
|
||||
media.contentType = "application/vnd.apple.mpegurl";
|
||||
// @ts-ignore
|
||||
media.hlsVideoSegmentFormat =
|
||||
"fmp4" as framework.messages.HlsVideoSegmentFormat.FMP4;
|
||||
framework.messages.HlsVideoSegmentFormat.FMP4;
|
||||
}
|
||||
return loadRequestData;
|
||||
}
|
||||
);
|
||||
|
||||
playerManager.addEventListener(
|
||||
"MEDIA_STATUS" as framework.events.EventType.MEDIA_STATUS,
|
||||
framework.events.EventType.MEDIA_STATUS,
|
||||
(event) => {
|
||||
if (
|
||||
event.mediaStatus?.playerState === "IDLE" &&
|
||||
event.mediaStatus?.playerState === framework.messages.PlayerState.IDLE &&
|
||||
event.mediaStatus?.idleReason &&
|
||||
event.mediaStatus?.idleReason !== "INTERRUPTED"
|
||||
event.mediaStatus?.idleReason !==
|
||||
framework.messages.IdleReason.INTERRUPTED
|
||||
) {
|
||||
// media finished or stopped, return to default Lovelace
|
||||
showLovelaceController();
|
||||
|
@@ -161,7 +161,7 @@
|
||||
"@rspack/core": "1.5.5",
|
||||
"@rspack/dev-server": "1.1.4",
|
||||
"@types/babel__plugin-transform-runtime": "7.9.5",
|
||||
"@types/chromecast-caf-receiver": "6.0.24",
|
||||
"@types/chromecast-caf-receiver": "6.0.22",
|
||||
"@types/chromecast-caf-sender": "1.0.11",
|
||||
"@types/color-name": "2.0.0",
|
||||
"@types/culori": "4.0.1",
|
||||
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
||||
|
||||
[project]
|
||||
name = "home-assistant-frontend"
|
||||
version = "20250924.0"
|
||||
version = "20250925.1"
|
||||
license = "Apache-2.0"
|
||||
license-files = ["LICENSE*"]
|
||||
description = "The Home Assistant frontend"
|
||||
|
@@ -1,5 +1,5 @@
|
||||
import type { CSSResultGroup, TemplateResult } from "lit";
|
||||
import { css, html, LitElement } from "lit";
|
||||
import { css, html, LitElement, nothing } from "lit";
|
||||
import { customElement, property } from "lit/decorators";
|
||||
import { fireEvent } from "../common/dom/fire_event";
|
||||
import type { LocalizeFunc } from "../common/translations/localize";
|
||||
@@ -73,14 +73,18 @@ export class HaAnalytics extends LitElement {
|
||||
.checked=${this.analytics?.preferences[preference]}
|
||||
.preference=${preference}
|
||||
name=${preference}
|
||||
?disabled=${baseEnabled}
|
||||
>
|
||||
</ha-switch>
|
||||
<ha-tooltip .for="switch-${preference}" placement="right">
|
||||
${this.localize(
|
||||
`ui.panel.${this.translationKeyPanel}.analytics.need_base_enabled`
|
||||
)}
|
||||
</ha-tooltip>
|
||||
${baseEnabled
|
||||
? nothing
|
||||
: html`<ha-tooltip
|
||||
.for="switch-${preference}"
|
||||
placement="right"
|
||||
>
|
||||
${this.localize(
|
||||
`ui.panel.${this.translationKeyPanel}.analytics.need_base_enabled`
|
||||
)}
|
||||
</ha-tooltip>`}
|
||||
</span>
|
||||
</ha-settings-row>
|
||||
`
|
||||
|
@@ -54,9 +54,9 @@ export class HaBottomSheet extends LitElement {
|
||||
border-top-left-radius: var(--ha-border-radius-lg);
|
||||
border-top-right-radius: var(--ha-border-radius-lg);
|
||||
max-height: 90vh;
|
||||
margin-bottom: var(--safe-area-inset-bottom);
|
||||
margin-left: var(--safe-area-inset-left);
|
||||
margin-right: var(--safe-area-inset-right);
|
||||
padding-bottom: var(--safe-area-inset-bottom);
|
||||
padding-left: var(--safe-area-inset-left);
|
||||
padding-right: var(--safe-area-inset-right);
|
||||
}
|
||||
`;
|
||||
}
|
||||
|
@@ -39,22 +39,24 @@ class HaSegmentedBar extends LitElement {
|
||||
<slot name="extra"></slot>
|
||||
</div>
|
||||
<div class="bar">
|
||||
${this.segments.map((segment) => {
|
||||
const bar = html`<div
|
||||
style=${styleMap({
|
||||
width: `${(segment.value / totalValue) * 100}%`,
|
||||
backgroundColor: segment.color,
|
||||
})}
|
||||
></div>`;
|
||||
return this.hideTooltip && !segment.label
|
||||
? bar
|
||||
: html`
|
||||
<ha-tooltip>
|
||||
<span slot="content">${segment.label}</span>
|
||||
${bar}
|
||||
</ha-tooltip>
|
||||
`;
|
||||
})}
|
||||
${this.segments.map(
|
||||
(segment, index) => html`
|
||||
${this.hideTooltip || !segment.label
|
||||
? nothing
|
||||
: html`
|
||||
<ha-tooltip for="segment-${index}" placement="top">
|
||||
${segment.label}
|
||||
</ha-tooltip>
|
||||
`}
|
||||
<div
|
||||
id="segment-${index}"
|
||||
style=${styleMap({
|
||||
width: `${(segment.value / totalValue) * 100}%`,
|
||||
backgroundColor: segment.color,
|
||||
})}
|
||||
></div>
|
||||
`
|
||||
)}
|
||||
</div>
|
||||
${this.hideLegend
|
||||
? nothing
|
||||
|
@@ -18,6 +18,8 @@ export class HaTabGroupTab extends Tab {
|
||||
opacity: 0.8;
|
||||
|
||||
color: inherit;
|
||||
|
||||
--wa-space-l: 16px;
|
||||
}
|
||||
|
||||
:host([active]:not([disabled])) {
|
||||
|
@@ -4,6 +4,7 @@ export interface LovelaceBadgeConfig {
|
||||
type: string;
|
||||
[key: string]: any;
|
||||
visibility?: Condition[];
|
||||
disabled?: boolean;
|
||||
}
|
||||
|
||||
export const ensureBadgeConfig = (
|
||||
|
@@ -4,7 +4,7 @@ import type { Action } from "./script";
|
||||
export const callExecuteScript = (
|
||||
hass: HomeAssistant,
|
||||
sequence: Action | Action[]
|
||||
): Promise<{ context: Context; response: Record<string, any> }> =>
|
||||
): Promise<{ context: Context; response: Record<string, any> | null }> =>
|
||||
hass.callWS({
|
||||
type: "execute_script",
|
||||
sequence,
|
||||
|
@@ -171,7 +171,7 @@ export default class HaAutomationSidebar extends LitElement {
|
||||
@mousedown=${this._handleMouseDown}
|
||||
@touchstart=${this._handleMouseDown}
|
||||
>
|
||||
${this._resizing ? html`<div class="indicator"></div>` : nothing}
|
||||
<div class="indicator ${this._resizing ? "" : "hidden"}"></div>
|
||||
</div>
|
||||
${this._renderContent()}
|
||||
`;
|
||||
@@ -333,6 +333,15 @@ export default class HaAutomationSidebar extends LitElement {
|
||||
height: 100%;
|
||||
width: 4px;
|
||||
border-radius: var(--ha-border-radius-pill);
|
||||
transform: scale3d(1, 1, 1);
|
||||
opacity: 1;
|
||||
transition:
|
||||
transform 180ms ease-in-out,
|
||||
opacity 180ms ease-in-out;
|
||||
}
|
||||
.handle .indicator.hidden {
|
||||
transform: scale3d(0, 1, 1);
|
||||
opacity: 0;
|
||||
}
|
||||
`;
|
||||
}
|
||||
|
@@ -260,7 +260,7 @@ class DialogPersonDetail extends LitElement implements HassDialog {
|
||||
>
|
||||
${this._params.entry
|
||||
? this.hass!.localize("ui.common.save")
|
||||
: this.hass!.localize("ui.panel.config.person.detail.create")}
|
||||
: this.hass!.localize("ui.common.add")}
|
||||
</ha-button>
|
||||
</ha-dialog>
|
||||
`;
|
||||
|
@@ -51,7 +51,7 @@ class HaPanelDevAction extends LitElement {
|
||||
@state() private _response?: {
|
||||
domain: string;
|
||||
service: string;
|
||||
result: Record<string, any>;
|
||||
result: Record<string, any> | null;
|
||||
media?: Promise<TemplateResult | typeof nothing>;
|
||||
};
|
||||
|
||||
@@ -205,7 +205,7 @@ class HaPanelDevAction extends LitElement {
|
||||
</ha-progress-button>
|
||||
</div>
|
||||
</div>
|
||||
${this._response
|
||||
${this._response?.result
|
||||
? html`<div class="content response">
|
||||
<ha-card
|
||||
.header=${this.hass.localize(
|
||||
@@ -491,7 +491,7 @@ class HaPanelDevAction extends LitElement {
|
||||
service,
|
||||
result,
|
||||
media:
|
||||
"media_source_id" in result
|
||||
result && "media_source_id" in result
|
||||
? resolveMediaSource(this.hass, result.media_source_id).then(
|
||||
(resolved) =>
|
||||
resolved.mime_type.startsWith("image/")
|
||||
|
@@ -161,7 +161,7 @@ export class HuiBadge extends ReactiveElement {
|
||||
);
|
||||
}
|
||||
|
||||
private _updateVisibility(forceVisible?: boolean) {
|
||||
private _updateVisibility(ignoreConditions?: boolean) {
|
||||
if (!this._element || !this.hass) {
|
||||
return;
|
||||
}
|
||||
@@ -171,9 +171,18 @@ export class HuiBadge extends ReactiveElement {
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.preview) {
|
||||
this._setElementVisibility(true);
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.config?.disabled) {
|
||||
this._setElementVisibility(false);
|
||||
return;
|
||||
}
|
||||
|
||||
const visible =
|
||||
forceVisible ||
|
||||
this.preview ||
|
||||
ignoreConditions ||
|
||||
!this.config?.visibility ||
|
||||
checkConditionsMet(this.config.visibility, this.hass);
|
||||
this._setElementVisibility(visible);
|
||||
|
@@ -1,6 +1,7 @@
|
||||
import { object, string, any } from "superstruct";
|
||||
import { object, string, any, optional, boolean } from "superstruct";
|
||||
|
||||
export const baseLovelaceBadgeConfig = object({
|
||||
type: string(),
|
||||
visibility: any(),
|
||||
disabled: optional(boolean()),
|
||||
});
|
||||
|
@@ -1,4 +1,4 @@
|
||||
import { object, string, any } from "superstruct";
|
||||
import { object, string, any, optional, boolean } from "superstruct";
|
||||
|
||||
export const baseLovelaceCardConfig = object({
|
||||
type: string(),
|
||||
@@ -6,4 +6,5 @@ export const baseLovelaceCardConfig = object({
|
||||
layout_options: any(),
|
||||
grid_options: any(),
|
||||
visibility: any(),
|
||||
disabled: optional(boolean()),
|
||||
});
|
||||
|
@@ -4,13 +4,14 @@ import { isComponentLoaded } from "../../../../common/config/is_component_loaded
|
||||
import type { LovelaceSectionConfig } from "../../../../data/lovelace/config/section";
|
||||
import { getCommonControlUsagePrediction } from "../../../../data/usage_prediction";
|
||||
import type { HomeAssistant } from "../../../../types";
|
||||
import type { TileCardConfig } from "../../cards/types";
|
||||
import type { HeadingCardConfig, TileCardConfig } from "../../cards/types";
|
||||
|
||||
const DEFAULT_LIMIT = 8;
|
||||
|
||||
export interface CommonControlSectionStrategyConfig {
|
||||
type: "common-controls";
|
||||
title?: string;
|
||||
icon?: string;
|
||||
limit?: number;
|
||||
exclude_entities?: string[];
|
||||
hide_empty?: boolean;
|
||||
@@ -31,7 +32,8 @@ export class CommonControlsSectionStrategy extends ReactiveElement {
|
||||
section.cards?.push({
|
||||
type: "heading",
|
||||
heading: config.title,
|
||||
});
|
||||
icon: config.icon,
|
||||
} satisfies HeadingCardConfig);
|
||||
}
|
||||
|
||||
if (!isComponentLoaded(hass, "usage_prediction")) {
|
||||
@@ -46,7 +48,9 @@ export class CommonControlsSectionStrategy extends ReactiveElement {
|
||||
}
|
||||
|
||||
const predictedCommonControl = await getCommonControlUsagePrediction(hass);
|
||||
let predictedEntities = predictedCommonControl.entities;
|
||||
let predictedEntities = predictedCommonControl.entities.filter(
|
||||
(entity) => entity in hass.states
|
||||
);
|
||||
|
||||
if (config.exclude_entities) {
|
||||
predictedEntities = predictedEntities.filter(
|
||||
|
@@ -1,3 +1,4 @@
|
||||
import scrollLockStyles from "@home-assistant/webawesome/dist/styles/utilities/scroll-lock.css.js";
|
||||
import { css } from "lit";
|
||||
import { extractDerivedVars } from "../../common/style/derived-css-vars";
|
||||
|
||||
@@ -18,6 +19,8 @@ export const waMainStyles = css`
|
||||
--wa-border-width-l: var(--ha-border-radius-l);
|
||||
--wa-space-xl: 32px;
|
||||
}
|
||||
|
||||
${scrollLockStyles}
|
||||
`;
|
||||
|
||||
export const waMainDerivedVariables = extractDerivedVars(waMainStyles);
|
||||
|
@@ -5365,7 +5365,7 @@
|
||||
"person_not_found_title": "Person not found",
|
||||
"person_not_found": "We couldn't find the person you were trying to edit.",
|
||||
"detail": {
|
||||
"new_person": "New person",
|
||||
"new_person": "Add person",
|
||||
"name": "Name",
|
||||
"name_error_msg": "Name is required",
|
||||
"linked_user": "Linked user",
|
||||
@@ -5376,7 +5376,6 @@
|
||||
"device_tracker_picked": "Track device",
|
||||
"device_tracker_pick": "Pick device to track",
|
||||
"delete": "Delete",
|
||||
"create": "Create",
|
||||
"update": "Update",
|
||||
"confirm_delete_user_title": "Delete user account",
|
||||
"confirm_delete_user_text": "The user account for ''{name}'' will be permanently deleted. You can still track the user, but the person will no longer be able to log in.",
|
||||
|
10
yarn.lock
10
yarn.lock
@@ -4491,10 +4491,10 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@types/chromecast-caf-receiver@npm:6.0.24":
|
||||
version: 6.0.24
|
||||
resolution: "@types/chromecast-caf-receiver@npm:6.0.24"
|
||||
checksum: 10/1f2b95e8a15dbb36d5328895229d4a5cb255b33e62d46335bd6ed75e16aa9ea6a7d765a64ae120d19b3134fb3e51e9547d2544c7277f7bffe0bf0b3999f026da
|
||||
"@types/chromecast-caf-receiver@npm:6.0.22":
|
||||
version: 6.0.22
|
||||
resolution: "@types/chromecast-caf-receiver@npm:6.0.22"
|
||||
checksum: 10/6c51cb52527776ddfa187a261b88184c98bdd61c129dd8719cba213894d565cf69073734d6473696ffd60a768f6fb5a3fe9932693f43174fbc5e7af201db8a90
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@@ -9442,7 +9442,7 @@ __metadata:
|
||||
"@tsparticles/engine": "npm:3.9.1"
|
||||
"@tsparticles/preset-links": "npm:3.2.0"
|
||||
"@types/babel__plugin-transform-runtime": "npm:7.9.5"
|
||||
"@types/chromecast-caf-receiver": "npm:6.0.24"
|
||||
"@types/chromecast-caf-receiver": "npm:6.0.22"
|
||||
"@types/chromecast-caf-sender": "npm:1.0.11"
|
||||
"@types/color-name": "npm:2.0.0"
|
||||
"@types/culori": "npm:4.0.1"
|
||||
|
Reference in New Issue
Block a user