mirror of
https://github.com/home-assistant/frontend.git
synced 2025-07-30 04:36:36 +00:00
Merge branch 'dev' of github.com:home-assistant/frontend into color-palettes
This commit is contained in:
commit
35c40360e1
17
package.json
17
package.json
@ -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"
|
||||
}
|
||||
|
@ -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),
|
||||
});
|
||||
|
@ -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) {
|
||||
|
@ -71,6 +71,7 @@ export class HaTemplateSelector extends LitElement {
|
||||
}
|
||||
|
||||
private _handleChange(ev) {
|
||||
ev.stopPropagation();
|
||||
let value = ev.target.value;
|
||||
if (this.value === value) {
|
||||
return;
|
||||
|
@ -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;
|
||||
|
@ -33,6 +33,7 @@ export class HaSelectorUiAction extends LitElement {
|
||||
}
|
||||
|
||||
private _valueChanged(ev: CustomEvent) {
|
||||
ev.stopPropagation();
|
||||
fireEvent(this, "value-changed", { value: ev.detail.value });
|
||||
}
|
||||
}
|
||||
|
@ -33,6 +33,7 @@ export class HaSelectorUiColor extends LitElement {
|
||||
}
|
||||
|
||||
private _valueChanged(ev: CustomEvent) {
|
||||
ev.stopPropagation();
|
||||
fireEvent(this, "value-changed", { value: ev.detail.value });
|
||||
}
|
||||
}
|
||||
|
@ -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"]);
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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() {
|
||||
|
@ -140,7 +140,7 @@ export class HuiActionEditor extends LitElement {
|
||||
.value=${action}
|
||||
@closed=${stopPropagation}
|
||||
fixedMenuPosition
|
||||
naturalMenuWidt
|
||||
naturalMenuWidth
|
||||
>
|
||||
<ha-list-item value="default">
|
||||
${this.hass!.localize(
|
||||
|
@ -25,6 +25,7 @@ export interface GUIModeChangedEvent {
|
||||
export interface ViewEditEvent extends Event {
|
||||
detail: {
|
||||
config: LovelaceViewConfig;
|
||||
valid?: boolean;
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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":
|
||||
|
@ -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 doesn’t support add-ons. If you wan’t to restore these, you have to install Home Assistant Operating System",
|
||||
"addons_unsupported": "Your installation method doesn’t 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"
|
||||
|
Loading…
x
Reference in New Issue
Block a user