Merge branch 'dev' of github.com:home-assistant/frontend into color-palettes

This commit is contained in:
Wendelin 2025-07-28 11:25:09 +02:00
commit 35c40360e1
No known key found for this signature in database
16 changed files with 760 additions and 654 deletions

View File

@ -26,7 +26,7 @@
"license": "Apache-2.0",
"type": "module",
"dependencies": {
"@babel/runtime": "7.27.6",
"@babel/runtime": "7.28.2",
"@braintree/sanitize-url": "7.1.1",
"@codemirror/autocomplete": "6.18.6",
"@codemirror/commands": "6.8.1",
@ -154,13 +154,13 @@
"@babel/plugin-transform-runtime": "7.28.0",
"@babel/preset-env": "7.28.0",
"@bundle-stats/plugin-webpack-filter": "4.21.0",
"@lokalise/node-api": "14.9.1",
"@lokalise/node-api": "15.0.0",
"@octokit/auth-oauth-device": "8.0.1",
"@octokit/plugin-retry": "8.0.1",
"@octokit/rest": "22.0.0",
"@rsdoctor/rspack-plugin": "1.1.8",
"@rspack/cli": "1.4.8",
"@rspack/core": "1.4.8",
"@rsdoctor/rspack-plugin": "1.1.10",
"@rspack/cli": "1.4.10",
"@rspack/core": "1.4.10",
"@types/babel__plugin-transform-runtime": "7.9.5",
"@types/chromecast-caf-receiver": "6.0.22",
"@types/chromecast-caf-sender": "1.0.11",
@ -190,7 +190,7 @@
"eslint-import-resolver-webpack": "0.13.10",
"eslint-plugin-import": "2.32.0",
"eslint-plugin-lit": "2.1.1",
"eslint-plugin-lit-a11y": "5.1.0",
"eslint-plugin-lit-a11y": "5.1.1",
"eslint-plugin-unused-imports": "4.1.4",
"eslint-plugin-wc": "3.0.1",
"fancy-log": "2.0.0",
@ -218,7 +218,7 @@
"terser-webpack-plugin": "5.3.14",
"ts-lit-plugin": "2.0.2",
"typescript": "5.8.3",
"typescript-eslint": "8.37.0",
"typescript-eslint": "8.38.0",
"vite-tsconfig-paths": "5.1.4",
"vitest": "3.2.4",
"webpack-stats-plugin": "1.1.3",
@ -234,7 +234,8 @@
"@fullcalendar/daygrid": "6.1.18",
"globals": "16.3.0",
"tslib": "2.8.1",
"@material/mwc-list@^0.27.0": "patch:@material/mwc-list@npm%3A0.27.0#~/.yarn/patches/@material-mwc-list-npm-0.27.0-5344fc9de4.patch"
"@material/mwc-list@^0.27.0": "patch:@material/mwc-list@npm%3A0.27.0#~/.yarn/patches/@material-mwc-list-npm-0.27.0-5344fc9de4.patch",
"@vaadin/vaadin-themable-mixin": "24.7.9"
},
"packageManager": "yarn@4.9.2"
}

View File

@ -95,6 +95,7 @@ export class HaColorTempSelector extends LitElement {
);
private _valueChanged(ev: CustomEvent) {
ev.stopPropagation();
fireEvent(this, "value-changed", {
value: Number((ev.detail as any).value),
});

View File

@ -279,6 +279,7 @@ export class HaObjectSelector extends LitElement {
}
private _handleChange(ev) {
ev.stopPropagation();
this._valueChangedFromChild = true;
const value = ev.target.value;
if (!ev.target.isValid) {

View File

@ -71,6 +71,7 @@ export class HaTemplateSelector extends LitElement {
}
private _handleChange(ev) {
ev.stopPropagation();
let value = ev.target.value;
if (this.value === value) {
return;

View File

@ -111,6 +111,7 @@ export class HaTextSelector extends LitElement {
}
private _handleChange(ev) {
ev.stopPropagation();
let value = ev.detail?.value ?? ev.target.value;
if (this.value === value) {
return;

View File

@ -33,6 +33,7 @@ export class HaSelectorUiAction extends LitElement {
}
private _valueChanged(ev: CustomEvent) {
ev.stopPropagation();
fireEvent(this, "value-changed", { value: ev.detail.value });
}
}

View File

@ -33,6 +33,7 @@ export class HaSelectorUiColor extends LitElement {
}
private _valueChanged(ev: CustomEvent) {
ev.stopPropagation();
fireEvent(this, "value-changed", { value: ev.detail.value });
}
}

View File

@ -146,7 +146,12 @@ const cloudyStates = new Set<string>([
"lightning-rainy",
]);
const rainStates = new Set<string>(["hail", "rainy", "pouring"]);
const rainStates = new Set<string>([
"hail",
"rainy",
"pouring",
"lightning-rainy",
]);
const windyStates = new Set<string>(["windy", "windy-variant"]);

View File

@ -1,9 +1,19 @@
import { mdiDotsVertical, mdiDownload } from "@mdi/js";
import type { TemplateResult } from "lit";
import { css, html, LitElement } from "lit";
import { css, html, LitElement, nothing } from "lit";
import { customElement, property } from "lit/decorators";
import "../../../components/ha-button-menu";
import "../../../components/ha-icon-button";
import "../../../components/ha-list-item";
import "../../../components/ha-svg-icon";
import { getSignedPath } from "../../../data/auth";
import "../../../layouts/hass-subpage";
import type { HomeAssistant, Route } from "../../../types";
import "./ha-config-analytics";
import {
downloadFileSupported,
fileDownload,
} from "../../../util/file_download";
@customElement("ha-config-section-analytics")
class HaConfigSectionAnalytics extends LitElement {
@ -21,6 +31,26 @@ class HaConfigSectionAnalytics extends LitElement {
.narrow=${this.narrow}
.header=${this.hass.localize("ui.panel.config.analytics.caption")}
>
${downloadFileSupported(this.hass)
? html`
<ha-button-menu
@action=${this._handleOverflowAction}
slot="toolbar-icon"
>
<ha-icon-button slot="trigger" .path=${mdiDotsVertical}>
</ha-icon-button>
<ha-list-item graphic="icon">
<ha-svg-icon
slot="graphic"
.path=${mdiDownload}
></ha-svg-icon>
${this.hass.localize(
"ui.panel.config.analytics.download_device_info"
)}
</ha-list-item>
</ha-button-menu>
`
: nothing}
<div class="content">
<ha-config-analytics .hass=${this.hass}></ha-config-analytics>
</div>
@ -28,6 +58,11 @@ class HaConfigSectionAnalytics extends LitElement {
`;
}
private async _handleOverflowAction(): Promise<void> {
const signedPath = await getSignedPath(this.hass, "/api/analytics/devices");
fileDownload(signedPath.path);
}
static styles = css`
.content {
padding: 28px 20px 0;

View File

@ -97,15 +97,12 @@ class AddIntegrationDialog extends LitElement {
public async showDialog(params?: AddIntegrationDialogParams): Promise<void> {
const loadPromise = this._load();
this._open = true;
this._pickedBrand = params?.brand;
this._initialFilter = params?.initialFilter;
this._narrow = matchMedia(
"all and (max-width: 450px), all and (max-height: 500px)"
).matches;
if (params?.domain) {
this._createFlow(params.domain);
// Just open the config flow dialog, do not show this dialog
await this._createFlow(params.domain);
return;
}
if (params?.brand) {
await loadPromise;
const brand = this._integrations?.[params.brand];
@ -113,6 +110,13 @@ class AddIntegrationDialog extends LitElement {
this._fetchFlowsInProgress(Object.keys(brand.integrations));
}
}
// Only open the dialog if no domain is provided
this._open = true;
this._pickedBrand = params?.brand;
this._initialFilter = params?.initialFilter;
this._narrow = matchMedia(
"all and (max-width: 450px), all and (max-height: 500px)"
).matches;
}
public closeDialog() {

View File

@ -140,7 +140,7 @@ export class HuiActionEditor extends LitElement {
.value=${action}
@closed=${stopPropagation}
fixedMenuPosition
naturalMenuWidt
naturalMenuWidth
>
<ha-list-item value="default">
${this.hass!.localize(

View File

@ -25,6 +25,7 @@ export interface GUIModeChangedEvent {
export interface ViewEditEvent extends Event {
detail: {
config: LovelaceViewConfig;
valid?: boolean;
};
}

View File

@ -73,6 +73,8 @@ export class HuiDialogEditView extends LitElement {
@state() private _dirty = false;
@state() private _valid = true;
@state() private _yamlMode = false;
@query("ha-yaml-editor") private _editor?: HaYamlEditor;
@ -308,6 +310,7 @@ export class HuiDialogEditView extends LitElement {
?disabled=${!this._config ||
this._saving ||
!this._dirty ||
!this._valid ||
convertToSection ||
convertNotSupported}
@click=${this._save}
@ -579,6 +582,9 @@ export class HuiDialogEditView extends LitElement {
ev.detail.config &&
!deepEqual(this._config, ev.detail.config)
) {
if (ev.detail.valid !== undefined) {
this._valid = ev.detail.valid;
}
this._config = ev.detail.config;
this._dirty = true;
}

View File

@ -23,10 +23,13 @@ declare global {
interface HASSDomEvents {
"view-config-changed": {
config: LovelaceViewConfig;
valid?: boolean;
};
}
}
const VALID_PATH_REGEX = /^[a-zA-Z0-9_-]+$/;
@customElement("hui-view-editor")
export class HuiViewEditor extends LitElement {
@property({ attribute: false }) public hass!: HomeAssistant;
@ -35,6 +38,8 @@ export class HuiViewEditor extends LitElement {
@state() private _config!: LovelaceViewConfig;
@state() private _error: Record<string, string> | undefined;
private _suggestedPath = false;
private _schema = memoizeOne(
@ -144,6 +149,8 @@ export class HuiViewEditor extends LitElement {
.schema=${schema}
.computeLabel=${this._computeLabel}
.computeHelper=${this._computeHelper}
.computeError=${this._computeError}
.error=${this._error}
@value-changed=${this._valueChanged}
></ha-form>
`;
@ -168,9 +175,20 @@ export class HuiViewEditor extends LitElement {
config.path = slugify(config.title || "", "-");
}
fireEvent(this, "view-config-changed", { config });
let valid = true;
this._error = undefined;
if (config.path && !VALID_PATH_REGEX.test(config.path)) {
valid = false;
this._error = { path: "error_invalid_path" };
}
fireEvent(this, "view-config-changed", { valid, config });
}
private _computeError = (error: string) =>
this.hass.localize(`ui.panel.lovelace.editor.edit_view.${error}` as any) ||
error;
private _computeLabel = (
schema: SchemaUnion<ReturnType<typeof this._schema>>
) => {
@ -197,6 +215,7 @@ export class HuiViewEditor extends LitElement {
schema: SchemaUnion<ReturnType<typeof this._schema>>
) => {
switch (schema.name) {
case "path":
case "subview":
case "dense_section_placement":
case "top_margin":

View File

@ -6541,7 +6541,8 @@
},
"need_base_enabled": "You need to enable basic analytics for this option to be available",
"learn_more": "How we process your data",
"intro": "Share anonymized information from your installation to help make Home Assistant better and help us convince manufacturers to add local control and privacy-focused features."
"intro": "Share anonymized information from your installation to help make Home Assistant better and help us convince manufacturers to add local control and privacy-focused features.",
"download_device_info": "Preview device analytics"
},
"network": {
"caption": "Network",
@ -7028,10 +7029,12 @@
"top_margin": "Add additional space above",
"top_margin_helper": "Helps reveal more of the background",
"subview_helper": "Subviews don't appear in tabs and have a back button.",
"path_helper": "This value will become part of the URL path to open this view.",
"edit_ui": "Edit in visual editor",
"edit_yaml": "Edit in YAML",
"saving_failed": "Saving failed",
"error_same_url": "You cannot save a view with the same URL as a different existing view.",
"error_invalid_path": "URL contains invalid/reserved characters. Please enter a simple string only for the path of this view.",
"move_to_dashboard": "Move to dashboard"
},
"edit_view_header": {
@ -8849,7 +8852,7 @@
"uploading": "[%key:ui::components::file-upload::uploading%]",
"details": {
"home_assistant_missing": "This backup does not include your Home Assistant configuration, you cannot use it to restore your instance.",
"addons_unsupported": "Your installation method doesnt support add-ons. If you want to restore these, you have to install Home Assistant Operating System",
"addons_unsupported": "Your installation method doesnt support add-ons. If you want to restore these, you have to install Home Assistant Operating System",
"summary": {
"created": "[%key:ui::panel::config::backup::details::summary::created%]",
"content": "Content"

1292
yarn.lock

File diff suppressed because it is too large Load Diff