Compare commits

..

8 Commits

Author SHA1 Message Date
Bram Kragten
b01ab9234b Bumped version to 20250731.0 2025-07-31 16:54:24 +02:00
Wendelin
ad39228dea Fix line-height, fix script editor buttons (#26337)
* Fix line-height

* Fix script root buttons
2025-07-31 16:54:03 +02:00
Wendelin
8cc48cdecb Use tilecard button feature editor (#26335)
Use button feature editor
2025-07-31 16:54:02 +02:00
Wendelin
524e89acf0 Revert "Use query params instead of path for media browser navigate ids" (#26333) 2025-07-31 16:54:01 +02:00
Wendelin
48f6b34882 Fix ha-button with missing label and links (#26332) 2025-07-31 16:54:00 +02:00
Bram Kragten
44d9185574 Fix area picker text alignment in voice wizard (#26330) 2025-07-31 16:53:59 +02:00
Joost Lekkerkerker
51ff6c6564 Use underscores in AI task name (#26327) 2025-07-31 16:53:58 +02:00
Franck Nijhof
b49b8e3db8 Add weekdays to time trigger (#25908)
* Add weekdays to time trigger

* Update src/translations/en.json

Co-authored-by: Norbert Rittel <norbert@rittel.de>

* Localization changes

---------

Co-authored-by: Norbert Rittel <norbert@rittel.de>
Co-authored-by: Simon Lamon <32477463+silamon@users.noreply.github.com>
2025-07-31 16:53:57 +02:00
79 changed files with 1314 additions and 1639 deletions

View File

@ -74,7 +74,7 @@ jobs:
echo "home-assistant-frontend==$version" > ./requirements.txt echo "home-assistant-frontend==$version" > ./requirements.txt
- name: Build wheels - name: Build wheels
uses: home-assistant/wheels@2025.07.0 uses: home-assistant/wheels@2025.03.0
with: with:
abi: cp313 abi: cp313
tag: musllinux_1_2 tag: musllinux_1_2

View File

@ -1,8 +0,0 @@
# People marked here will be automatically requested for a review
# when the code that they own is touched.
# https://github.com/blog/2392-introducing-code-owners
# https://docs.github.com/en/repositories/managing-your-repositorys-settings-and-features/customizing-your-repository/about-code-owners
# Part of the frontend that mobile developper should review
src/external_app/ @bgoncal @TimoPtr
test/external_app/ @bgoncal @TimoPtr

View File

@ -64,4 +64,4 @@ Check the [webawesome documentation](https://webawesome.com/docs/components/butt
**CSS Custom Properties** **CSS Custom Properties**
- `--ha-button-height` - Height of the button. - `--ha-button-height` - Height of the button.
- `--ha-button-border-radius` - Border radius of the button. Defaults to `var(--ha-border-radius-pill)`. - `--ha-button-radius` - Border radius of the button. Defaults to `var(--wa-border-radius-pill)`.

View File

@ -21,8 +21,8 @@ import type { HomeAssistant } from "../../../../src/types";
import type { HassioDatatiskDialogParams } from "./show-dialog-hassio-datadisk"; import type { HassioDatatiskDialogParams } from "./show-dialog-hassio-datadisk";
const calculateMoveTime = memoizeOne((supervisor: Supervisor): number => { const calculateMoveTime = memoizeOne((supervisor: Supervisor): number => {
// Assume a speed of 30 MB/s. const speed = supervisor.host.disk_life_time !== "" ? 30 : 10;
const moveTime = (supervisor.host.disk_used * 1000) / 60 / 30; const moveTime = (supervisor.host.disk_used * 1000) / 60 / speed;
const rebootTime = (supervisor.host.startup_time * 4) / 60; const rebootTime = (supervisor.host.startup_time * 4) / 60;
return Math.ceil((moveTime + rebootTime) / 10) * 10; return Math.ceil((moveTime + rebootTime) / 10) * 10;
}); });

View File

@ -2,13 +2,13 @@ import { mdiDelete, mdiPlus } from "@mdi/js";
import type { CSSResultGroup, TemplateResult } from "lit"; import type { CSSResultGroup, TemplateResult } from "lit";
import { css, html, LitElement } from "lit"; import { css, html, LitElement } from "lit";
import { customElement, property, state } from "lit/decorators"; import { customElement, property, state } from "lit/decorators";
import "../../../../src/components/ha-button";
import { createCloseHeading } from "../../../../src/components/ha-dialog"; import { createCloseHeading } from "../../../../src/components/ha-dialog";
import "../../../../src/components/ha-form/ha-form"; import "../../../../src/components/ha-form/ha-form";
import type { SchemaUnion } from "../../../../src/components/ha-form/types"; import type { SchemaUnion } from "../../../../src/components/ha-form/types";
import "../../../../src/components/ha-icon-button"; import "../../../../src/components/ha-icon-button";
import "../../../../src/components/ha-settings-row"; import "../../../../src/components/ha-button";
import "../../../../src/components/ha-svg-icon"; import "../../../../src/components/ha-svg-icon";
import "../../../../src/components/ha-settings-row";
import { extractApiErrorMessage } from "../../../../src/data/hassio/common"; import { extractApiErrorMessage } from "../../../../src/data/hassio/common";
import { import {
addHassioDockerRegistry, addHassioDockerRegistry,

View File

@ -7,14 +7,10 @@ import { fireEvent } from "../../../../src/common/dom/fire_event";
import { caseInsensitiveStringCompare } from "../../../../src/common/string/compare"; import { caseInsensitiveStringCompare } from "../../../../src/common/string/compare";
import "../../../../src/components/ha-alert"; import "../../../../src/components/ha-alert";
import "../../../../src/components/ha-button"; import "../../../../src/components/ha-button";
import "../../../../src/components/ha-tooltip";
import "../../../../src/components/ha-svg-icon";
import { createCloseHeading } from "../../../../src/components/ha-dialog"; import { createCloseHeading } from "../../../../src/components/ha-dialog";
import "../../../../src/components/ha-icon-button"; import "../../../../src/components/ha-icon-button";
import "../../../../src/components/ha-md-list";
import "../../../../src/components/ha-md-list-item";
import "../../../../src/components/ha-svg-icon";
import "../../../../src/components/ha-textfield";
import type { HaTextField } from "../../../../src/components/ha-textfield";
import "../../../../src/components/ha-tooltip";
import type { import type {
HassioAddonInfo, HassioAddonInfo,
HassioAddonRepository, HassioAddonRepository,
@ -28,6 +24,10 @@ import {
import { haStyle, haStyleDialog } from "../../../../src/resources/styles"; import { haStyle, haStyleDialog } from "../../../../src/resources/styles";
import type { HomeAssistant } from "../../../../src/types"; import type { HomeAssistant } from "../../../../src/types";
import type { HassioRepositoryDialogParams } from "./show-dialog-repositories"; import type { HassioRepositoryDialogParams } from "./show-dialog-repositories";
import type { HaTextField } from "../../../../src/components/ha-textfield";
import "../../../../src/components/ha-textfield";
import "../../../../src/components/ha-md-list";
import "../../../../src/components/ha-md-list-item";
@customElement("dialog-hassio-repositories") @customElement("dialog-hassio-repositories")
class HassioRepositoriesDialog extends LitElement { class HassioRepositoriesDialog extends LitElement {

View File

@ -143,12 +143,16 @@ class HassioHostInfo extends LitElement {
: ""} : ""}
</div> </div>
<div> <div>
${this.supervisor.host.disk_life_time !== null ${this.supervisor.host.disk_life_time !== "" &&
this.supervisor.host.disk_life_time >= 10
? html` <ha-settings-row> ? html` <ha-settings-row>
<span slot="heading"> <span slot="heading">
${this.supervisor.localize("system.host.lifetime_used")} ${this.supervisor.localize(
"system.host.emmc_lifetime_used"
)}
</span> </span>
<span slot="description"> <span slot="description">
${this.supervisor.host.disk_life_time - 10} % -
${this.supervisor.host.disk_life_time} % ${this.supervisor.host.disk_life_time} %
</span> </span>
</ha-settings-row>` </ha-settings-row>`

View File

@ -3,26 +3,26 @@ import { mdiArrowCollapseDown, mdiDownload } from "@mdi/js";
// eslint-disable-next-line import/extensions // eslint-disable-next-line import/extensions
import { IntersectionController } from "@lit-labs/observers/intersection-controller.js"; import { IntersectionController } from "@lit-labs/observers/intersection-controller.js";
import { LitElement, type PropertyValues, css, html, nothing } from "lit"; import { LitElement, type PropertyValues, css, html, nothing } from "lit";
import { customElement, property, query, state } from "lit/decorators";
import { classMap } from "lit/directives/class-map"; import { classMap } from "lit/directives/class-map";
import { fireEvent } from "../../../src/common/dom/fire_event"; import { customElement, property, query, state } from "lit/decorators";
import type { import type {
LandingPageKeys, LandingPageKeys,
LocalizeFunc, LocalizeFunc,
} from "../../../src/common/translations/localize"; } from "../../../src/common/translations/localize";
import { waitForSeconds } from "../../../src/common/util/wait";
import "../../../src/components/ha-alert";
import "../../../src/components/ha-ansi-to-html";
import type { HaAnsiToHtml } from "../../../src/components/ha-ansi-to-html";
import "../../../src/components/ha-button"; import "../../../src/components/ha-button";
import "../../../src/components/ha-icon-button"; import "../../../src/components/ha-icon-button";
import "../../../src/components/ha-svg-icon"; import "../../../src/components/ha-svg-icon";
import { fileDownload } from "../../../src/util/file_download"; import "../../../src/components/ha-ansi-to-html";
import "../../../src/components/ha-alert";
import type { HaAnsiToHtml } from "../../../src/components/ha-ansi-to-html";
import { import {
getObserverLogs, getObserverLogs,
downloadUrl as observerLogsDownloadUrl, downloadUrl as observerLogsDownloadUrl,
} from "../data/observer"; } from "../data/observer";
import { fireEvent } from "../../../src/common/dom/fire_event";
import { fileDownload } from "../../../src/util/file_download";
import { getSupervisorLogs, getSupervisorLogsFollow } from "../data/supervisor"; import { getSupervisorLogs, getSupervisorLogsFollow } from "../data/supervisor";
import { waitForSeconds } from "../../../src/common/util/wait";
import { ASSUME_CORE_START_SECONDS } from "../ha-landing-page"; import { ASSUME_CORE_START_SECONDS } from "../ha-landing-page";
const ERROR_CHECK = /^[\d\s-:]+(ERROR|CRITICAL)(.*)/gm; const ERROR_CHECK = /^[\d\s-:]+(ERROR|CRITICAL)(.*)/gm;
@ -108,8 +108,6 @@ class LandingPageLogs extends LitElement {
!this._scrolledToBottomController.value) || !this._scrolledToBottomController.value) ||
false, false,
})}" })}"
size="small"
appearance="filled"
@click=${this._scrollToBottom} @click=${this._scrollToBottom}
> >
<ha-svg-icon .path=${mdiArrowCollapseDown} slot="start"></ha-svg-icon> <ha-svg-icon .path=${mdiArrowCollapseDown} slot="start"></ha-svg-icon>
@ -311,14 +309,21 @@ class LandingPageLogs extends LitElement {
} }
.new-logs-indicator { .new-logs-indicator {
--mdc-theme-primary: var(--text-primary-color);
overflow: hidden; overflow: hidden;
position: absolute; position: absolute;
bottom: 4px; bottom: 0;
left: 4px; left: 0;
right: 0;
height: 0; height: 0;
background-color: var(--primary-color);
border-radius: 8px;
transition: height 0.4s ease-out; transition: height 0.4s ease-out;
display: flex; display: flex;
justify-content: space-between;
align-items: center;
} }
.new-logs-indicator.visible { .new-logs-indicator.visible {

View File

@ -26,7 +26,7 @@
"license": "Apache-2.0", "license": "Apache-2.0",
"type": "module", "type": "module",
"dependencies": { "dependencies": {
"@awesome.me/webawesome": "3.0.0-beta.4", "@awesome.me/webawesome": "3.0.0-beta.3",
"@babel/runtime": "7.28.2", "@babel/runtime": "7.28.2",
"@braintree/sanitize-url": "7.1.1", "@braintree/sanitize-url": "7.1.1",
"@codemirror/autocomplete": "6.18.6", "@codemirror/autocomplete": "6.18.6",
@ -88,7 +88,7 @@
"@shoelace-style/shoelace": "2.20.1", "@shoelace-style/shoelace": "2.20.1",
"@swc/helpers": "0.5.17", "@swc/helpers": "0.5.17",
"@thomasloven/round-slider": "0.6.0", "@thomasloven/round-slider": "0.6.0",
"@tsparticles/engine": "3.9.1", "@tsparticles/engine": "3.8.1",
"@tsparticles/preset-links": "3.2.0", "@tsparticles/preset-links": "3.2.0",
"@vaadin/combo-box": "24.7.9", "@vaadin/combo-box": "24.7.9",
"@vaadin/vaadin-themable-mixin": "24.7.9", "@vaadin/vaadin-themable-mixin": "24.7.9",
@ -100,7 +100,7 @@
"barcode-detector": "3.0.5", "barcode-detector": "3.0.5",
"color-name": "2.0.0", "color-name": "2.0.0",
"comlink": "4.4.2", "comlink": "4.4.2",
"core-js": "3.45.0", "core-js": "3.44.0",
"cropperjs": "1.6.2", "cropperjs": "1.6.2",
"culori": "4.0.2", "culori": "4.0.2",
"date-fns": "4.1.0", "date-fns": "4.1.0",
@ -108,12 +108,12 @@
"deep-clone-simple": "1.1.1", "deep-clone-simple": "1.1.1",
"deep-freeze": "0.0.1", "deep-freeze": "0.0.1",
"dialog-polyfill": "0.5.6", "dialog-polyfill": "0.5.6",
"echarts": "6.0.0", "echarts": "5.6.0",
"element-internals-polyfill": "3.0.2", "element-internals-polyfill": "3.0.2",
"fuse.js": "7.1.0", "fuse.js": "7.1.0",
"google-timezones-json": "1.2.0", "google-timezones-json": "1.2.0",
"gulp-zopfli-green": "6.0.2", "gulp-zopfli-green": "6.0.2",
"hls.js": "1.6.8", "hls.js": "1.6.7",
"home-assistant-js-websocket": "9.5.0", "home-assistant-js-websocket": "9.5.0",
"idb-keyval": "6.2.2", "idb-keyval": "6.2.2",
"intl-messageformat": "10.7.16", "intl-messageformat": "10.7.16",
@ -124,7 +124,7 @@
"lit": "3.3.1", "lit": "3.3.1",
"lit-html": "3.3.1", "lit-html": "3.3.1",
"luxon": "3.7.1", "luxon": "3.7.1",
"marked": "16.1.2", "marked": "16.1.1",
"memoize-one": "6.0.0", "memoize-one": "6.0.0",
"node-vibrant": "4.0.3", "node-vibrant": "4.0.3",
"object-hash": "3.0.0", "object-hash": "3.0.0",
@ -159,9 +159,9 @@
"@octokit/auth-oauth-device": "8.0.1", "@octokit/auth-oauth-device": "8.0.1",
"@octokit/plugin-retry": "8.0.1", "@octokit/plugin-retry": "8.0.1",
"@octokit/rest": "22.0.0", "@octokit/rest": "22.0.0",
"@rsdoctor/rspack-plugin": "1.1.11", "@rsdoctor/rspack-plugin": "1.1.10",
"@rspack/cli": "1.4.11", "@rspack/cli": "1.4.10",
"@rspack/core": "1.4.11", "@rspack/core": "1.4.10",
"@types/babel__plugin-transform-runtime": "7.9.5", "@types/babel__plugin-transform-runtime": "7.9.5",
"@types/chromecast-caf-receiver": "6.0.22", "@types/chromecast-caf-receiver": "6.0.22",
"@types/chromecast-caf-sender": "1.0.11", "@types/chromecast-caf-sender": "1.0.11",
@ -173,7 +173,7 @@
"@types/leaflet-draw": "1.0.12", "@types/leaflet-draw": "1.0.12",
"@types/leaflet.markercluster": "1.5.5", "@types/leaflet.markercluster": "1.5.5",
"@types/lodash.merge": "4.6.9", "@types/lodash.merge": "4.6.9",
"@types/luxon": "3.7.1", "@types/luxon": "3.6.2",
"@types/mocha": "10.0.10", "@types/mocha": "10.0.10",
"@types/qrcode": "1.5.5", "@types/qrcode": "1.5.5",
"@types/sortablejs": "1.15.8", "@types/sortablejs": "1.15.8",
@ -195,7 +195,7 @@
"eslint-plugin-unused-imports": "4.1.4", "eslint-plugin-unused-imports": "4.1.4",
"eslint-plugin-wc": "3.0.1", "eslint-plugin-wc": "3.0.1",
"fancy-log": "2.0.0", "fancy-log": "2.0.0",
"fs-extra": "11.3.1", "fs-extra": "11.3.0",
"glob": "11.0.3", "glob": "11.0.3",
"gulp": "5.0.1", "gulp": "5.0.1",
"gulp-brotli": "3.0.0", "gulp-brotli": "3.0.0",
@ -205,7 +205,7 @@
"husky": "9.1.7", "husky": "9.1.7",
"jsdom": "26.1.0", "jsdom": "26.1.0",
"jszip": "3.10.1", "jszip": "3.10.1",
"lint-staged": "16.1.4", "lint-staged": "16.1.2",
"lit-analyzer": "2.0.3", "lit-analyzer": "2.0.3",
"lodash.merge": "4.6.2", "lodash.merge": "4.6.2",
"lodash.template": "4.5.0", "lodash.template": "4.5.0",
@ -219,7 +219,7 @@
"terser-webpack-plugin": "5.3.14", "terser-webpack-plugin": "5.3.14",
"ts-lit-plugin": "2.0.2", "ts-lit-plugin": "2.0.2",
"typescript": "5.8.3", "typescript": "5.8.3",
"typescript-eslint": "8.39.0", "typescript-eslint": "8.38.0",
"vite-tsconfig-paths": "5.1.4", "vite-tsconfig-paths": "5.1.4",
"vitest": "3.2.4", "vitest": "3.2.4",
"webpack-stats-plugin": "1.1.3", "webpack-stats-plugin": "1.1.3",

View File

@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
[project] [project]
name = "home-assistant-frontend" name = "home-assistant-frontend"
version = "20250730.0" version = "20250731.0"
license = "Apache-2.0" license = "Apache-2.0"
license-files = ["LICENSE*"] license-files = ["LICENSE*"]
description = "The Home Assistant frontend" description = "The Home Assistant frontend"

View File

@ -132,13 +132,15 @@ export const shiftDateRange = (
end = calcDate(endDate, addDays, locale, config, difference); end = calcDate(endDate, addDays, locale, config, difference);
} else { } else {
const difference = const difference =
(calcDateDifferenceProperty( ((calcDateDifferenceProperty(
endDate, endDate,
startDate, startDate,
differenceInMilliseconds, differenceInMilliseconds,
locale, locale,
config config
) as number) * (forward ? 1 : -1); ) as number) +
1) *
(forward ? 1 : -1);
start = calcDate(startDate, addMilliseconds, locale, config, difference); start = calcDate(startDate, addMilliseconds, locale, config, difference);
end = calcDate(endDate, addMilliseconds, locale, config, difference); end = calcDate(endDate, addMilliseconds, locale, config, difference);
} }

View File

@ -22,8 +22,8 @@ export type LocalizeKeys =
| `ui.dialogs.more_info_control.lawn_mower.${string}` | `ui.dialogs.more_info_control.lawn_mower.${string}`
| `ui.dialogs.more_info_control.vacuum.${string}` | `ui.dialogs.more_info_control.vacuum.${string}`
| `ui.dialogs.quick-bar.commands.${string}` | `ui.dialogs.quick-bar.commands.${string}`
| `ui.dialogs.unhealthy.reasons.${string}` | `ui.dialogs.unhealthy.reason.${string}`
| `ui.dialogs.unsupported.reasons.${string}` | `ui.dialogs.unsupported.reason.${string}`
| `ui.panel.config.${string}.${"caption" | "description"}` | `ui.panel.config.${string}.${"caption" | "description"}`
| `ui.panel.config.dashboard.${string}` | `ui.panel.config.dashboard.${string}`
| `ui.panel.config.zha.${string}` | `ui.panel.config.zha.${string}`

View File

@ -117,7 +117,7 @@ export class HaProgressButton extends LitElement {
} }
ha-svg-icon { ha-svg-icon {
color: var(--white-color); color: var(--white);
} }
`; `;
} }

View File

@ -29,6 +29,7 @@ import { formatTimeLabel } from "./axis-label";
import { ensureArray } from "../../common/array/ensure-array"; import { ensureArray } from "../../common/array/ensure-array";
import "../chips/ha-assist-chip"; import "../chips/ha-assist-chip";
import { downSampleLineData } from "./down-sample"; import { downSampleLineData } from "./down-sample";
import { colorVariables } from "../../resources/theme/color/color.globals";
export const MIN_TIME_BETWEEN_UPDATES = 60 * 5 * 1000; export const MIN_TIME_BETWEEN_UPDATES = 60 * 5 * 1000;
const LEGEND_OVERFLOW_LIMIT = 10; const LEGEND_OVERFLOW_LIMIT = 10;
@ -167,16 +168,14 @@ export class HaChartBase extends LitElement {
} }
protected firstUpdated() { protected firstUpdated() {
if (this.isConnected) { this._setupChart();
this._setupChart();
}
} }
public willUpdate(changedProps: PropertyValues): void { public willUpdate(changedProps: PropertyValues): void {
if (!this.chart) { if (!this.chart) {
return; return;
} }
if (changedProps.has("_themes") && this.hasUpdated) { if (changedProps.has("_themes")) {
this._setupChart(); this._setupChart();
return; return;
} }
@ -343,8 +342,7 @@ export class HaChartBase extends LitElement {
echarts.use(this.extraComponents); echarts.use(this.extraComponents);
} }
const style = getComputedStyle(this); echarts.registerTheme("custom", this._createTheme());
echarts.registerTheme("custom", this._createTheme(style));
this.chart = echarts.init(container, "custom"); this.chart = echarts.init(container, "custom");
this.chart.on("datazoom", (e: any) => { this.chart.on("datazoom", (e: any) => {
@ -387,25 +385,24 @@ export class HaChartBase extends LitElement {
lastTipX = e.x; lastTipX = e.x;
lastTipY = e.y; lastTipY = e.y;
this.chart?.setOption({ this.chart?.setOption({
xAxis: ensureArray( xAxis: ensureArray(this.chart?.getOption().xAxis as any).map(
(this.chart?.getOption().xAxis as any) ?? [] (axis: XAXisOption) =>
).map((axis: XAXisOption) => axis.show
axis.show ? {
? { ...axis,
...axis, axisPointer: {
axisPointer: { ...axis.axisPointer,
...axis.axisPointer, status: "show",
status: "show", handle: {
handle: { color: colorVariables["primary-color"],
color: style.getPropertyValue("primary-color"), margin: 0,
margin: 0, size: 20,
size: 20, ...axis.axisPointer?.handle,
...axis.axisPointer?.handle, show: true,
show: true, },
}, },
}, }
} : axis
: axis
), ),
}); });
}); });
@ -418,22 +415,21 @@ export class HaChartBase extends LitElement {
return; return;
} }
this.chart?.setOption({ this.chart?.setOption({
xAxis: ensureArray( xAxis: ensureArray(this.chart?.getOption().xAxis as any).map(
(this.chart?.getOption().xAxis as any) ?? [] (axis: XAXisOption) =>
).map((axis: XAXisOption) => axis.show
axis.show ? {
? { ...axis,
...axis, axisPointer: {
axisPointer: { ...axis.axisPointer,
...axis.axisPointer, handle: {
handle: { ...axis.axisPointer?.handle,
...axis.axisPointer?.handle, show: false,
show: false, },
status: "hide",
}, },
status: "hide", }
}, : axis
}
: axis
), ),
}); });
this.chart?.dispatchAction({ this.chart?.dispatchAction({
@ -572,7 +568,8 @@ export class HaChartBase extends LitElement {
return options; return options;
} }
private _createTheme(style: CSSStyleDeclaration) { private _createTheme() {
const style = getComputedStyle(this);
return { return {
color: getAllGraphColors(style), color: getAllGraphColors(style),
backgroundColor: "transparent", backgroundColor: "transparent",
@ -600,13 +597,6 @@ export class HaChartBase extends LitElement {
textBorderWidth: 2, textBorderWidth: 2,
}, },
}, },
sankey: {
label: {
color: style.getPropertyValue("--primary-text-color"),
textBorderColor: style.getPropertyValue("--primary-background-color"),
textBorderWidth: 2,
},
},
categoryAxis: { categoryAxis: {
axisLine: { show: false }, axisLine: { show: false },
axisTick: { show: false }, axisTick: { show: false },
@ -812,7 +802,6 @@ export class HaChartBase extends LitElement {
}; };
} }
} }
const replaceMerge = options.series ? ["series"] : []; const replaceMerge = options.series ? ["series"] : [];
this.chart.setOption(options, { replaceMerge }); this.chart.setOption(options, { replaceMerge });
} }

View File

@ -105,14 +105,12 @@ export class HaNetworkGraph extends SubscribeMixin(LitElement) {
} }
protected render() { protected render() {
if (!GraphChart || !this.data.nodes?.length) { if (!GraphChart) {
return nothing; return nothing;
} }
const isMobile = window.matchMedia( const isMobile = window.matchMedia(
"all and (max-width: 450px), all and (max-height: 500px)" "all and (max-width: 450px), all and (max-height: 500px)"
).matches; ).matches;
return html`<ha-chart-base return html`<ha-chart-base
.hass=${this.hass} .hass=${this.hass}
.data=${this._getSeries( .data=${this._getSeries(
@ -245,7 +243,6 @@ export class HaNetworkGraph extends SubscribeMixin(LitElement) {
) { ) {
const containerWidth = this.clientWidth; const containerWidth = this.clientWidth;
const containerHeight = this.clientHeight; const containerHeight = this.clientHeight;
const positionedNodes: NetworkNode[] = nodes.map((node) => ({ ...node })); const positionedNodes: NetworkNode[] = nodes.map((node) => ({ ...node }));
positionedNodes.forEach((node) => { positionedNodes.forEach((node) => {
if (nodePositions[node.id]) { if (nodePositions[node.id]) {

View File

@ -186,22 +186,23 @@ export class HaSankeyChart extends LitElement {
"" ""
); );
const wordWidth = measureTextWidth(longestWord, FONT_SIZE); const wordWidth = measureTextWidth(longestWord, FONT_SIZE);
const availableWidth = params.rect.width + 6;
const fontSize = Math.min( const fontSize = Math.min(
FONT_SIZE, FONT_SIZE,
(availableWidth / wordWidth) * FONT_SIZE (params.rect.width / wordWidth) * FONT_SIZE
); );
return { return {
fontSize: fontSize > 1 ? fontSize : 0, fontSize: fontSize > 1 ? fontSize : 0,
width: availableWidth, width: params.rect.width,
align: "center", align: "center",
dy: -2, // shift up or the lowest row labels may be cut off
}; };
} }
const availableHeight = params.rect.height + 8; // account for the margin // estimate the number of lines after the label is wrapped
// this is a very rough estimate, but it works for now
const lineCount = Math.ceil(params.labelRect.width / labelSpace);
// `overflow: "break"` allows the label to overflow outside its height, so we need to account for that
const fontSize = Math.min( const fontSize = Math.min(
(availableHeight / params.labelRect.height) * FONT_SIZE, (params.rect.height / lineCount) * FONT_SIZE,
FONT_SIZE FONT_SIZE
); );
return { return {

View File

@ -27,7 +27,7 @@ export type Appearance = "accent" | "filled" | "outlined" | "plain";
* @csspart spinner - The spinner that shows when the button is in the loading state. * @csspart spinner - The spinner that shows when the button is in the loading state.
* *
* @cssprop --ha-button-height - The height of the button. * @cssprop --ha-button-height - The height of the button.
* @cssprop --ha-button-border-radius - The border radius of the button. defaults to `var(--ha-border-radius-pill)`. * @cssprop --ha-button-radius - The border radius of the button. defaults to `var(--wa-border-radius-pill)`.
* *
* @attr {("small"|"medium")} size - Sets the button size. * @attr {("small"|"medium")} size - Sets the button size.
* @attr {("brand"|"neutral"|"danger"|"warning"|"success")} variant - Sets the button color variant. "primary" is default. * @attr {("brand"|"neutral"|"danger"|"warning"|"success")} variant - Sets the button color variant. "primary" is default.
@ -55,9 +55,10 @@ export class HaButton extends Button {
/* set theme vars */ /* set theme vars */
--wa-form-control-padding-inline: 16px; --wa-form-control-padding-inline: 16px;
--wa-font-weight-action: var(--ha-font-weight-medium); --wa-font-weight-action: var(--ha-font-weight-medium);
--wa-border-radius-pill: 9999px;
--wa-form-control-border-radius: var( --wa-form-control-border-radius: var(
--ha-button-border-radius, --ha-button-radius,
var(--ha-border-radius-pill) var(--wa-border-radius-pill)
); );
--wa-form-control-height: var( --wa-form-control-height: var(
@ -78,102 +79,61 @@ export class HaButton extends Button {
} }
:host([variant="brand"]) { :host([variant="brand"]) {
--button-color-fill-normal-active: var( --color-fill-normal-active: var(--color-fill-primary-normal-active);
--ha-color-fill-primary-normal-active --color-fill-normal-hover: var(--color-fill-primary-normal-hover);
); --color-fill-loud-active: var(--color-fill-primary-loud-active);
--button-color-fill-normal-hover: var( --color-fill-loud-hover: var(--color-fill-primary-loud-hover);
--ha-color-fill-primary-normal-hover
);
--button-color-fill-loud-active: var(
--ha-color-fill-primary-loud-active
);
--button-color-fill-loud-hover: var(
--ha-color-fill-primary-loud-hover
);
} }
:host([variant="neutral"]) { :host([variant="neutral"]) {
--button-color-fill-normal-active: var( --color-fill-normal-active: var(--color-fill-neutral-normal-active);
--ha-color-fill-neutral-normal-active --color-fill-normal-hover: var(--color-fill-neutral-normal-hover);
); --color-fill-loud-active: var(--color-fill-neutral-loud-active);
--button-color-fill-normal-hover: var( --color-fill-loud-hover: var(--color-fill-neutral-loud-hover);
--ha-color-fill-neutral-normal-hover
);
--button-color-fill-loud-active: var(
--ha-color-fill-neutral-loud-active
);
--button-color-fill-loud-hover: var(
--ha-color-fill-neutral-loud-hover
);
} }
:host([variant="success"]) { :host([variant="success"]) {
--button-color-fill-normal-active: var( --color-fill-normal-active: var(--color-fill-success-normal-active);
--ha-color-fill-success-normal-active --color-fill-normal-hover: var(--color-fill-success-normal-hover);
); --color-fill-loud-active: var(--color-fill-success-loud-active);
--button-color-fill-normal-hover: var( --color-fill-loud-hover: var(--color-fill-success-loud-hover);
--ha-color-fill-success-normal-hover
);
--button-color-fill-loud-active: var(
--ha-color-fill-success-loud-active
);
--button-color-fill-loud-hover: var(
--ha-color-fill-success-loud-hover
);
} }
:host([variant="warning"]) { :host([variant="warning"]) {
--button-color-fill-normal-active: var( --color-fill-normal-active: var(--color-fill-warning-normal-active);
--ha-color-fill-warning-normal-active --color-fill-normal-hover: var(--color-fill-warning-normal-hover);
); --color-fill-loud-active: var(--color-fill-warning-loud-active);
--button-color-fill-normal-hover: var( --color-fill-loud-hover: var(--color-fill-warning-loud-hover);
--ha-color-fill-warning-normal-hover
);
--button-color-fill-loud-active: var(
--ha-color-fill-warning-loud-active
);
--button-color-fill-loud-hover: var(
--ha-color-fill-warning-loud-hover
);
} }
:host([variant="danger"]) { :host([variant="danger"]) {
--button-color-fill-normal-active: var( --color-fill-normal-active: var(--color-fill-danger-normal-active);
--ha-color-fill-danger-normal-active --color-fill-normal-hover: var(--color-fill-danger-normal-hover);
); --color-fill-loud-active: var(--color-fill-danger-loud-active);
--button-color-fill-normal-hover: var( --color-fill-loud-hover: var(--color-fill-danger-loud-hover);
--ha-color-fill-danger-normal-hover
);
--button-color-fill-loud-active: var(
--ha-color-fill-danger-loud-active
);
--button-color-fill-loud-hover: var(
--ha-color-fill-danger-loud-hover
);
} }
:host([appearance~="plain"]) .button { :host([appearance~="plain"]) .button {
color: var(--wa-color-on-normal); color: var(--wa-color-on-normal);
background-color: transparent;
} }
:host([appearance~="plain"]) .button.disabled { :host([appearance~="plain"]) .button.disabled {
background-color: transparent; background-color: var(--transparent-none);
color: var(--ha-color-on-disabled-quiet); color: var(--color-on-disabled-quiet);
} }
:host([appearance~="outlined"]) .button.disabled { :host([appearance~="outlined"]) .button.disabled {
background-color: transparent; background-color: var(--transparent-none);
color: var(--ha-color-on-disabled-quiet); color: var(--color-on-disabled-quiet);
} }
@media (hover: hover) { @media (hover: hover) {
:host([appearance~="filled"]) :host([appearance~="filled"])
.button:not(.disabled):not(.loading):hover { .button:not(.disabled):not(.loading):hover {
background-color: var(--button-color-fill-normal-hover); background-color: var(--color-fill-normal-hover);
} }
:host([appearance~="accent"]) :host([appearance~="accent"])
.button:not(.disabled):not(.loading):hover { .button:not(.disabled):not(.loading):hover {
background-color: var(--button-color-fill-loud-hover); background-color: var(--color-fill-loud-hover);
} }
:host([appearance~="plain"]) :host([appearance~="plain"])
.button:not(.disabled):not(.loading):hover { .button:not(.disabled):not(.loading):hover {
@ -182,11 +142,11 @@ export class HaButton extends Button {
} }
:host([appearance~="filled"]) :host([appearance~="filled"])
.button:not(.disabled):not(.loading):active { .button:not(.disabled):not(.loading):active {
background-color: var(--button-color-fill-normal-active); background-color: var(--color-fill-normal-active);
} }
:host([appearance~="filled"]) .button.disabled { :host([appearance~="filled"]) .button.disabled {
background-color: var(--ha-color-fill-disabled-normal-resting); background-color: var(--color-fill-disabled-normal-resting);
color: var(--ha-color-on-disabled-normal); color: var(--color-on-disabled-normal);
} }
:host([appearance~="accent"]) .button { :host([appearance~="accent"]) .button {
@ -197,11 +157,11 @@ export class HaButton extends Button {
} }
:host([appearance~="accent"]) :host([appearance~="accent"])
.button:not(.disabled):not(.loading):active { .button:not(.disabled):not(.loading):active {
background-color: var(--button-color-fill-loud-active); background-color: var(--color-fill-loud-active);
} }
:host([appearance~="accent"]) .button.disabled { :host([appearance~="accent"]) .button.disabled {
background-color: var(--ha-color-fill-disabled-loud-resting); background-color: var(--color-fill-disabled-loud-resting);
color: var(--ha-color-on-disabled-loud); color: var(--color-on-disabled-loud);
} }
:host([loading]) { :host([loading]) {
@ -211,13 +171,6 @@ export class HaButton extends Button {
.button.disabled { .button.disabled {
opacity: 1; opacity: 1;
} }
slot[name="start"]::slotted(*) {
margin-inline-end: 4px;
}
slot[name="end"]::slotted(*) {
margin-inline-start: 4px;
}
`, `,
]; ];
} }

View File

@ -506,7 +506,7 @@ export class HaControlSlider extends LitElement {
width: 100%; width: 100%;
} }
.slider .slider-track-bar { .slider .slider-track-bar {
--ha-border-radius: var(--control-slider-border-radius); --border-radius: var(--control-slider-border-radius);
--slider-size: 100%; --slider-size: 100%;
position: absolute; position: absolute;
height: 100%; height: 100%;

View File

@ -5,8 +5,8 @@ import { customElement, property, state } from "lit/decorators";
import { fireEvent } from "../common/dom/fire_event"; import { fireEvent } from "../common/dom/fire_event";
import { stopPropagation } from "../common/dom/stop_propagation"; import { stopPropagation } from "../common/dom/stop_propagation";
import { debounce } from "../common/util/debounce"; import { debounce } from "../common/util/debounce";
import type { ConfigEntry, SubEntry } from "../data/config_entries"; import type { ConfigEntry } from "../data/config_entries";
import { getConfigEntry, getSubEntries } from "../data/config_entries"; import { getConfigEntry } from "../data/config_entries";
import type { Agent } from "../data/conversation"; import type { Agent } from "../data/conversation";
import { listAgents } from "../data/conversation"; import { listAgents } from "../data/conversation";
import { fetchIntegrationManifest } from "../data/integration"; import { fetchIntegrationManifest } from "../data/integration";
@ -16,7 +16,6 @@ import "./ha-list-item";
import "./ha-select"; import "./ha-select";
import type { HaSelect } from "./ha-select"; import type { HaSelect } from "./ha-select";
import { getExtendedEntityRegistryEntry } from "../data/entity_registry"; import { getExtendedEntityRegistryEntry } from "../data/entity_registry";
import { showSubConfigFlowDialog } from "../dialogs/config-flow/show-dialog-sub-config-flow";
const NONE = "__NONE_OPTION__"; const NONE = "__NONE_OPTION__";
@ -38,8 +37,6 @@ export class HaConversationAgentPicker extends LitElement {
@state() private _configEntry?: ConfigEntry; @state() private _configEntry?: ConfigEntry;
@state() private _subConfigEntry?: SubEntry;
protected render() { protected render() {
if (!this._agents) { if (!this._agents) {
return nothing; return nothing;
@ -104,11 +101,7 @@ export class HaConversationAgentPicker extends LitElement {
${agent.name} ${agent.name}
</ha-list-item>` </ha-list-item>`
)}</ha-select )}</ha-select
>${(this._subConfigEntry && >${this._configEntry?.supports_options
this._configEntry?.supported_subentry_types[
this._subConfigEntry.subentry_type
]?.supports_reconfigure) ||
this._configEntry?.supports_options
? html`<ha-icon-button ? html`<ha-icon-button
.path=${mdiCog} .path=${mdiCog}
@click=${this._openOptionsFlow} @click=${this._openOptionsFlow}
@ -149,17 +142,8 @@ export class HaConversationAgentPicker extends LitElement {
this._configEntry = ( this._configEntry = (
await getConfigEntry(this.hass, regEntry.config_entry_id) await getConfigEntry(this.hass, regEntry.config_entry_id)
).config_entry; ).config_entry;
if (!regEntry.config_subentry_id) {
this._subConfigEntry = undefined;
} else {
this._subConfigEntry = (
await getSubEntries(this.hass, regEntry.config_entry_id)
).find((entry) => entry.subentry_id === regEntry.config_subentry_id);
}
} catch (_err) { } catch (_err) {
this._configEntry = undefined; this._configEntry = undefined;
this._subConfigEntry = undefined;
} }
} }
@ -198,25 +182,6 @@ export class HaConversationAgentPicker extends LitElement {
if (!this._configEntry) { if (!this._configEntry) {
return; return;
} }
if (
this._subConfigEntry &&
this._configEntry.supported_subentry_types[
this._subConfigEntry.subentry_type
]?.supports_reconfigure
) {
showSubConfigFlowDialog(
this,
this._configEntry,
this._subConfigEntry.subentry_type,
{
startFlowHandler: this._configEntry.entry_id,
subEntryId: this._subConfigEntry.subentry_id,
}
);
return;
}
showOptionsFlowDialog(this, this._configEntry, { showOptionsFlowDialog(this, this._configEntry, {
manifest: await fetchIntegrationManifest( manifest: await fetchIntegrationManifest(
this.hass, this.hass,

View File

@ -254,37 +254,21 @@ export class HaDateRangePicker extends LitElement {
} }
private _applyDateRange() { private _applyDateRange() {
let start = new Date(this._dateRangePicker.start);
let end = new Date(this._dateRangePicker.end);
if (this.timePicker) {
start.setSeconds(0);
start.setMilliseconds(0);
end.setSeconds(0);
end.setMilliseconds(0);
if (
end.getHours() === 0 &&
end.getMinutes() === 0 &&
start.getFullYear() === end.getFullYear() &&
start.getMonth() === end.getMonth() &&
start.getDate() === end.getDate()
) {
end.setDate(end.getDate() + 1);
}
}
if (this.hass.locale.time_zone === TimeZone.server) { if (this.hass.locale.time_zone === TimeZone.server) {
start = fromZonedTime(start, this.hass.config.time_zone); const dateRangePicker = this._dateRangePicker;
end = fromZonedTime(end, this.hass.config.time_zone);
const startDate = fromZonedTime(
dateRangePicker.start,
this.hass.config.time_zone
);
const endDate = fromZonedTime(
dateRangePicker.end,
this.hass.config.time_zone
);
dateRangePicker.clickRange([startDate, endDate]);
} }
if (
start.getTime() !== this._dateRangePicker.start.getTime() ||
end.getTime() !== this._dateRangePicker.end.getTime()
) {
this._dateRangePicker.clickRange([start, end]);
}
this._dateRangePicker.clickedApply(); this._dateRangePicker.clickedApply();
} }

View File

@ -20,18 +20,6 @@ export class HaFab extends FabBase {
--mdc-typography-button-font-family: var(--ha-font-family-body); --mdc-typography-button-font-family: var(--ha-font-family-body);
--mdc-typography-button-font-weight: var(--ha-font-weight-medium); --mdc-typography-button-font-weight: var(--ha-font-weight-medium);
} }
:host .mdc-fab--extended {
border-radius: var(
--ha-button-border-radius,
var(--ha-border-radius-pill)
);
}
:host .mdc-fab.mdc-fab--extended .ripple {
border-radius: var(
--ha-button-border-radius,
var(--ha-border-radius-pill)
);
}
:host .mdc-fab--extended .mdc-fab__icon { :host .mdc-fab--extended .mdc-fab__icon {
margin-inline-start: -8px; margin-inline-start: -8px;
margin-inline-end: 12px; margin-inline-end: 12px;

View File

@ -7,8 +7,8 @@ import { haStyle } from "../resources/styles";
import type { HomeAssistant } from "../types"; import type { HomeAssistant } from "../types";
import "./ha-button"; import "./ha-button";
import "./ha-icon-button"; import "./ha-icon-button";
import "./ha-input-helper-text";
import "./ha-textfield"; import "./ha-textfield";
import "./ha-input-helper-text";
import type { HaTextField } from "./ha-textfield"; import type { HaTextField } from "./ha-textfield";
@customElement("ha-multi-textfield") @customElement("ha-multi-textfield")
@ -79,7 +79,6 @@ class HaMultiTextField extends LitElement {
@click=${this._addItem} @click=${this._addItem}
.disabled=${this.disabled} .disabled=${this.disabled}
> >
<ha-svg-icon slot="start" .path=${mdiPlus}></ha-svg-icon>
${this.addLabel ?? ${this.addLabel ??
(this.label (this.label
? this.hass?.localize("ui.components.multi-textfield.add_item", { ? this.hass?.localize("ui.components.multi-textfield.add_item", {
@ -87,6 +86,7 @@ class HaMultiTextField extends LitElement {
}) })
: this.hass?.localize("ui.common.add")) ?? : this.hass?.localize("ui.common.add")) ??
"Add"} "Add"}
<ha-svg-icon slot="end" .path=${mdiPlus}></ha-svg-icon>
</ha-button> </ha-button>
</div> </div>
${this.helper ${this.helper

View File

@ -116,7 +116,7 @@ class DialogMediaManage extends LitElement {
` `
: html` : html`
<ha-button <ha-button
variant="danger" class="danger"
slot="navigationIcon" slot="navigationIcon"
.disabled=${this._deleting} .disabled=${this._deleting}
@click=${this._handleDelete} @click=${this._handleDelete}
@ -327,6 +327,10 @@ class DialogMediaManage extends LitElement {
display: block; display: block;
} }
.danger {
--mdc-theme-primary: var(--error-color);
}
ha-tip { ha-tip {
margin: 16px; margin: 16px;
} }

View File

@ -18,9 +18,9 @@ import { fireEvent } from "../../common/dom/fire_event";
import { debounce } from "../../common/util/debounce"; import { debounce } from "../../common/util/debounce";
import { isUnavailableState } from "../../data/entity"; import { isUnavailableState } from "../../data/entity";
import type { import type {
MediaPlayerItem,
MediaPickedEvent, MediaPickedEvent,
MediaPlayerBrowseAction, MediaPlayerBrowseAction,
MediaPlayerItem,
MediaPlayerLayoutType, MediaPlayerLayoutType,
} from "../../data/media-player"; } from "../../data/media-player";
import { import {
@ -32,7 +32,6 @@ import { browseLocalMediaPlayer } from "../../data/media_source";
import { isTTSMediaSource } from "../../data/tts"; import { isTTSMediaSource } from "../../data/tts";
import { showAlertDialog } from "../../dialogs/generic/show-dialog-box"; import { showAlertDialog } from "../../dialogs/generic/show-dialog-box";
import { haStyle } from "../../resources/styles"; import { haStyle } from "../../resources/styles";
import { loadVirtualizer } from "../../resources/virtualizer";
import type { HomeAssistant } from "../../types"; import type { HomeAssistant } from "../../types";
import { import {
brandsUrl, brandsUrl,
@ -45,15 +44,16 @@ import "../ha-alert";
import "../ha-button"; import "../ha-button";
import "../ha-button-menu"; import "../ha-button-menu";
import "../ha-card"; import "../ha-card";
import "../ha-spinner";
import "../ha-fab"; import "../ha-fab";
import "../ha-icon-button"; import "../ha-icon-button";
import "../ha-list";
import "../ha-list-item";
import "../ha-spinner";
import "../ha-svg-icon"; import "../ha-svg-icon";
import "../ha-tooltip"; import "../ha-tooltip";
import "../ha-list";
import "../ha-list-item";
import "./ha-browse-media-tts"; import "./ha-browse-media-tts";
import type { TtsMediaPickedEvent } from "./ha-browse-media-tts"; import type { TtsMediaPickedEvent } from "./ha-browse-media-tts";
import { loadVirtualizer } from "../../resources/virtualizer";
declare global { declare global {
interface HASSDomEvents { interface HASSDomEvents {

View File

@ -8,7 +8,7 @@ export interface HassioHostInfo {
chassis: string; chassis: string;
cpe: string; cpe: string;
deployment: string; deployment: string;
disk_life_time: number | null; disk_life_time: number | "";
disk_free: number; disk_free: number;
disk_total: number; disk_total: number;
disk_used: number; disk_used: number;

View File

@ -4,7 +4,7 @@ import type {
HassEntityBase, HassEntityBase,
HassEvent, HassEvent,
} from "home-assistant-js-websocket"; } from "home-assistant-js-websocket";
import { BINARY_STATE_ON, BINARY_STATE_OFF } from "../common/const"; import { BINARY_STATE_ON } from "../common/const";
import { computeDomain } from "../common/entity/compute_domain"; import { computeDomain } from "../common/entity/compute_domain";
import { computeStateDomain } from "../common/entity/compute_state_domain"; import { computeStateDomain } from "../common/entity/compute_state_domain";
import { supportsFeature } from "../common/entity/supports-feature"; import { supportsFeature } from "../common/entity/supports-feature";
@ -52,15 +52,6 @@ export const updateCanInstall = (
(showSkipped && Boolean(entity.attributes.skipped_version))) && (showSkipped && Boolean(entity.attributes.skipped_version))) &&
supportsFeature(entity, UpdateEntityFeature.INSTALL); supportsFeature(entity, UpdateEntityFeature.INSTALL);
export const latestVersionIsSkipped = (entity: UpdateEntity): boolean =>
!!(
entity.attributes.latest_version &&
entity.attributes.skipped_version === entity.attributes.latest_version
);
export const updateButtonIsDisabled = (entity: UpdateEntity): boolean =>
entity.state === BINARY_STATE_OFF && !latestVersionIsSkipped(entity);
export const updateIsInstalling = (entity: UpdateEntity): boolean => export const updateIsInstalling = (entity: UpdateEntity): boolean =>
!!entity.attributes.in_progress; !!entity.attributes.in_progress;

View File

@ -7,7 +7,6 @@ import { relativeTime } from "../../../common/datetime/relative_time";
import { supportsFeature } from "../../../common/entity/supports-feature"; import { supportsFeature } from "../../../common/entity/supports-feature";
import "../../../components/ha-alert"; import "../../../components/ha-alert";
import "../../../components/ha-button"; import "../../../components/ha-button";
import "../../../components/buttons/ha-progress-button";
import "../../../components/ha-checkbox"; import "../../../components/ha-checkbox";
import "../../../components/ha-faded"; import "../../../components/ha-faded";
import "../../../components/ha-markdown"; import "../../../components/ha-markdown";
@ -27,8 +26,6 @@ import {
UpdateEntityFeature, UpdateEntityFeature,
updateIsInstalling, updateIsInstalling,
updateReleaseNotes, updateReleaseNotes,
latestVersionIsSkipped,
updateButtonIsDisabled,
} from "../../../data/update"; } from "../../../data/update";
import type { HomeAssistant } from "../../../types"; import type { HomeAssistant } from "../../../types";
import { showAlertDialog } from "../../generic/show-dialog-box"; import { showAlertDialog } from "../../generic/show-dialog-box";
@ -183,6 +180,11 @@ class MoreInfoUpdate extends LitElement {
return nothing; return nothing;
} }
const skippedVersion =
this.stateObj.attributes.latest_version &&
this.stateObj.attributes.skipped_version ===
this.stateObj.attributes.latest_version;
const createBackupTexts = this._computeCreateBackupTexts(); const createBackupTexts = this._computeCreateBackupTexts();
return html` return html`
@ -310,7 +312,7 @@ class MoreInfoUpdate extends LitElement {
<ha-button <ha-button
appearance="plain" appearance="plain"
@click=${this._handleSkip} @click=${this._handleSkip}
.disabled=${latestVersionIsSkipped(this.stateObj) || .disabled=${skippedVersion ||
this.stateObj.state === BINARY_STATE_OFF || this.stateObj.state === BINARY_STATE_OFF ||
updateIsInstalling(this.stateObj)} updateIsInstalling(this.stateObj)}
> >
@ -323,8 +325,9 @@ class MoreInfoUpdate extends LitElement {
? html` ? html`
<ha-button <ha-button
@click=${this._handleInstall} @click=${this._handleInstall}
.loading=${updateIsInstalling(this.stateObj)} .disabled=${(this.stateObj.state === BINARY_STATE_OFF &&
.disabled=${updateButtonIsDisabled(this.stateObj)} !skippedVersion) ||
updateIsInstalling(this.stateObj)}
> >
${this.hass.localize( ${this.hass.localize(
"ui.dialogs.more_info_control.update.update" "ui.dialogs.more_info_control.update.update"

View File

@ -1,34 +0,0 @@
import type { LitElement } from "lit";
import { state } from "lit/decorators";
import type { Constructor } from "../types";
import { isMobileClient } from "../util/is_mobile";
import { listenMediaQuery } from "../common/dom/media_query";
export const MobileAwareMixin = <T extends Constructor<LitElement>>(
superClass: T
) => {
class MobileAwareClass extends superClass {
@state() protected _isMobileSize = false;
protected _isMobileClient = isMobileClient;
private _unsubMql?: () => void;
public connectedCallback() {
super.connectedCallback();
this._unsubMql = listenMediaQuery(
"all and (max-width: 450px), all and (max-height: 500px)",
(matches) => {
this._isMobileSize = matches;
}
);
}
public disconnectedCallback() {
super.disconnectedCallback();
this._unsubMql?.();
this._unsubMql = undefined;
}
}
return MobileAwareClass;
};

View File

@ -1,3 +1,4 @@
import { formatInTimeZone, toDate } from "date-fns-tz";
import { import {
addDays, addDays,
addHours, addHours,
@ -5,7 +6,6 @@ import {
differenceInMilliseconds, differenceInMilliseconds,
startOfHour, startOfHour,
} from "date-fns"; } from "date-fns";
import { formatInTimeZone, toDate } from "date-fns-tz";
import type { HassEntity } from "home-assistant-js-websocket"; import type { HassEntity } from "home-assistant-js-websocket";
import type { CSSResultGroup } from "lit"; import type { CSSResultGroup } from "lit";
import { LitElement, css, html, nothing } from "lit"; import { LitElement, css, html, nothing } from "lit";
@ -18,11 +18,11 @@ import { supportsFeature } from "../../common/entity/supports-feature";
import { isDate } from "../../common/string/is_date"; import { isDate } from "../../common/string/is_date";
import "../../components/entity/ha-entity-picker"; import "../../components/entity/ha-entity-picker";
import "../../components/ha-alert"; import "../../components/ha-alert";
import "../../components/ha-button";
import "../../components/ha-date-input"; import "../../components/ha-date-input";
import { createCloseHeading } from "../../components/ha-dialog"; import { createCloseHeading } from "../../components/ha-dialog";
import "../../components/ha-formfield"; import "../../components/ha-formfield";
import "../../components/ha-switch"; import "../../components/ha-switch";
import "../../components/ha-button";
import "../../components/ha-textarea"; import "../../components/ha-textarea";
import "../../components/ha-textfield"; import "../../components/ha-textfield";
import "../../components/ha-time-input"; import "../../components/ha-time-input";
@ -282,7 +282,6 @@ class DialogCalendarEventEditor extends LitElement {
? html` ? html`
<ha-button <ha-button
slot="secondaryAction" slot="secondaryAction"
appearance="plain"
variant="danger" variant="danger"
@click=${this._deleteEvent} @click=${this._deleteEvent}
.disabled=${this._submitting} .disabled=${this._submitting}

View File

@ -317,6 +317,9 @@ export default class HaAutomationAction extends LitElement {
display: block; display: block;
scroll-margin-top: 48px; scroll-margin-top: 48px;
} }
ha-svg-icon {
height: 20px;
}
.handle { .handle {
padding: 12px; padding: 12px;
cursor: move; /* fallback if grab cursor is unsupported */ cursor: move; /* fallback if grab cursor is unsupported */

View File

@ -15,8 +15,6 @@ export class HaParallelAction extends LitElement implements ActionElement {
@property({ type: Boolean }) public disabled = false; @property({ type: Boolean }) public disabled = false;
@property({ type: Boolean }) public narrow = false;
@property({ attribute: false }) public action!: ParallelAction; @property({ attribute: false }) public action!: ParallelAction;
public static get defaultConfig(): ParallelAction { public static get defaultConfig(): ParallelAction {
@ -31,7 +29,6 @@ export class HaParallelAction extends LitElement implements ActionElement {
return html` return html`
<ha-automation-action <ha-automation-action
.actions=${action.parallel} .actions=${action.parallel}
.narrow=${this.narrow}
.disabled=${this.disabled} .disabled=${this.disabled}
@value-changed=${this._actionsChanged} @value-changed=${this._actionsChanged}
.hass=${this.hass} .hass=${this.hass}

View File

@ -15,8 +15,6 @@ export class HaSequenceAction extends LitElement implements ActionElement {
@property({ type: Boolean }) public disabled = false; @property({ type: Boolean }) public disabled = false;
@property({ type: Boolean }) public narrow = false;
@property({ attribute: false }) public action!: SequenceAction; @property({ attribute: false }) public action!: SequenceAction;
public static get defaultConfig(): SequenceAction { public static get defaultConfig(): SequenceAction {
@ -31,7 +29,6 @@ export class HaSequenceAction extends LitElement implements ActionElement {
return html` return html`
<ha-automation-action <ha-automation-action
.actions=${action.sequence} .actions=${action.sequence}
.narrow=${this.narrow}
.disabled=${this.disabled} .disabled=${this.disabled}
@value-changed=${this._actionsChanged} @value-changed=${this._actionsChanged}
.hass=${this.hass} .hass=${this.hass}

View File

@ -260,14 +260,12 @@ class DialogAutomationSave extends LitElement implements HassDialog {
.path=${mdiClose} .path=${mdiClose}
></ha-icon-button> ></ha-icon-button>
<span slot="title">${this._params.title || title}</span> <span slot="title">${this._params.title || title}</span>
${this._params.hideInputs <ha-suggest-with-ai-button
? nothing slot="actionItems"
: html` <ha-suggest-with-ai-button .hass=${this.hass}
slot="actionItems" .generateTask=${this._generateTask}
.hass=${this.hass} @suggestion=${this._handleSuggestion}
.generateTask=${this._generateTask} ></ha-suggest-with-ai-button>
@suggestion=${this._handleSuggestion}
></ha-suggest-with-ai-button>`}
</ha-dialog-header> </ha-dialog-header>
${this._error ${this._error
? html`<ha-alert alert-type="error" ? html`<ha-alert alert-type="error"

View File

@ -345,6 +345,9 @@ export default class HaAutomationCondition extends LitElement {
.buttons { .buttons {
order: 1; order: 1;
} }
ha-svg-icon {
height: 20px;
}
.handle { .handle {
padding: 12px; padding: 12px;
cursor: move; /* fallback if grab cursor is unsupported */ cursor: move; /* fallback if grab cursor is unsupported */

View File

@ -487,7 +487,6 @@ export class HaAutomationEditor extends PreventUnsavedMixin(
.disabled=${Boolean(this._readOnly)} .disabled=${Boolean(this._readOnly)}
.dirty=${this._dirty} .dirty=${this._dirty}
@value-changed=${this._valueChanged} @value-changed=${this._valueChanged}
@editor-save=${this._handleSaveAutomation}
></manual-automation-editor> ></manual-automation-editor>
`} `}
</div> </div>
@ -518,7 +517,6 @@ export class HaAutomationEditor extends PreventUnsavedMixin(
.defaultValue=${this._preprocessYaml()} .defaultValue=${this._preprocessYaml()}
.readOnly=${this._readOnly} .readOnly=${this._readOnly}
@value-changed=${this._yamlChanged} @value-changed=${this._yamlChanged}
@editor-save=${this._handleSaveAutomation}
.showErrors=${false} .showErrors=${false}
disable-fullscreen disable-fullscreen
></ha-yaml-editor>` ></ha-yaml-editor>`

View File

@ -255,6 +255,9 @@ export default class HaAutomationOption extends LitElement {
display: block; display: block;
scroll-margin-top: 48px; scroll-margin-top: 48px;
} }
ha-svg-icon {
height: 20px;
}
.handle { .handle {
padding: 12px; padding: 12px;
cursor: move; /* fallback if grab cursor is unsupported */ cursor: move; /* fallback if grab cursor is unsupported */

View File

@ -296,6 +296,9 @@ export default class HaAutomationTrigger extends LitElement {
display: block; display: block;
scroll-margin-top: 48px; scroll-margin-top: 48px;
} }
ha-svg-icon {
height: 20px;
}
.handle { .handle {
padding: 12px; padding: 12px;
cursor: move; /* fallback if grab cursor is unsupported */ cursor: move; /* fallback if grab cursor is unsupported */

View File

@ -2,10 +2,10 @@ import type { CSSResultGroup } from "lit";
import { css, html, LitElement, nothing } from "lit"; import { css, html, LitElement, nothing } from "lit";
import { customElement, property, state } from "lit/decorators"; import { customElement, property, state } from "lit/decorators";
import { fireEvent } from "../../../../common/dom/fire_event"; import { fireEvent } from "../../../../common/dom/fire_event";
import "../../../../components/ha-alert";
import "../../../../components/ha-button"; import "../../../../components/ha-button";
import { createCloseHeading } from "../../../../components/ha-dialog"; import { createCloseHeading } from "../../../../components/ha-dialog";
import "../../../../components/ha-form/ha-form"; import "../../../../components/ha-form/ha-form";
import "../../../../components/ha-alert";
import type { import type {
HaFormSchema, HaFormSchema,
SchemaUnion, SchemaUnion,
@ -91,7 +91,6 @@ class LocalBackupLocationDialog extends LitElement {
</ha-alert> </ha-alert>
<ha-button <ha-button
slot="secondaryAction" slot="secondaryAction"
appearance="plain"
@click=${this.closeDialog} @click=${this.closeDialog}
dialogInitialFocus dialogInitialFocus
> >

View File

@ -2,20 +2,19 @@ import "@material/mwc-button";
import { mdiHelpCircle, mdiStarFourPoints } from "@mdi/js"; import { mdiHelpCircle, mdiStarFourPoints } from "@mdi/js";
import { css, html, LitElement } from "lit"; import { css, html, LitElement } from "lit";
import { customElement, property, state } from "lit/decorators"; import { customElement, property, state } from "lit/decorators";
import { isComponentLoaded } from "../../../common/config/is_component_loaded";
import type { HaProgressButton } from "../../../components/buttons/ha-progress-button";
import "../../../components/entity/ha-entity-picker";
import type { HaEntityPicker } from "../../../components/entity/ha-entity-picker";
import "../../../components/ha-card"; import "../../../components/ha-card";
import "../../../components/ha-settings-row"; import "../../../components/ha-settings-row";
import "../../../components/entity/ha-entity-picker";
import type { HaEntityPicker } from "../../../components/entity/ha-entity-picker";
import type { HomeAssistant } from "../../../types";
import { brandsUrl } from "../../../util/brands-url";
import { import {
fetchAITaskPreferences, fetchAITaskPreferences,
saveAITaskPreferences, saveAITaskPreferences,
type AITaskPreferences, type AITaskPreferences,
} from "../../../data/ai_task"; } from "../../../data/ai_task";
import type { HomeAssistant } from "../../../types";
import { brandsUrl } from "../../../util/brands-url";
import { documentationUrl } from "../../../util/documentation-url"; import { documentationUrl } from "../../../util/documentation-url";
import { isComponentLoaded } from "../../../common/config/is_component_loaded";
@customElement("ai-task-pref") @customElement("ai-task-pref")
export class AITaskPref extends LitElement { export class AITaskPref extends LitElement {
@ -25,8 +24,6 @@ export class AITaskPref extends LitElement {
@state() private _prefs?: AITaskPreferences; @state() private _prefs?: AITaskPreferences;
private _gen_data_entity_id?: string | null;
protected firstUpdated(changedProps) { protected firstUpdated(changedProps) {
super.firstUpdated(changedProps); super.firstUpdated(changedProps);
if (!this.hass || !isComponentLoaded(this.hass, "ai_task")) { if (!this.hass || !isComponentLoaded(this.hass, "ai_task")) {
@ -89,51 +86,30 @@ export class AITaskPref extends LitElement {
.hass=${this.hass} .hass=${this.hass}
.disabled=${this._prefs === undefined && .disabled=${this._prefs === undefined &&
isComponentLoaded(this.hass, "ai_task")} isComponentLoaded(this.hass, "ai_task")}
.value=${this._gen_data_entity_id || .value=${this._prefs?.gen_data_entity_id}
this._prefs?.gen_data_entity_id}
.includeDomains=${["ai_task"]} .includeDomains=${["ai_task"]}
@value-changed=${this._handlePrefChange} @value-changed=${this._handlePrefChange}
></ha-entity-picker> ></ha-entity-picker>
</ha-settings-row> </ha-settings-row>
</div> </div>
<div class="card-actions">
<ha-progress-button @click=${this._update}>
${this.hass!.localize("ui.common.save")}
</ha-progress-button>
</div>
</ha-card> </ha-card>
`; `;
} }
private _handlePrefChange(ev: CustomEvent<{ value: string | undefined }>) { private async _handlePrefChange(
ev: CustomEvent<{ value: string | undefined }>
) {
const input = ev.target as HaEntityPicker; const input = ev.target as HaEntityPicker;
const key = input.dataset.name as keyof AITaskPreferences; const key = input.getAttribute("data-name") as keyof AITaskPreferences;
const value = ev.detail.value || null; const entityId = ev.detail.value || null;
this[`_${key}`] = value;
}
private async _update(ev) {
const button = ev.target as HaProgressButton;
if (button.progress) {
return;
}
button.progress = true;
const oldPrefs = this._prefs; const oldPrefs = this._prefs;
const update: Partial<AITaskPreferences> = { this._prefs = { ...this._prefs!, [key]: entityId };
gen_data_entity_id: this._gen_data_entity_id,
};
this._prefs = { ...this._prefs!, ...update };
try { try {
this._prefs = await saveAITaskPreferences(this.hass, { this._prefs = await saveAITaskPreferences(this.hass, {
...update, [key]: entityId,
}); });
button.actionSuccess();
} catch (_err: any) { } catch (_err: any) {
button.actionError();
this._prefs = oldPrefs; this._prefs = oldPrefs;
} finally {
button.progress = false;
} }
} }
@ -169,9 +145,6 @@ export class AITaskPref extends LitElement {
direction: var(--direction); direction: var(--direction);
color: var(--secondary-text-color); color: var(--secondary-text-color);
} }
.card-actions {
text-align: right;
}
ha-entity-picker { ha-entity-picker {
flex: 1; flex: 1;
margin-left: 16px; margin-left: 16px;

View File

@ -1442,11 +1442,11 @@ export class HaConfigDevicePage extends LitElement {
} }
private async _signUrl(ev) { private async _signUrl(ev) {
const a = ev.currentTarget.getAttribute("href") const anchor = ev.currentTarget.closest("a");
? ev.currentTarget const signedUrl = await getSignedPath(
: ev.currentTarget.closest("a"); this.hass,
anchor.getAttribute("href")
const signedUrl = await getSignedPath(this.hass, a.getAttribute("href")); );
fileDownload(signedUrl.path); fileDownload(signedUrl.path);
} }

View File

@ -17,10 +17,6 @@ import { customElement, property, state } from "lit/decorators";
import { until } from "lit/directives/until"; import { until } from "lit/directives/until";
import memoizeOne from "memoize-one"; import memoizeOne from "memoize-one";
import { isComponentLoaded } from "../../../common/config/is_component_loaded"; import { isComponentLoaded } from "../../../common/config/is_component_loaded";
import {
PROTOCOL_INTEGRATIONS,
protocolIntegrationPicked,
} from "../../../common/integrations/protocolIntegrationPicked";
import { caseInsensitiveStringCompare } from "../../../common/string/compare"; import { caseInsensitiveStringCompare } from "../../../common/string/compare";
import { nextRender } from "../../../common/util/render-status"; import { nextRender } from "../../../common/util/render-status";
import "../../../components/ha-button"; import "../../../components/ha-button";
@ -68,6 +64,10 @@ import "./ha-config-entry-row";
import type { DataEntryFlowProgressExtended } from "./ha-config-integrations"; import type { DataEntryFlowProgressExtended } from "./ha-config-integrations";
import { showAddIntegrationDialog } from "./show-add-integration-dialog"; import { showAddIntegrationDialog } from "./show-add-integration-dialog";
import { showPickConfigEntryDialog } from "./show-pick-config-entry-dialog"; import { showPickConfigEntryDialog } from "./show-pick-config-entry-dialog";
import {
PROTOCOL_INTEGRATIONS,
protocolIntegrationPicked,
} from "../../../common/integrations/protocolIntegrationPicked";
export const renderConfigEntryError = ( export const renderConfigEntryError = (
hass: HomeAssistant, hass: HomeAssistant,

View File

@ -26,6 +26,7 @@ import {
} from "../../../../../data/bluetooth"; } from "../../../../../data/bluetooth";
import type { DeviceRegistryEntry } from "../../../../../data/device_registry"; import type { DeviceRegistryEntry } from "../../../../../data/device_registry";
import "../../../../../layouts/hass-subpage"; import "../../../../../layouts/hass-subpage";
import { colorVariables } from "../../../../../resources/theme/color/color.globals";
import type { HomeAssistant, Route } from "../../../../../types"; import type { HomeAssistant, Route } from "../../../../../types";
import { bluetoothAdvertisementMonitorTabs } from "./bluetooth-advertisement-monitor"; import { bluetoothAdvertisementMonitorTabs } from "./bluetooth-advertisement-monitor";
@ -130,34 +131,33 @@ export class BluetoothNetworkVisualization extends LitElement {
data: BluetoothDeviceData[], data: BluetoothDeviceData[],
scanners: BluetoothScannersDetails scanners: BluetoothScannersDetails
): NetworkData => { ): NetworkData => {
const style = getComputedStyle(this);
const categories = [ const categories = [
{ {
name: CORE_SOURCE_LABEL, name: CORE_SOURCE_LABEL,
symbol: "roundRect", symbol: "roundRect",
itemStyle: { itemStyle: {
color: style.getPropertyValue("--primary-color"), color: colorVariables["primary-color"],
}, },
}, },
{ {
name: this.hass.localize("ui.panel.config.bluetooth.scanners"), name: this.hass.localize("ui.panel.config.bluetooth.scanners"),
symbol: "circle", symbol: "circle",
itemStyle: { itemStyle: {
color: style.getPropertyValue("--cyan-color"), color: colorVariables["cyan-color"],
}, },
}, },
{ {
name: this.hass.localize("ui.panel.config.bluetooth.known_devices"), name: this.hass.localize("ui.panel.config.bluetooth.known_devices"),
symbol: "circle", symbol: "circle",
itemStyle: { itemStyle: {
color: style.getPropertyValue("--teal-color"), color: colorVariables["teal-color"],
}, },
}, },
{ {
name: this.hass.localize("ui.panel.config.bluetooth.unknown_devices"), name: this.hass.localize("ui.panel.config.bluetooth.unknown_devices"),
symbol: "circle", symbol: "circle",
itemStyle: { itemStyle: {
color: style.getPropertyValue("--disabled-color"), color: colorVariables["disabled-color"],
}, },
}, },
]; ];
@ -192,7 +192,7 @@ export class BluetoothNetworkVisualization extends LitElement {
symbol: "none", symbol: "none",
lineStyle: { lineStyle: {
width: 3, width: 3,
color: style.getPropertyValue("--primary-color"), color: colorVariables["primary-color"],
}, },
}); });
}); });
@ -206,7 +206,7 @@ export class BluetoothNetworkVisualization extends LitElement {
symbol: "none", symbol: "none",
lineStyle: { lineStyle: {
width: this._getLineWidth(node.rssi), width: this._getLineWidth(node.rssi),
color: style.getPropertyValue("--primary-color"), color: colorVariables["primary-color"],
}, },
}); });
return; return;
@ -227,8 +227,8 @@ export class BluetoothNetworkVisualization extends LitElement {
lineStyle: { lineStyle: {
width: this._getLineWidth(node.rssi), width: this._getLineWidth(node.rssi),
color: device color: device
? style.getPropertyValue("--primary-color") ? colorVariables["primary-color"]
: style.getPropertyValue("--disabled-color"), : colorVariables["disabled-color"],
}, },
}); });
}); });

View File

@ -14,9 +14,6 @@ import "../../../../../layouts/hass-subpage";
import { haStyle } from "../../../../../resources/styles"; import { haStyle } from "../../../../../resources/styles";
import type { HomeAssistant } from "../../../../../types"; import type { HomeAssistant } from "../../../../../types";
import "./mqtt-subscribe-card"; import "./mqtt-subscribe-card";
import type { Action } from "../../../../../data/script";
import { callExecuteScript } from "../../../../../data/service";
import { showToast } from "../../../../../util/toast";
const qosLevel = ["0", "1", "2"]; const qosLevel = ["0", "1", "2"];
@ -58,6 +55,14 @@ export class MQTTConfigPanel extends LitElement {
}) })
private _retain = false; private _retain = false;
@state()
@storage({
key: "panel-dev-mqtt-allow-template-ls",
state: true,
subscribe: false,
})
private _allowTemplate = false;
protected render(): TemplateResult { protected render(): TemplateResult {
return html` return html`
<hass-subpage .narrow=${this.narrow} .hass=${this.hass}> <hass-subpage .narrow=${this.narrow} .hass=${this.hass}>
@ -103,7 +108,25 @@ export class MQTTConfigPanel extends LitElement {
></ha-switch> ></ha-switch>
</ha-formfield> </ha-formfield>
</div> </div>
<p>${this.hass.localize("ui.panel.config.mqtt.payload")}</p> <p>
<ha-formfield
.label=${this.hass!.localize(
"ui.panel.config.mqtt.allow_template"
)}
>
<ha-switch
@change=${this._handleAllowTemplate}
.checked=${this._allowTemplate}
></ha-switch>
</ha-formfield>
</p>
<p>
${this._allowTemplate
? this.hass.localize("ui.panel.config.mqtt.payload")
: this.hass.localize(
"ui.panel.config.mqtt.payload_no_template"
)}
</p>
<ha-code-editor <ha-code-editor
mode="jinja2" mode="jinja2"
autocomplete-entities autocomplete-entities
@ -148,28 +171,21 @@ export class MQTTConfigPanel extends LitElement {
this._retain = (ev.target! as any).checked; this._retain = (ev.target! as any).checked;
} }
private _handleAllowTemplate(ev: CustomEvent) {
this._allowTemplate = (ev.target! as any).checked;
}
private _publish(): void { private _publish(): void {
if (!this.hass) { if (!this.hass) {
return; return;
} }
this.hass.callService("mqtt", "publish", {
const script: Action[] = [ topic: this._topic,
{ payload: !this._allowTemplate ? this._payload : undefined,
action: "mqtt.publish", payload_template: this._allowTemplate ? this._payload : undefined,
data: { qos: parseInt(this._qos),
topic: this._topic, retain: this._retain,
payload: this._payload, });
qos: parseInt(this._qos),
retain: this._retain,
},
},
];
callExecuteScript(this.hass, script).catch((err) =>
showToast(this, {
message: err.message,
})
);
} }
private async _openOptionFlow() { private async _openOptionFlow() {

View File

@ -105,6 +105,7 @@ class MqttSubscribeCard extends LitElement {
size="small" size="small"
.disabled=${this._topic === ""} .disabled=${this._topic === ""}
@click=${this._handleSubmit} @click=${this._handleSubmit}
type="submit"
> >
${this._subscribed ${this._subscribed
? this.hass.localize("ui.panel.config.mqtt.stop_listening") ? this.hass.localize("ui.panel.config.mqtt.stop_listening")

View File

@ -3,16 +3,16 @@ import { html, LitElement, nothing } from "lit";
import { customElement, property, state } from "lit/decorators"; import { customElement, property, state } from "lit/decorators";
import { fireEvent } from "../../../../../common/dom/fire_event"; import { fireEvent } from "../../../../../common/dom/fire_event";
import { stopPropagation } from "../../../../../common/dom/stop_propagation"; import { stopPropagation } from "../../../../../common/dom/stop_propagation";
import type { HassDialog } from "../../../../../dialogs/make-dialog-manager";
import { changeZHANetworkChannel } from "../../../../../data/zha";
import { showAlertDialog } from "../../../../../dialogs/generic/show-dialog-box";
import { createCloseHeading } from "../../../../../components/ha-dialog";
import type { HomeAssistant } from "../../../../../types";
import "../../../../../components/buttons/ha-progress-button"; import "../../../../../components/buttons/ha-progress-button";
import "../../../../../components/ha-alert"; import "../../../../../components/ha-alert";
import "../../../../../components/ha-button"; import "../../../../../components/ha-button";
import { createCloseHeading } from "../../../../../components/ha-dialog";
import "../../../../../components/ha-list-item";
import "../../../../../components/ha-select"; import "../../../../../components/ha-select";
import { changeZHANetworkChannel } from "../../../../../data/zha"; import "../../../../../components/ha-list-item";
import { showAlertDialog } from "../../../../../dialogs/generic/show-dialog-box";
import type { HassDialog } from "../../../../../dialogs/make-dialog-manager";
import type { HomeAssistant } from "../../../../../types";
import type { ZHAChangeChannelDialogParams } from "./show-dialog-zha-change-channel"; import type { ZHAChangeChannelDialogParams } from "./show-dialog-zha-change-channel";
const VALID_CHANNELS = [ const VALID_CHANNELS = [
@ -128,7 +128,6 @@ class DialogZHAChangeChannel extends LitElement implements HassDialog {
<ha-button <ha-button
slot="secondaryAction" slot="secondaryAction"
appearance="plain"
@click=${this.closeDialog} @click=${this.closeDialog}
.disabled=${this._migrationInProgress} .disabled=${this._migrationInProgress}
>${this.hass.localize("ui.common.cancel")}</ha-button >${this.hass.localize("ui.common.cancel")}</ha-button

View File

@ -16,6 +16,7 @@ import type {
import type { ZHADevice } from "../../../../../data/zha"; import type { ZHADevice } from "../../../../../data/zha";
import { fetchDevices, refreshTopology } from "../../../../../data/zha"; import { fetchDevices, refreshTopology } from "../../../../../data/zha";
import "../../../../../layouts/hass-tabs-subpage"; import "../../../../../layouts/hass-tabs-subpage";
import { colorVariables } from "../../../../../resources/theme/color/color.globals";
import type { HomeAssistant, Route } from "../../../../../types"; import type { HomeAssistant, Route } from "../../../../../types";
import { formatAsPaddedHex } from "./functions"; import { formatAsPaddedHex } from "./functions";
import { zhaTabs } from "./zha-config-dashboard"; import { zhaTabs } from "./zha-config-dashboard";
@ -155,12 +156,10 @@ export class ZHANetworkVisualizationPage extends LitElement {
} }
private _createChartData(devices: ZHADevice[]): NetworkData { private _createChartData(devices: ZHADevice[]): NetworkData {
const style = getComputedStyle(this); const primaryColor = colorVariables["primary-color"];
const routerColor = colorVariables["cyan-color"];
const primaryColor = style.getPropertyValue("--primary-color"); const endDeviceColor = colorVariables["teal-color"];
const routerColor = style.getPropertyValue("--cyan-color"); const offlineColor = colorVariables["error-color"];
const endDeviceColor = style.getPropertyValue("--teal-color");
const offlineColor = style.getPropertyValue("--error-color");
const nodes: NetworkNode[] = []; const nodes: NetworkNode[] = [];
const links: NetworkLink[] = []; const links: NetworkLink[] = [];
const categories = [ const categories = [
@ -283,7 +282,7 @@ export class ZHANetworkVisualizationPage extends LitElement {
color: color:
route.route_status === "Active" route.route_status === "Active"
? primaryColor ? primaryColor
: style.getPropertyValue("--disabled-color"), : colorVariables["disabled-color"],
type: ["Child", "Parent"].includes(neighbor.relationship) type: ["Child", "Parent"].includes(neighbor.relationship)
? "solid" ? "solid"
: "dotted", : "dotted",
@ -323,7 +322,7 @@ export class ZHANetworkVisualizationPage extends LitElement {
symbolSize: 5, symbolSize: 5,
lineStyle: { lineStyle: {
width: 1, width: 1,
color: style.getPropertyValue("--disabled-color"), color: colorVariables["disabled-color"],
type: "dotted", type: "dotted",
}, },
ignoreForceLayout: true, ignoreForceLayout: true,

View File

@ -157,388 +157,380 @@ class ZWaveJSConfigDashboard extends SubscribeMixin(LitElement) {
.path=${mdiRefresh} .path=${mdiRefresh}
.label=${this.hass!.localize("ui.common.refresh")} .label=${this.hass!.localize("ui.common.refresh")}
></ha-icon-button> ></ha-icon-button>
<div class="container"> ${this._network
${this._network ? html`
? html` <ha-card class="content network-status">
<ha-card class="content network-status"> <div class="card-content">
<div class="card-content"> <div class="heading">
<div class="heading"> <div class="icon">
<div class="icon"> ${this._status === "disconnected"
${this._status === "disconnected" ? html`<ha-spinner></ha-spinner>`
? html`<ha-spinner></ha-spinner>` : html`
: html` <ha-svg-icon
<ha-svg-icon .path=${this._icon}
.path=${this._icon} class="network-status-icon ${classMap({
class="network-status-icon ${classMap({ [this._status!]: true,
[this._status!]: true, })}"
})}" slot="item-icon"
slot="item-icon" ></ha-svg-icon>
></ha-svg-icon> `}
`}
</div>
${this._status !== "disconnected"
? html`
<div class="details">
Z-Wave
${this.hass.localize(
"ui.panel.config.zwave_js.common.network"
)}
${this.hass.localize(
`ui.panel.config.zwave_js.network_status.${this._status}`
)}<br />
<small>
${this.hass.localize(
`ui.panel.config.zwave_js.dashboard.devices`,
{
count:
this._network.controller.nodes.length +
provisioningDevices,
}
)}
${notReadyDevices > 0
? html`(${this.hass.localize(
`ui.panel.config.zwave_js.dashboard.not_ready`,
{ count: notReadyDevices }
)})`
: nothing}
</small>
</div>
`
: nothing}
</div> </div>
</div> ${this._status !== "disconnected"
<div class="card-actions">
<ha-button
appearance="plain"
href=${`/config/devices/dashboard?historyBack=1&config_entry=${this.configEntryId}`}
>
${this.hass.localize("ui.panel.config.devices.caption")}
</ha-button>
<ha-button
appearance="plain"
href=${`/config/entities/dashboard?historyBack=1&config_entry=${this.configEntryId}`}
>
${this.hass.localize("ui.panel.config.entities.caption")}
</ha-button>
${this._provisioningEntries?.length
? html`<ha-button
appearance="plain"
href=${`provisioned?config_entry=${this.configEntryId}`}
>
${this.hass.localize(
"ui.panel.config.zwave_js.dashboard.provisioned_devices"
)}
</ha-button>`
: nothing}
<ha-button
class="remove-node-button"
@click=${this._removeNodeClicked}
appearance="filled"
.disabled=${this._status !== "connected" ||
(this._network?.controller.inclusion_state !==
InclusionState.Idle &&
this._network?.controller.inclusion_state !==
InclusionState.SmartStart)}
>
${this.hass.localize(
"ui.panel.config.zwave_js.common.remove_a_node"
)}
</ha-button>
</div>
</ha-card>
<ha-card header="Diagnostics">
<div class="card-content">
<div class="row">
<span>
${this.hass.localize(
"ui.panel.config.zwave_js.dashboard.driver_version"
)}:
</span>
<span>${this._network.client.driver_version}</span>
</div>
<div class="row">
<span>
${this.hass.localize(
"ui.panel.config.zwave_js.dashboard.server_version"
)}:
</span>
<span>${this._network.client.server_version}</span>
</div>
<div class="row">
<span>
${this.hass.localize(
"ui.panel.config.zwave_js.dashboard.home_id"
)}:
</span>
<span>${this._network.controller.home_id}</span>
</div>
<div class="row">
<span>
${this.hass.localize(
"ui.panel.config.zwave_js.dashboard.server_url"
)}:
</span>
<span>${this._network.client.ws_server_url}</span>
</div>
<br />
<ha-expansion-panel
.header=${this.hass.localize(
"ui.panel.config.zwave_js.dashboard.statistics.title"
)}
>
<ha-list noninteractive>
<ha-list-item twoline hasmeta>
<span>
${this.hass.localize(
"ui.panel.config.zwave_js.dashboard.statistics.messages_tx.label"
)}
</span>
<span slot="secondary">
${this.hass.localize(
"ui.panel.config.zwave_js.dashboard.statistics.messages_tx.tooltip"
)}
</span>
<span slot="meta"
>${this._statistics?.messages_tx ?? 0}</span
>
</ha-list-item>
<ha-list-item twoline hasmeta>
<span>
${this.hass.localize(
"ui.panel.config.zwave_js.dashboard.statistics.messages_rx.label"
)}
</span>
<span slot="secondary">
${this.hass.localize(
"ui.panel.config.zwave_js.dashboard.statistics.messages_rx.tooltip"
)}
</span>
<span slot="meta"
>${this._statistics?.messages_rx ?? 0}</span
>
</ha-list-item>
<ha-list-item twoline hasmeta>
<span>
${this.hass.localize(
"ui.panel.config.zwave_js.dashboard.statistics.messages_dropped_tx.label"
)}
</span>
<span slot="secondary">
${this.hass.localize(
"ui.panel.config.zwave_js.dashboard.statistics.messages_dropped_tx.tooltip"
)}
</span>
<span slot="meta"
>${this._statistics?.messages_dropped_tx ?? 0}</span
>
</ha-list-item>
<ha-list-item twoline hasmeta>
<span>
${this.hass.localize(
"ui.panel.config.zwave_js.dashboard.statistics.messages_dropped_rx.label"
)}
</span>
<span slot="secondary">
${this.hass.localize(
"ui.panel.config.zwave_js.dashboard.statistics.messages_dropped_rx.tooltip"
)}
</span>
<span slot="meta"
>${this._statistics?.messages_dropped_rx ?? 0}</span
>
</ha-list-item>
<ha-list-item twoline hasmeta>
<span>
${this.hass.localize(
"ui.panel.config.zwave_js.dashboard.statistics.nak.label"
)}
</span>
<span slot="secondary">
${this.hass.localize(
"ui.panel.config.zwave_js.dashboard.statistics.nak.tooltip"
)}
</span>
<span slot="meta">${this._statistics?.nak ?? 0}</span>
</ha-list-item>
<ha-list-item twoline hasmeta>
<span>
${this.hass.localize(
"ui.panel.config.zwave_js.dashboard.statistics.can.label"
)}
</span>
<span slot="secondary">
${this.hass.localize(
"ui.panel.config.zwave_js.dashboard.statistics.can.tooltip"
)}
</span>
<span slot="meta">${this._statistics?.can ?? 0}</span>
</ha-list-item>
<ha-list-item twoline hasmeta>
<span>
${this.hass.localize(
"ui.panel.config.zwave_js.dashboard.statistics.timeout_ack.label"
)}
</span>
<span slot="secondary">
${this.hass.localize(
"ui.panel.config.zwave_js.dashboard.statistics.timeout_ack.tooltip"
)}
</span>
<span slot="meta"
>${this._statistics?.timeout_ack ?? 0}</span
>
</ha-list-item>
<ha-list-item twoline hasmeta>
<span>
${this.hass.localize(
"ui.panel.config.zwave_js.dashboard.statistics.timeout_response.label"
)}
</span>
<span slot="secondary">
${this.hass.localize(
"ui.panel.config.zwave_js.dashboard.statistics.timeout_response.tooltip"
)}
</span>
<span slot="meta"
>${this._statistics?.timeout_response ?? 0}</span
>
</ha-list-item>
<ha-list-item twoline hasmeta>
<span>
${this.hass.localize(
"ui.panel.config.zwave_js.dashboard.statistics.timeout_callback.label"
)}
</span>
<span slot="secondary">
${this.hass.localize(
"ui.panel.config.zwave_js.dashboard.statistics.timeout_callback.tooltip"
)}
</span>
<span slot="meta"
>${this._statistics?.timeout_callback ?? 0}</span
>
</ha-list-item>
</ha-list>
</ha-expansion-panel>
</div>
<div class="card-actions">
<ha-button
appearance="plain"
@click=${this._rebuildNetworkRoutesClicked}
.disabled=${this._status === "disconnected"}
>
${this.hass.localize(
"ui.panel.config.zwave_js.common.rebuild_network_routes"
)}
</ha-button>
</div>
</ha-card>
<ha-card>
<div class="card-header">
<h1>
${this.hass.localize(
"ui.panel.config.zwave_js.dashboard.data_collection.title"
)}
</h1>
${this._dataCollectionOptIn !== undefined
? html` ? html`
<ha-switch <div class="details">
.checked=${this._dataCollectionOptIn === true} Z-Wave
@change=${this._dataCollectionToggled} ${this.hass.localize(
></ha-switch> "ui.panel.config.zwave_js.common.network"
)}
${this.hass.localize(
`ui.panel.config.zwave_js.network_status.${this._status}`
)}<br />
<small>
${this.hass.localize(
`ui.panel.config.zwave_js.dashboard.devices`,
{
count:
this._network.controller.nodes.length +
provisioningDevices,
}
)}
${notReadyDevices > 0
? html`(${this.hass.localize(
`ui.panel.config.zwave_js.dashboard.not_ready`,
{ count: notReadyDevices }
)})`
: nothing}
</small>
</div>
` `
: html` <ha-spinner size="small"></ha-spinner> `} : nothing}
</div> </div>
<div class="card-content"> </div>
<p> <div class="card-actions">
<ha-button
appearance="plain"
href=${`/config/devices/dashboard?historyBack=1&config_entry=${this.configEntryId}`}
>
${this.hass.localize("ui.panel.config.devices.caption")}
</ha-button>
<ha-button
appearance="plain"
href=${`/config/entities/dashboard?historyBack=1&config_entry=${this.configEntryId}`}
>
${this.hass.localize("ui.panel.config.entities.caption")}
</ha-button>
${this._provisioningEntries?.length
? html`<ha-button
appearance="plain"
href=${`provisioned?config_entry=${this.configEntryId}`}
>
${this.hass.localize(
"ui.panel.config.zwave_js.dashboard.provisioned_devices"
)}
</ha-button>`
: nothing}
</div>
</ha-card>
<ha-card header="Diagnostics">
<div class="card-content">
<div class="row">
<span>
${this.hass.localize( ${this.hass.localize(
"ui.panel.config.zwave_js.dashboard.data_collection.description", "ui.panel.config.zwave_js.dashboard.driver_version"
{ )}:
documentation_link: html`<a </span>
target="_blank" <span>${this._network.client.driver_version}</span>
href="https://zwave-js.github.io/node-zwave-js/#/data-collection/data-collection"
>${this.hass.localize(
"ui.panel.config.zwave_js.dashboard.data_collection.documentation_link"
)}</a
>`,
}
)}
</p>
</div> </div>
</ha-card> <div class="row">
<ha-card <span>
.header=${this.hass.localize(
"ui.panel.config.zwave_js.dashboard.nvm_backup.title"
)}
>
<div class="card-content">
<p>
${this.hass.localize( ${this.hass.localize(
"ui.panel.config.zwave_js.dashboard.nvm_backup.description" "ui.panel.config.zwave_js.dashboard.server_version"
)} )}:
</p> </span>
<span>${this._network.client.server_version}</span>
</div> </div>
<div class="card-actions"> <div class="row">
${this._backupProgress !== undefined <span>
${this.hass.localize(
"ui.panel.config.zwave_js.dashboard.home_id"
)}:
</span>
<span>${this._network.controller.home_id}</span>
</div>
<div class="row">
<span>
${this.hass.localize(
"ui.panel.config.zwave_js.dashboard.server_url"
)}:
</span>
<span>${this._network.client.ws_server_url}</span>
</div>
<br />
<ha-expansion-panel
.header=${this.hass.localize(
"ui.panel.config.zwave_js.dashboard.statistics.title"
)}
>
<ha-list noninteractive>
<ha-list-item twoline hasmeta>
<span>
${this.hass.localize(
"ui.panel.config.zwave_js.dashboard.statistics.messages_tx.label"
)}
</span>
<span slot="secondary">
${this.hass.localize(
"ui.panel.config.zwave_js.dashboard.statistics.messages_tx.tooltip"
)}
</span>
<span slot="meta"
>${this._statistics?.messages_tx ?? 0}</span
>
</ha-list-item>
<ha-list-item twoline hasmeta>
<span>
${this.hass.localize(
"ui.panel.config.zwave_js.dashboard.statistics.messages_rx.label"
)}
</span>
<span slot="secondary">
${this.hass.localize(
"ui.panel.config.zwave_js.dashboard.statistics.messages_rx.tooltip"
)}
</span>
<span slot="meta"
>${this._statistics?.messages_rx ?? 0}</span
>
</ha-list-item>
<ha-list-item twoline hasmeta>
<span>
${this.hass.localize(
"ui.panel.config.zwave_js.dashboard.statistics.messages_dropped_tx.label"
)}
</span>
<span slot="secondary">
${this.hass.localize(
"ui.panel.config.zwave_js.dashboard.statistics.messages_dropped_tx.tooltip"
)}
</span>
<span slot="meta"
>${this._statistics?.messages_dropped_tx ?? 0}</span
>
</ha-list-item>
<ha-list-item twoline hasmeta>
<span>
${this.hass.localize(
"ui.panel.config.zwave_js.dashboard.statistics.messages_dropped_rx.label"
)}
</span>
<span slot="secondary">
${this.hass.localize(
"ui.panel.config.zwave_js.dashboard.statistics.messages_dropped_rx.tooltip"
)}
</span>
<span slot="meta"
>${this._statistics?.messages_dropped_rx ?? 0}</span
>
</ha-list-item>
<ha-list-item twoline hasmeta>
<span>
${this.hass.localize(
"ui.panel.config.zwave_js.dashboard.statistics.nak.label"
)}
</span>
<span slot="secondary">
${this.hass.localize(
"ui.panel.config.zwave_js.dashboard.statistics.nak.tooltip"
)}
</span>
<span slot="meta">${this._statistics?.nak ?? 0}</span>
</ha-list-item>
<ha-list-item twoline hasmeta>
<span>
${this.hass.localize(
"ui.panel.config.zwave_js.dashboard.statistics.can.label"
)}
</span>
<span slot="secondary">
${this.hass.localize(
"ui.panel.config.zwave_js.dashboard.statistics.can.tooltip"
)}
</span>
<span slot="meta">${this._statistics?.can ?? 0}</span>
</ha-list-item>
<ha-list-item twoline hasmeta>
<span>
${this.hass.localize(
"ui.panel.config.zwave_js.dashboard.statistics.timeout_ack.label"
)}
</span>
<span slot="secondary">
${this.hass.localize(
"ui.panel.config.zwave_js.dashboard.statistics.timeout_ack.tooltip"
)}
</span>
<span slot="meta"
>${this._statistics?.timeout_ack ?? 0}</span
>
</ha-list-item>
<ha-list-item twoline hasmeta>
<span>
${this.hass.localize(
"ui.panel.config.zwave_js.dashboard.statistics.timeout_response.label"
)}
</span>
<span slot="secondary">
${this.hass.localize(
"ui.panel.config.zwave_js.dashboard.statistics.timeout_response.tooltip"
)}
</span>
<span slot="meta"
>${this._statistics?.timeout_response ?? 0}</span
>
</ha-list-item>
<ha-list-item twoline hasmeta>
<span>
${this.hass.localize(
"ui.panel.config.zwave_js.dashboard.statistics.timeout_callback.label"
)}
</span>
<span slot="secondary">
${this.hass.localize(
"ui.panel.config.zwave_js.dashboard.statistics.timeout_callback.tooltip"
)}
</span>
<span slot="meta"
>${this._statistics?.timeout_callback ?? 0}</span
>
</ha-list-item>
</ha-list>
</ha-expansion-panel>
</div>
<div class="card-actions">
<ha-button
appearance="plain"
@click=${this._removeNodeClicked}
.disabled=${this._status !== "connected" ||
(this._network?.controller.inclusion_state !==
InclusionState.Idle &&
this._network?.controller.inclusion_state !==
InclusionState.SmartStart)}
>
${this.hass.localize(
"ui.panel.config.zwave_js.common.remove_a_node"
)}
</ha-button>
<ha-button
appearance="plain"
@click=${this._rebuildNetworkRoutesClicked}
.disabled=${this._status === "disconnected"}
>
${this.hass.localize(
"ui.panel.config.zwave_js.common.rebuild_network_routes"
)}
</ha-button>
</div>
</ha-card>
<ha-card>
<div class="card-header">
<h1>Third-party data reporting</h1>
${this._dataCollectionOptIn !== undefined
? html`
<ha-switch
.checked=${this._dataCollectionOptIn === true}
@change=${this._dataCollectionToggled}
></ha-switch>
`
: html` <ha-spinner size="small"></ha-spinner> `}
</div>
<div class="card-content">
<p>
Enable the reporting of anonymized telemetry and statistics
to the <em>Z-Wave JS organization</em>. This data will be
used to focus development efforts and improve the user
experience. Information about the data that is collected and
how it is used, including an example of the data collected,
can be found in the
<a
target="_blank"
href="https://zwave-js.github.io/node-zwave-js/#/data-collection/data-collection"
>Z-Wave JS data collection documentation</a
>.
</p>
</div>
</ha-card>
<ha-card
.header=${this.hass.localize(
"ui.panel.config.zwave_js.dashboard.nvm_backup.title"
)}
>
<div class="card-content">
<p>
${this.hass.localize(
"ui.panel.config.zwave_js.dashboard.nvm_backup.description"
)}
</p>
</div>
<div class="card-actions">
${this._backupProgress !== undefined
? html`<ha-progress-ring
size="small"
.value=${this._backupProgress}
></ha-progress-ring>
${this.hass.localize(
"ui.panel.config.zwave_js.dashboard.nvm_backup.creating"
)}
${this._backupProgress}%`
: this._restoreProgress !== undefined
? html`<ha-progress-ring ? html`<ha-progress-ring
size="small" size="small"
.value=${this._backupProgress} .value=${this._restoreProgress}
></ha-progress-ring> ></ha-progress-ring>
${this.hass.localize( ${this.hass.localize(
"ui.panel.config.zwave_js.dashboard.nvm_backup.creating" "ui.panel.config.zwave_js.dashboard.nvm_backup.restoring"
)} )}
${this._backupProgress}%` ${this._restoreProgress}%`
: this._restoreProgress !== undefined : html`<ha-button
? html`<ha-progress-ring appearance="plain"
size="small" @click=${this._downloadBackup}
.value=${this._restoreProgress} >
></ha-progress-ring>
${this.hass.localize( ${this.hass.localize(
"ui.panel.config.zwave_js.dashboard.nvm_backup.restoring" "ui.panel.config.zwave_js.dashboard.nvm_backup.download_backup"
)} )}
${this._restoreProgress}%` </ha-button>
: html`<ha-button <div class="upload-button">
<ha-button
appearance="plain" appearance="plain"
@click=${this._downloadBackup} @click=${this._restoreButtonClick}
variant="danger"
> >
${this.hass.localize( <span class="button-content">
"ui.panel.config.zwave_js.dashboard.nvm_backup.download_backup"
)}
</ha-button>
<div class="right-buttons">
<div class="upload-button">
<ha-button
appearance="filled"
@click=${this._restoreButtonClick}
>
<span class="button-content">
${this.hass.localize(
"ui.panel.config.zwave_js.dashboard.nvm_backup.restore_backup"
)}
</span>
</ha-button>
<input
type="file"
id="nvm-restore-file"
accept=".bin"
@change=${this._handleRestoreFileSelected}
style="display: none"
/>
</div>
<ha-button
appearance="filled"
@click=${this._openConfigFlow}
>
${this.hass.localize( ${this.hass.localize(
"ui.panel.config.zwave_js.dashboard.nvm_backup.migrate" "ui.panel.config.zwave_js.dashboard.nvm_backup.restore_backup"
)} )}
</ha-button> </span>
</div>`} </ha-button>
</div> <input
</ha-card> type="file"
` id="nvm-restore-file"
: nothing} accept=".bin"
</div> @change=${this._handleRestoreFileSelected}
style="display: none"
/>
</div>
<ha-button
variant="danger"
@click=${this._openConfigFlow}
class="migrate-button"
>
${this.hass.localize(
"ui.panel.config.zwave_js.dashboard.nvm_backup.migrate"
)}
</ha-button>`}
</div>
</ha-card>
`
: nothing}
<ha-fab <ha-fab
slot="fab" slot="fab"
.label=${this.hass.localize( .label=${this.hass.localize(
@ -965,7 +957,6 @@ class ZWaveJSConfigDashboard extends SubscribeMixin(LitElement) {
.card-actions { .card-actions {
display: flex; display: flex;
align-items: center; align-items: center;
flex-wrap: wrap;
} }
.card-actions ha-progress-ring { .card-actions ha-progress-ring {
@ -990,19 +981,9 @@ class ZWaveJSConfigDashboard extends SubscribeMixin(LitElement) {
pointer-events: none; pointer-events: none;
} }
.remove-node-button { .migrate-button {
margin-left: auto; margin-left: auto;
} }
.right-buttons {
display: flex;
gap: 8px;
margin-left: auto;
}
.container {
padding: 8px 16px 16px;
}
`, `,
]; ];
} }

View File

@ -162,7 +162,6 @@ class ZWaveJSLogs extends SubscribeMixin(LitElement) {
textarea { textarea {
flex-grow: 1; flex-grow: 1;
padding: 16px; padding: 16px;
font-family: var(--ha-font-family-code);
} }
ha-card { ha-card {
margin: 16px 0; margin: 16px 0;

View File

@ -25,6 +25,7 @@ import {
} from "../../../../../data/zwave_js"; } from "../../../../../data/zwave_js";
import "../../../../../layouts/hass-tabs-subpage"; import "../../../../../layouts/hass-tabs-subpage";
import { SubscribeMixin } from "../../../../../mixins/subscribe-mixin"; import { SubscribeMixin } from "../../../../../mixins/subscribe-mixin";
import { colorVariables } from "../../../../../resources/theme/color/color.globals";
import type { HomeAssistant, Route } from "../../../../../types"; import type { HomeAssistant, Route } from "../../../../../types";
import { configTabs } from "./zwave_js-config-router"; import { configTabs } from "./zwave_js-config-router";
@ -146,10 +147,8 @@ export class ZWaveJSNetworkVisualization extends SubscribeMixin(LitElement) {
nodeStatuses: Record<number, ZWaveJSNodeStatus>, nodeStatuses: Record<number, ZWaveJSNodeStatus>,
nodeStatistics: Record<number, ZWaveJSNodeStatisticsUpdatedMessage> nodeStatistics: Record<number, ZWaveJSNodeStatisticsUpdatedMessage>
): NetworkData => { ): NetworkData => {
const style = getComputedStyle(this);
const nodes: NetworkNode[] = []; const nodes: NetworkNode[] = [];
const links: NetworkLink[] = []; const links: NetworkLink[] = [];
const categories = [ const categories = [
{ {
name: this.hass.localize( name: this.hass.localize(
@ -157,7 +156,7 @@ export class ZWaveJSNetworkVisualization extends SubscribeMixin(LitElement) {
), ),
symbol: "roundRect", symbol: "roundRect",
itemStyle: { itemStyle: {
color: style.getPropertyValue("--primary-color"), color: colorVariables["primary-color"],
}, },
}, },
{ {
@ -166,7 +165,7 @@ export class ZWaveJSNetworkVisualization extends SubscribeMixin(LitElement) {
), ),
symbol: "circle", symbol: "circle",
itemStyle: { itemStyle: {
color: style.getPropertyValue("--cyan-color"), color: colorVariables["cyan-color"],
}, },
}, },
{ {
@ -175,7 +174,7 @@ export class ZWaveJSNetworkVisualization extends SubscribeMixin(LitElement) {
), ),
symbol: "circle", symbol: "circle",
itemStyle: { itemStyle: {
color: style.getPropertyValue("--disabled-color"), color: colorVariables["disabled-color"],
}, },
}, },
{ {
@ -184,7 +183,7 @@ export class ZWaveJSNetworkVisualization extends SubscribeMixin(LitElement) {
), ),
symbol: "circle", symbol: "circle",
itemStyle: { itemStyle: {
color: style.getPropertyValue("--error-color"), color: colorVariables["error-color"],
}, },
}, },
]; ];
@ -215,12 +214,12 @@ export class ZWaveJSNetworkVisualization extends SubscribeMixin(LitElement) {
itemStyle: { itemStyle: {
color: color:
node.status === NodeStatus.Dead node.status === NodeStatus.Dead
? style.getPropertyValue("--error-color") ? colorVariables["error-color"]
: node.status === NodeStatus.Asleep : node.status === NodeStatus.Asleep
? style.getPropertyValue("--disabled-color") ? colorVariables["disabled-color"]
: node.is_controller_node : node.is_controller_node
? style.getPropertyValue("--primary-color") ? colorVariables["primary-color"]
: style.getPropertyValue("--cyan-color"), : colorVariables["cyan-color"],
}, },
polarDistance: node.is_controller_node polarDistance: node.is_controller_node
? 0 ? 0
@ -270,8 +269,8 @@ export class ZWaveJSNetworkVisualization extends SubscribeMixin(LitElement) {
width, width,
color: color:
repeater === controllerNode repeater === controllerNode
? style.getPropertyValue("--primary-color") ? colorVariables["primary-color"]
: style.getPropertyValue("--disabled-color"), : colorVariables["disabled-color"],
type: route.protocol_data_rate > 1 ? "solid" : "dotted", type: route.protocol_data_rate > 1 ? "solid" : "dotted",
}, },
symbolSize: width * 3, symbolSize: width * 3,

View File

@ -825,7 +825,6 @@ class ErrorLogCard extends LitElement {
overflow: hidden; overflow: hidden;
position: absolute; position: absolute;
bottom: 4px; bottom: 4px;
left: 4px;
height: 0; height: 0;
transition: height 0.4s ease-out; transition: height 0.4s ease-out;
} }

View File

@ -250,21 +250,6 @@ export class HaConfigLogs extends LitElement {
.content { .content {
direction: ltr; direction: ltr;
} }
@media all and (max-width: 870px) {
ha-button-menu {
max-width: 50%;
}
ha-button {
max-width: 100%;
}
ha-button::part(label) {
overflow: hidden;
white-space: nowrap;
}
}
ha-list-item[selected] {
color: var(--primary-color);
}
`, `,
]; ];
} }

View File

@ -260,6 +260,9 @@ export class HassioNetwork extends LitElement {
: nothing} : nothing}
</div> </div>
<div class="card-actions"> <div class="card-actions">
<ha-button appearance="plain" @click=${this._clear}>
${this.hass.localize("ui.panel.config.network.supervisor.reset")}
</ha-button>
<ha-button <ha-button
.loading=${this._processing} .loading=${this._processing}
@click=${this._updateNetwork} @click=${this._updateNetwork}
@ -267,9 +270,6 @@ export class HassioNetwork extends LitElement {
> >
${this.hass.localize("ui.common.save")} ${this.hass.localize("ui.common.save")}
</ha-button> </ha-button>
<ha-button variant="danger" appearance="plain" @click=${this._clear}>
${this.hass.localize("ui.panel.config.network.supervisor.reset")}
</ha-button>
</div>`; </div>`;
} }

View File

@ -250,7 +250,7 @@ class DialogSystemInformation extends LitElement {
rel="noreferrer" rel="noreferrer"
> >
${this.hass.localize( ${this.hass.localize(
`ui.dialogs.unsupported.reasons.${reason}` `ui.dialogs.unsupported.reason.${reason}`
) || reason} ) || reason}
</a> </a>
</li> </li>
@ -279,7 +279,7 @@ class DialogSystemInformation extends LitElement {
rel="noreferrer" rel="noreferrer"
> >
${this.hass.localize( ${this.hass.localize(
`ui.dialogs.unhealthy.reasons.${reason}` `ui.dialogs.unhealthy.reason.${reason}`
) || reason} ) || reason}
</a> </a>
</li> </li>

View File

@ -320,7 +320,6 @@ export class HaSceneEditor extends PreventUnsavedMixin(
.hass=${this.hass} .hass=${this.hass}
.defaultValue=${this._config} .defaultValue=${this._config}
@value-changed=${this._yamlChanged} @value-changed=${this._yamlChanged}
@editor-save=${this._saveScene}
.showErrors=${false} .showErrors=${false}
disable-fullscreen disable-fullscreen
></ha-yaml-editor>`; ></ha-yaml-editor>`;

View File

@ -438,7 +438,6 @@ export class HaScriptEditor extends SubscribeMixin(
.disabled=${this._readOnly} .disabled=${this._readOnly}
.dirty=${this._dirty} .dirty=${this._dirty}
@value-changed=${this._valueChanged} @value-changed=${this._valueChanged}
@editor-save=${this._handleSave}
></manual-script-editor> ></manual-script-editor>
`} `}
</div> </div>
@ -451,7 +450,6 @@ export class HaScriptEditor extends SubscribeMixin(
.readOnly=${this._readOnly} .readOnly=${this._readOnly}
disable-fullscreen disable-fullscreen
@value-changed=${this._yamlChanged} @value-changed=${this._yamlChanged}
@editor-save=${this._handleSave}
.showErrors=${false} .showErrors=${false}
></ha-yaml-editor>` ></ha-yaml-editor>`
: nothing} : nothing}

View File

@ -30,8 +30,8 @@ import { bytesToString } from "../../../util/bytes-to-string";
import type { MoveDatadiskDialogParams } from "./show-dialog-move-datadisk"; import type { MoveDatadiskDialogParams } from "./show-dialog-move-datadisk";
const calculateMoveTime = memoizeOne((hostInfo: HassioHostInfo): number => { const calculateMoveTime = memoizeOne((hostInfo: HassioHostInfo): number => {
// Assume a speed of 30 MB/s. const speed = hostInfo.disk_life_time !== "" ? 30 : 10;
const moveTime = (hostInfo.disk_used * 1000) / 60 / 30; const moveTime = (hostInfo.disk_used * 1000) / 60 / speed;
const rebootTime = (hostInfo.startup_time * 4) / 60; const rebootTime = (hostInfo.startup_time * 4) / 60;
return Math.ceil((moveTime + rebootTime) / 10) * 10; return Math.ceil((moveTime + rebootTime) / 10) * 10;
}); });

View File

@ -117,17 +117,16 @@ class HaConfigSectionStorage extends LitElement {
} }
)} )}
</div> </div>
${this._hostInfo.disk_life_time !== null ${this._hostInfo.disk_life_time !== "" &&
this._hostInfo.disk_life_time >= 10
? // prettier-ignore ? // prettier-ignore
html` html`
<ha-metric <ha-metric
.heading=${this.hass.localize( .heading=${this.hass.localize(
"ui.panel.config.storage.lifetime_used" "ui.panel.config.storage.emmc_lifetime_used"
)} )}
.value=${this._hostInfo.disk_life_time} .value=${this._hostInfo.disk_life_time}
.tooltip=${this.hass.localize( .tooltip=${`${this._hostInfo.disk_life_time - 10}% - ${this._hostInfo.disk_life_time}%`}
"ui.panel.config.storage.lifetime_used_description"
)}
class="emmc" class="emmc"
></ha-metric> ></ha-metric>
` `

View File

@ -426,7 +426,13 @@ class HaPanelHistory extends LitElement {
private _dateRangeChanged(ev) { private _dateRangeChanged(ev) {
this._startDate = ev.detail.value.startDate; this._startDate = ev.detail.value.startDate;
this._endDate = ev.detail.value.endDate; const endDate = ev.detail.value.endDate;
if (endDate.getHours() === 0 && endDate.getMinutes() === 0) {
endDate.setDate(endDate.getDate() + 1);
endDate.setMilliseconds(endDate.getMilliseconds() - 1);
}
this._endDate = endDate;
this._updatePath(); this._updatePath();
} }

View File

@ -236,6 +236,10 @@ export class HaPanelLogbook extends LitElement {
private _dateRangeChanged(ev) { private _dateRangeChanged(ev) {
const startDate = ev.detail.value.startDate; const startDate = ev.detail.value.startDate;
const endDate = ev.detail.value.endDate; const endDate = ev.detail.value.endDate;
if (endDate.getHours() === 0 && endDate.getMinutes() === 0) {
endDate.setDate(endDate.getDate() + 1);
endDate.setMilliseconds(endDate.getMilliseconds() - 1);
}
this._time = { this._time = {
range: [startDate, endDate], range: [startDate, endDate],
}; };

View File

@ -21,7 +21,7 @@ export const supportsButtonCardFeature = (
: undefined; : undefined;
if (!stateObj) return false; if (!stateObj) return false;
const domain = computeDomain(stateObj.entity_id); const domain = computeDomain(stateObj.entity_id);
return ["button", "input_button", "script"].includes(domain); return ["button", "script"].includes(domain);
}; };
@customElement("hui-button-card-feature") @customElement("hui-button-card-feature")
@ -43,8 +43,7 @@ class HuiButtonCardFeature extends LitElement implements LovelaceCardFeature {
if (!this.hass || !this._stateObj) return; if (!this.hass || !this._stateObj) return;
const domain = computeDomain(this._stateObj.entity_id); const domain = computeDomain(this._stateObj.entity_id);
const service = const service = domain === "button" ? "press" : "turn_on";
domain === "button" || domain === "input_button" ? "press" : "turn_on";
this.hass.callService(domain, service, { this.hass.callService(domain, service, {
entity_id: this._stateObj.entity_id, entity_id: this._stateObj.entity_id,

View File

@ -23,7 +23,6 @@ import type { Link, Node } from "../../../../components/chart/ha-sankey-chart";
import { getGraphColorByIndex } from "../../../../common/color/colors"; import { getGraphColorByIndex } from "../../../../common/color/colors";
import { formatNumber } from "../../../../common/number/format_number"; import { formatNumber } from "../../../../common/number/format_number";
import { getEntityContext } from "../../../../common/entity/context/get_entity_context"; import { getEntityContext } from "../../../../common/entity/context/get_entity_context";
import { MobileAwareMixin } from "../../../../mixins/mobile-aware-mixin";
const DEFAULT_CONFIG: Partial<EnergySankeyCardConfig> = { const DEFAULT_CONFIG: Partial<EnergySankeyCardConfig> = {
group_by_floor: true, group_by_floor: true,
@ -32,7 +31,7 @@ const DEFAULT_CONFIG: Partial<EnergySankeyCardConfig> = {
@customElement("hui-energy-sankey-card") @customElement("hui-energy-sankey-card")
class HuiEnergySankeyCard class HuiEnergySankeyCard
extends SubscribeMixin(MobileAwareMixin(LitElement)) extends SubscribeMixin(LitElement)
implements LovelaceCard implements LovelaceCard
{ {
@property({ attribute: false }) public hass!: HomeAssistant; @property({ attribute: false }) public hass!: HomeAssistant;
@ -71,11 +70,7 @@ class HuiEnergySankeyCard
} }
protected shouldUpdate(changedProps: PropertyValues): boolean { protected shouldUpdate(changedProps: PropertyValues): boolean {
return ( return changedProps.has("_config") || changedProps.has("_data");
changedProps.has("_config") ||
changedProps.has("_data") ||
changedProps.has("_isMobileSize")
);
} }
protected render() { protected render() {
@ -378,17 +373,13 @@ class HuiEnergySankeyCard
const hasData = nodes.some((node) => node.value > 0); const hasData = nodes.some((node) => node.value > 0);
const vertical =
this._config.layout === "vertical" ||
(this._config.layout !== "horizontal" && this._isMobileSize);
return html` return html`
<ha-card .header=${this._config.title}> <ha-card .header=${this._config.title}>
<div class="card-content"> <div class="card-content">
${hasData ${hasData
? html`<ha-sankey-chart ? html`<ha-sankey-chart
.data=${{ nodes, links }} .data=${{ nodes, links }}
.vertical=${vertical} .vertical=${this._config.layout === "vertical"}
.valueFormatter=${this._valueFormatter} .valueFormatter=${this._valueFormatter}
></ha-sankey-chart>` ></ha-sankey-chart>`
: html`${this.hass.localize( : html`${this.hass.localize(

View File

@ -30,14 +30,7 @@ import type {
} from "./types"; } from "./types";
import type { PersonEntity } from "../../../data/person"; import type { PersonEntity } from "../../../data/person";
const STATES_OFF = new Set([ const STATES_OFF = new Set(["closed", "locked", "not_home", "off"]);
"closed",
"locked",
"not_home",
"off",
"unavailable",
"unknown",
]);
@customElement("hui-picture-glance-card") @customElement("hui-picture-glance-card")
class HuiPictureGlanceCard extends LitElement implements LovelaceCard { class HuiPictureGlanceCard extends LitElement implements LovelaceCard {

View File

@ -213,7 +213,7 @@ export interface EnergyCarbonGaugeCardConfig extends EnergyCardBaseConfig {
export interface EnergySankeyCardConfig extends EnergyCardBaseConfig { export interface EnergySankeyCardConfig extends EnergyCardBaseConfig {
type: "energy-sankey"; type: "energy-sankey";
title?: string; title?: string;
layout?: "vertical" | "horizontal" | "auto"; layout?: "vertical" | "horizontal";
group_by_floor?: boolean; group_by_floor?: boolean;
group_by_area?: boolean; group_by_area?: boolean;
} }

View File

@ -2,7 +2,6 @@ import {
mdiAccount, mdiAccount,
mdiAmpersand, mdiAmpersand,
mdiGateOr, mdiGateOr,
mdiNotEqualVariant,
mdiNumeric, mdiNumeric,
mdiResponsive, mdiResponsive,
mdiStateMachine, mdiStateMachine,
@ -15,6 +14,5 @@ export const ICON_CONDITION: Record<Condition["condition"], string> = {
screen: mdiResponsive, screen: mdiResponsive,
user: mdiAccount, user: mdiAccount,
and: mdiAmpersand, and: mdiAmpersand,
not: mdiNotEqualVariant,
or: mdiGateOr, or: mdiGateOr,
}; };

View File

@ -11,8 +11,7 @@ export type Condition =
| ScreenCondition | ScreenCondition
| UserCondition | UserCondition
| OrCondition | OrCondition
| AndCondition | AndCondition;
| NotCondition;
// Legacy conditional card condition // Legacy conditional card condition
export interface LegacyCondition { export interface LegacyCondition {
@ -59,11 +58,6 @@ export interface AndCondition extends BaseCondition {
conditions?: Condition[]; conditions?: Condition[];
} }
export interface NotCondition extends BaseCondition {
condition: "not";
conditions?: Condition[];
}
function getValueFromEntityId( function getValueFromEntityId(
hass: HomeAssistant, hass: HomeAssistant,
value: string value: string
@ -155,11 +149,6 @@ function checkAndCondition(condition: AndCondition, hass: HomeAssistant) {
return checkConditionsMet(condition.conditions, hass); return checkConditionsMet(condition.conditions, hass);
} }
function checkNotCondition(condition: NotCondition, hass: HomeAssistant) {
if (!condition.conditions) return true;
return !checkConditionsMet(condition.conditions, hass);
}
function checkOrCondition(condition: OrCondition, hass: HomeAssistant) { function checkOrCondition(condition: OrCondition, hass: HomeAssistant) {
if (!condition.conditions) return true; if (!condition.conditions) return true;
return condition.conditions.some((c) => checkConditionsMet([c], hass)); return condition.conditions.some((c) => checkConditionsMet([c], hass));
@ -186,8 +175,6 @@ export function checkConditionsMet(
return checkStateNumericCondition(c, hass); return checkStateNumericCondition(c, hass);
case "and": case "and":
return checkAndCondition(c, hass); return checkAndCondition(c, hass);
case "not":
return checkNotCondition(c, hass);
case "or": case "or":
return checkOrCondition(c, hass); return checkOrCondition(c, hass);
default: default:
@ -260,10 +247,6 @@ function validateAndCondition(condition: AndCondition) {
return condition.conditions != null; return condition.conditions != null;
} }
function validateNotCondition(condition: NotCondition) {
return condition.conditions != null;
}
function validateOrCondition(condition: OrCondition) { function validateOrCondition(condition: OrCondition) {
return condition.conditions != null; return condition.conditions != null;
} }
@ -293,8 +276,6 @@ export function validateConditionalConfig(
return validateNumericStateCondition(c); return validateNumericStateCondition(c);
case "and": case "and":
return validateAndCondition(c); return validateAndCondition(c);
case "not":
return validateNotCondition(c);
case "or": case "or":
return validateOrCondition(c); return validateOrCondition(c);
default: default:

View File

@ -208,7 +208,7 @@ export class HuiEnergyPeriodSelector extends SubscribeMixin(LitElement) {
? html`<ha-button ? html`<ha-button
appearance="filled" appearance="filled"
size="small" size="small"
@click=${this._pickNow} click=${this._pickNow}
> >
${this.hass.localize( ${this.hass.localize(
"ui.panel.lovelace.components.energy_period_selector.now" "ui.panel.lovelace.components.energy_period_selector.now"

View File

@ -18,7 +18,6 @@ import "./ha-card-condition-editor";
import type { HaCardConditionEditor } from "./ha-card-condition-editor"; import type { HaCardConditionEditor } from "./ha-card-condition-editor";
import type { LovelaceConditionEditorConstructor } from "./types"; import type { LovelaceConditionEditorConstructor } from "./types";
import "./types/ha-card-condition-and"; import "./types/ha-card-condition-and";
import "./types/ha-card-condition-not";
import "./types/ha-card-condition-numeric_state"; import "./types/ha-card-condition-numeric_state";
import "./types/ha-card-condition-or"; import "./types/ha-card-condition-or";
import "./types/ha-card-condition-screen"; import "./types/ha-card-condition-screen";
@ -31,7 +30,6 @@ const UI_CONDITION = [
"screen", "screen",
"user", "user",
"and", "and",
"not",
"or", "or",
] as const satisfies readonly Condition["condition"][]; ] as const satisfies readonly Condition["condition"][];

View File

@ -1,62 +0,0 @@
import { html, LitElement } from "lit";
import { customElement, property } from "lit/decorators";
import { any, array, assert, literal, object, optional } from "superstruct";
import { fireEvent } from "../../../../../common/dom/fire_event";
import "../../../../../components/ha-form/ha-form";
import type { HomeAssistant } from "../../../../../types";
import type {
NotCondition,
Condition,
StateCondition,
} from "../../../common/validate-condition";
import "../ha-card-conditions-editor";
const notConditionStruct = object({
condition: literal("not"),
conditions: optional(array(any())),
});
@customElement("ha-card-condition-not")
export class HaCardConditionNot extends LitElement {
@property({ attribute: false }) public hass!: HomeAssistant;
@property({ attribute: false }) public condition!: NotCondition;
@property({ type: Boolean }) public disabled = false;
public static get defaultConfig(): NotCondition {
return { condition: "not", conditions: [] };
}
protected static validateUIConfig(condition: StateCondition) {
return assert(condition, notConditionStruct);
}
protected render() {
return html`
<ha-card-conditions-editor
nested
.hass=${this.hass}
.conditions=${this.condition.conditions}
@value-changed=${this._valueChanged}
>
</ha-card-conditions-editor>
`;
}
private _valueChanged(ev: CustomEvent): void {
ev.stopPropagation();
const conditions = ev.detail.value as Condition[];
const condition = {
...this.condition,
conditions,
};
fireEvent(this, "value-changed", { value: condition });
}
}
declare global {
interface HTMLElementTagNameMap {
"ha-card-condition-not": HaCardConditionNot;
}
}

View File

@ -47,7 +47,7 @@ class HuiSceneEntityRow extends LitElement implements LovelaceRow {
return html` return html`
<hui-generic-entity-row .hass=${this.hass} .config=${this._config}> <hui-generic-entity-row .hass=${this.hass} .config=${this._config}>
<ha-button <ha-button
appearance="plain" appearance="filled"
size="small" size="small"
@click=${this._callService} @click=${this._callService}
.disabled=${stateObj.state === UNAVAILABLE} .disabled=${stateObj.state === UNAVAILABLE}

View File

@ -49,9 +49,8 @@ class HuiScriptEntityRow extends LitElement implements LovelaceRow {
<hui-generic-entity-row .hass=${this.hass} .config=${this._config}> <hui-generic-entity-row .hass=${this.hass} .config=${this._config}>
${stateObj.state === "on" ${stateObj.state === "on"
? html`<ha-button ? html`<ha-button
appearance="plain" appearance="filled"
size="small" size="small"
variant="danger"
@click=${this._cancelScript} @click=${this._cancelScript}
> >
${stateObj.attributes.mode !== "single" && ${stateObj.attributes.mode !== "single" &&
@ -62,10 +61,10 @@ class HuiScriptEntityRow extends LitElement implements LovelaceRow {
}) })
: this.hass.localize("ui.card.script.cancel")} : this.hass.localize("ui.card.script.cancel")}
</ha-button>` </ha-button>`
: nothing} : ""}
${stateObj.state === "off" || stateObj.attributes.max ${stateObj.state === "off" || stateObj.attributes.max
? html`<ha-button ? html`<ha-button
appearance="plain" appearance="filled"
size="small" size="small"
@click=${this._runScript} @click=${this._runScript}
.disabled=${isUnavailableState(stateObj.state) || .disabled=${isUnavailableState(stateObj.state) ||
@ -74,7 +73,7 @@ class HuiScriptEntityRow extends LitElement implements LovelaceRow {
${this._config.action_name || ${this._config.action_name ||
this.hass!.localize("ui.card.script.run")} this.hass!.localize("ui.card.script.run")}
</ha-button>` </ha-button>`
: nothing} : ""}
</hui-generic-entity-row> </hui-generic-entity-row>
`; `;
} }

View File

@ -101,6 +101,11 @@ export class HuiButtonRow extends LitElement implements LovelaceRow {
overflow: hidden; overflow: hidden;
text-overflow: ellipsis; text-overflow: ellipsis;
} }
ha-button {
margin-right: -0.57em;
margin-inline-end: -0.57em;
margin-inline-start: initial;
}
`; `;
private _handleAction(ev: ActionHandlerEvent) { private _handleAction(ev: ActionHandlerEvent) {

View File

@ -1,18 +1,21 @@
import { css } from "lit"; import { css } from "lit";
import { extractVar } from "../../../common/style/derived-css-vars"; import {
extractVar,
extractVars,
} from "../../../common/style/derived-css-vars";
import { coreColorVariables } from "./core.globals"; import { coreColorVariables } from "./core.globals";
export const colorStyles = css` export const colorStyles = css`
html { html {
/* text */ /* text */
--primary-text-color: var(--ha-color-text-primary); --primary-text-color: var(--color-text-primary);
--secondary-text-color: var(--ha-color-text-secondary); --secondary-text-color: var(--color-text-secondary);
--text-primary-color: #ffffff; --text-primary-color: #ffffff;
--text-light-primary-color: #212121; --text-light-primary-color: #212121;
--disabled-text-color: #bdbdbd; --disabled-text-color: #bdbdbd;
/* main interface colors */ /* main interface colors */
--primary-color: var(--ha-color-primary-40); --primary-color: var(--color-primary-40);
--dark-primary-color: #0288d1; --dark-primary-color: #0288d1;
--darker-primary-color: #016194; --darker-primary-color: #016194;
--light-primary-color: #b3e5fc; --light-primary-color: #b3e5fc;
@ -362,6 +365,7 @@ export const darkColorStyles = css`
--ha-button-neutral-light-color: #6a7081; --ha-button-neutral-light-color: #6a7081;
} }
`; `;
export const colorVariables = extractVars(colorStyles);
export const DefaultPrimaryColor = extractVar( export const DefaultPrimaryColor = extractVar(
colorStyles, colorStyles,

View File

@ -1,79 +1,76 @@
import { css } from "lit"; import { css } from "lit";
import { extractVars } from "../../../common/style/derived-css-vars"; import { extractVars } from "../../../common/style/derived-css-vars";
/*
* Core color tokens are the foundational color values used throughout the design system.
* These tokens represent raw, brand-independent colors such as grayscale shades, base hues, and accent tones.
* Core tokens shouldn't be tied to any specific UI purpose or role. Instead, they serve as building blocks from which semantic tokens are derived.
* Changes to core tokens will cascade into semantic tokens that reference them, enabling flexible theming and consistent design language.
* Please note that these core tokens are not intended to be used directly in components or styles.
*/
export const coreColorStyles = css` export const coreColorStyles = css`
html { html {
--white: #ffffff;
--black: #000000;
--transparent-none: rgba(255, 255, 255, 0);
/* primary */ /* primary */
--ha-color-primary-05: #001721; --color-primary-05: #001721;
--ha-color-primary-10: #002e3e; --color-primary-10: #002e3e;
--ha-color-primary-20: #004156; --color-primary-20: #004156;
--ha-color-primary-30: #006787; --color-primary-30: #006787;
--ha-color-primary-40: #009ac7; --color-primary-40: #009ac7;
--ha-color-primary-50: #18bcf2; --color-primary-50: #18bcf2;
--ha-color-primary-60: #37c8fd; --color-primary-60: #37c8fd;
--ha-color-primary-70: #7bd4fb; --color-primary-70: #7bd4fb;
--ha-color-primary-80: #b9e6fc; --color-primary-80: #b9e6fc;
--ha-color-primary-90: #dff3fc; --color-primary-90: #dff3fc;
--ha-color-primary-95: #eff9fe; --color-primary-95: #eff9fe;
/* neutral */ /* neutral */
--ha-color-neutral-05: #141414; --color-neutral-05: #101219;
--ha-color-neutral-10: #202020; --color-neutral-10: #1b1d26;
--ha-color-neutral-20: #363636; --color-neutral-20: #2f323f;
--ha-color-neutral-30: #4a4a4a; --color-neutral-30: #424554;
--ha-color-neutral-40: #5e5e5e; --color-neutral-40: #545868;
--ha-color-neutral-50: #7a7a7a; --color-neutral-50: #717584;
--ha-color-neutral-60: #989898; --color-neutral-60: #9194a2;
--ha-color-neutral-70: #b1b1b1; --color-neutral-70: #abaeb9;
--ha-color-neutral-80: #cccccc; --color-neutral-80: #c7c9d0;
--ha-color-neutral-90: #e6e6e6; --color-neutral-90: #e4e5e9;
--ha-color-neutral-95: #f3f3f3; --color-neutral-95: #f1f2f3;
/* orange */ /* orange */
--ha-color-orange-05: #280700; --color-orange-05: #280700;
--ha-color-orange-10: #3b0f00; --color-orange-10: #3b0f00;
--ha-color-orange-20: #5e1c00; --color-orange-20: #5e1c00;
--ha-color-orange-30: #7e2900; --color-orange-30: #7e2900;
--ha-color-orange-40: #9d3800; --color-orange-40: #9d3800;
--ha-color-orange-50: #c94e00; --color-orange-50: #c94e00;
--ha-color-orange-60: #f36d00; --color-orange-60: #f36d00;
--ha-color-orange-70: #ff9342; --color-orange-70: #ff9342;
--ha-color-orange-80: #ffbb89; --color-orange-80: #ffbb89;
--ha-color-orange-90: #ffe0c8; --color-orange-90: #ffe0c8;
--ha-color-orange-95: #fff0e4; --color-orange-95: #fff0e4;
/* red */ /* red */
--ha-color-red-05: #2a040b; --color-red-05: #2a040b;
--ha-color-red-10: #3e0913; --color-red-10: #3e0913;
--ha-color-red-20: #631323; --color-red-20: #631323;
--ha-color-red-30: #8a132c; --color-red-30: #8a132c;
--ha-color-red-40: #b30532; --color-red-40: #b30532;
--ha-color-red-50: #dc3146; --color-red-50: #dc3146;
--ha-color-red-60: #f3676c; --color-red-60: #f3676c;
--ha-color-red-70: #fd8f90; --color-red-70: #fd8f90;
--ha-color-red-80: #ffb8b6; --color-red-80: #ffb8b6;
--ha-color-red-90: #ffdedc; --color-red-90: #ffdedc;
--ha-color-red-95: #fff0ef; --color-red-95: #fff0ef;
/* green */ /* green */
--ha-color-green-05: #031608; --color-green-05: #031608;
--ha-color-green-10: #052310; --color-green-10: #052310;
--ha-color-green-20: #0a3a1d; --color-green-20: #0a3a1d;
--ha-color-green-30: #0a5027; --color-green-30: #0a5027;
--ha-color-green-40: #036730; --color-green-40: #036730;
--ha-color-green-50: #00883c; --color-green-50: #00883c;
--ha-color-green-60: #00ac49; --color-green-60: #00ac49;
--ha-color-green-70: #5dc36f; --color-green-70: #5dc36f;
--ha-color-green-80: #93da98; --color-green-80: #93da98;
--ha-color-green-90: #c2f2c1; --color-green-90: #c2f2c1;
--ha-color-green-95: #e3f9e3; --color-green-95: #e3f9e3;
} }
`; `;

View File

@ -1,284 +1,293 @@
import { css } from "lit"; import { css } from "lit";
/*
* Semantic color tokens are abstractions built on top of core color tokens to represent colors based on their usage or purpose.
* These tokens are named according to their semantic role in the UI (e.g., "primary," "success," "error"), making it easier to maintain consistency and scalability in design.
* Semantic tokens use core tokens to reference the actual color values. This separation allows for adjustments in color schemes without affecting the semantic meaning or intent.
*/
export const semanticColorStyles = css` export const semanticColorStyles = css`
html { html {
--ha-color-focus: var(--ha-color-orange-60); --color-overlay-modal: rgba(0, 0, 0, 0.25);
--color-focus: var(--color-orange-60);
/* surface */
--color-surface-lower: var(--color-neutral-90);
--color-surface-low: var(--color-neutral-95);
--color-surface-default: var(--white);
/* text */ /* text */
--ha-color-text-primary: var(--ha-color-neutral-05); --color-text-primary: var(--color-neutral-05);
--ha-color-text-secondary: var(--ha-color-neutral-40); --color-text-secondary: var(--color-neutral-40);
--ha-color-text-disabled: var(--ha-color-neutral-60); --color-text-disabled: var(--color-neutral-60);
--ha-color-text-link: var(--ha-color-primary-40); --color-text-link: var(--color-primary-40);
/* border primary */ /* border primary */
--ha-color-border-primary-quiet: var(--ha-color-primary-80); --color-border-quiet: var(--color-primary-80);
--ha-color-border-primary-normal: var(--ha-color-primary-70); --color-border-normal: var(--color-primary-70);
--ha-color-border-primary-loud: var(--ha-color-primary-40); --color-border-loud: var(--color-primary-40);
/* border neutral */ /* border neutral */
--ha-color-border-neutral-quiet: var(--ha-color-neutral-80); --color-border-neutral-quiet: var(--color-neutral-80);
--ha-color-border-neutral-normal: var(--ha-color-neutral-60); --color-border-neutral-normal: var(--color-neutral-60);
--ha-color-border-neutral-loud: var(--ha-color-neutral-40); --color-border-neutral-loud: var(--color-neutral-40);
/* border danger */ /* border danger */
--ha-color-border-danger-quiet: var(--ha-color-red-80); --color-border-danger-quiet: var(--color-red-80);
--ha-color-border-danger-normal: var(--ha-color-red-70); --color-border-danger-normal: var(--color-red-70);
--ha-color-border-danger-loud: var(--ha-color-red-40); --color-border-danger-loud: var(--color-red-40);
/* border warning */ /* border warning */
--ha-color-border-warning-quiet: var(--ha-color-orange-80); --color-border-warning-quiet: var(--color-orange-80);
--ha-color-border-warning-normal: var(--ha-color-orange-70); --color-border-warning-normal: var(--color-orange-70);
--ha-color-border-warning-loud: var(--ha-color-orange-40); --color-border-warning-loud: var(--color-orange-40);
/* border success */ /* border success */
--ha-color-border-success-quiet: var(--ha-color-green-80); --color-border-success-quiet: var(--color-green-80);
--ha-color-border-success-normal: var(--ha-color-green-70); --color-border-success-normal: var(--color-green-70);
--ha-color-border-success-loud: var(--ha-color-green-40); --color-border-success-loud: var(--color-green-40);
/* fill primary quiet */ /* fill primary quiet */
--ha-color-fill-primary-quiet-resting: var(--ha-color-primary-95); --color-fill-primary-quiet-resting: var(--color-primary-95);
--ha-color-fill-primary-quiet-hover: var(--ha-color-primary-90); --color-fill-primary-quiet-hover: var(--color-primary-90);
--ha-color-fill-primary-quiet-active: var(--ha-color-primary-95); --color-fill-primary-quiet-active: var(--color-primary-95);
/* fill primary normal */ /* fill primary normal */
--ha-color-fill-primary-normal-resting: var(--ha-color-primary-90); --color-fill-primary-normal-resting: var(--color-primary-90);
--ha-color-fill-primary-normal-hover: var(--ha-color-primary-80); --color-fill-primary-normal-hover: var(--color-primary-80);
--ha-color-fill-primary-normal-active: var(--ha-color-primary-90); --color-fill-primary-normal-active: var(--color-primary-90);
/* fill primary loud */ /* fill primary loud */
--ha-color-fill-primary-loud-resting: var(--ha-color-primary-40); --color-fill-primary-loud-resting: var(--color-primary-40);
--ha-color-fill-primary-loud-hover: var(--ha-color-primary-30); --color-fill-primary-loud-hover: var(--color-primary-30);
--ha-color-fill-primary-loud-active: var(--ha-color-primary-40); --color-fill-primary-loud-active: var(--color-primary-40);
/* fill neutral quiet */ /* fill neutral quiet */
--ha-color-fill-neutral-quiet-resting: var(--ha-color-neutral-95); --color-fill-neutral-quiet-resting: var(--color-neutral-95);
--ha-color-fill-neutral-quiet-hover: var(--ha-color-neutral-90); --color-fill-neutral-quiet-hover: var(--color-neutral-90);
--ha-color-fill-neutral-quiet-active: var(--ha-color-neutral-95); --color-fill-neutral-quiet-active: var(--color-neutral-95);
/* fill neutral normal */ /* fill neutral normal */
--ha-color-fill-neutral-normal-resting: var(--ha-color-neutral-90); --color-fill-neutral-normal-resting: var(--color-neutral-90);
--ha-color-fill-neutral-normal-hover: var(--ha-color-neutral-80); --color-fill-neutral-normal-hover: var(--color-neutral-80);
--ha-color-fill-neutral-normal-active: var(--ha-color-neutral-90); --color-fill-neutral-normal-active: var(--color-neutral-90);
/* fill neutral loud */ /* fill neutral loud */
--ha-color-fill-neutral-loud-resting: var(--ha-color-neutral-40); --color-fill-neutral-loud-resting: var(--color-neutral-40);
--ha-color-fill-neutral-loud-hover: var(--ha-color-neutral-30); --color-fill-neutral-loud-hover: var(--color-neutral-30);
--ha-color-fill-neutral-loud-active: var(--ha-color-neutral-40); --color-fill-neutral-loud-active: var(--color-neutral-40);
/* fill disabled quiet */ /* fill disabled quiet */
--ha-color-fill-disabled-quiet-resting: var(--ha-color-neutral-95); --color-fill-disabled-quiet-resting: var(--color-neutral-95);
/* fill disabled normal */ /* fill disabled normal */
--ha-color-fill-disabled-normal-resting: var(--ha-color-neutral-95); --color-fill-disabled-normal-resting: var(--color-neutral-95);
/* fill disabled loud */ /* fill disabled loud */
--ha-color-fill-disabled-loud-resting: var(--ha-color-neutral-80); --color-fill-disabled-loud-resting: var(--color-neutral-80);
/* fill danger quiet */ /* fill danger quiet */
--ha-color-fill-danger-quiet-resting: var(--ha-color-red-95); --color-fill-danger-quiet-resting: var(--color-red-95);
--ha-color-fill-danger-quiet-hover: var(--ha-color-red-90); --color-fill-danger-quiet-hover: var(--color-red-90);
--ha-color-fill-danger-quiet-active: var(--ha-color-red-95); --color-fill-danger-quiet-active: var(--color-red-95);
/* fill danger normal */ /* fill danger normal */
--ha-color-fill-danger-normal-resting: var(--ha-color-red-90); --color-fill-danger-normal-resting: var(--color-red-90);
--ha-color-fill-danger-normal-hover: var(--ha-color-red-80); --color-fill-danger-normal-hover: var(--color-red-80);
--ha-color-fill-danger-normal-active: var(--ha-color-red-90); --color-fill-danger-normal-active: var(--color-red-90);
/* fill danger loud */ /* fill danger loud */
--ha-color-fill-danger-loud-resting: var(--ha-color-red-50); --color-fill-danger-loud-resting: var(--color-red-50);
--ha-color-fill-danger-loud-hover: var(--ha-color-red-40); --color-fill-danger-loud-hover: var(--color-red-40);
--ha-color-fill-danger-loud-active: var(--ha-color-red-50); --color-fill-danger-loud-active: var(--color-red-50);
/* fill warning quiet */ /* fill warning quiet */
--ha-color-fill-warning-quiet-resting: var(--ha-color-orange-95); --color-fill-warning-quiet-resting: var(--color-orange-95);
--ha-color-fill-warning-quiet-hover: var(--ha-color-orange-90); --color-fill-warning-quiet-hover: var(--color-orange-90);
--ha-color-fill-warning-quiet-active: var(--ha-color-orange-95); --color-fill-warning-quiet-active: var(--color-orange-95);
/* fill warning normal */ /* fill warning normal */
--ha-color-fill-warning-normal-resting: var(--ha-color-orange-90); --color-fill-warning-normal-resting: var(--color-orange-90);
--ha-color-fill-warning-normal-hover: var(--ha-color-orange-80); --color-fill-warning-normal-hover: var(--color-orange-80);
--ha-color-fill-warning-normal-active: var(--ha-color-orange-90); --color-fill-warning-normal-active: var(--color-orange-90);
/* fill warning loud */ /* fill warning loud */
--ha-color-fill-warning-loud-resting: var(--ha-color-orange-70); --color-fill-warning-loud-resting: var(--color-orange-70);
--ha-color-fill-warning-loud-hover: var(--ha-color-orange-50); --color-fill-warning-loud-hover: var(--color-orange-50);
--ha-color-fill-warning-loud-active: var(--ha-color-orange-70); --color-fill-warning-loud-active: var(--color-orange-70);
/* fill success quiet */ /* fill success quiet */
--ha-color-fill-success-quiet-resting: var(--ha-color-green-95); --color-fill-success-quiet-resting: var(--color-green-95);
--ha-color-fill-success-quiet-hover: var(--ha-color-green-90); --color-fill-success-quiet-hover: var(--color-green-90);
--ha-color-fill-success-quiet-active: var(--ha-color-green-95); --color-fill-success-quiet-active: var(--color-green-95);
/* fill success normal */ /* fill success normal */
--ha-color-fill-success-normal-resting: var(--ha-color-green-90); --color-fill-success-normal-resting: var(--color-green-90);
--ha-color-fill-success-normal-hover: var(--ha-color-green-80); --color-fill-success-normal-hover: var(--color-green-80);
--ha-color-fill-success-normal-active: var(--ha-color-green-90); --color-fill-success-normal-active: var(--color-green-90);
/* fill success loud */ /* fill success loud */
--ha-color-fill-success-loud-resting: var(--ha-color-green-50); --color-fill-success-loud-resting: var(--color-green-50);
--ha-color-fill-success-loud-hover: var(--ha-color-green-40); --color-fill-success-loud-hover: var(--color-green-40);
--ha-color-fill-success-loud-active: var(--ha-color-green-50); --color-fill-success-loud-active: var(--color-green-50);
/* on primary */ /* on primary */
--ha-color-on-primary-quiet: var(--ha-color-primary-50); --color-on-primary-quiet: var(--color-primary-50);
--ha-color-on-primary-normal: var(--ha-color-primary-40); --color-on-primary-normal: var(--color-primary-40);
--ha-color-on-primary-loud: var(--white-color); --color-on-primary-loud: var(--white);
/* on neutral */ /* on neutral */
--ha-color-on-neutral-quiet: var(--ha-color-neutral-50); --color-on-neutral-quiet: var(--color-neutral-50);
--ha-color-on-neutral-normal: var(--ha-color-neutral-40); --color-on-neutral-normal: var(--color-neutral-40);
--ha-color-on-neutral-loud: var(--white-color); --color-on-neutral-loud: var(--white);
/* on disabled */ /* on disabled */
--ha-color-on-disabled-quiet: var(--ha-color-neutral-80); --color-on-disabled-quiet: var(--color-neutral-80);
--ha-color-on-disabled-normal: var(--ha-color-neutral-70); --color-on-disabled-normal: var(--color-neutral-70);
--ha-color-on-disabled-loud: var(--ha-color-neutral-95); --color-on-disabled-loud: var(--color-neutral-95);
/* on danger */ /* on danger */
--ha-color-on-danger-quiet: var(--ha-color-red-50); --color-on-danger-quiet: var(--color-red-50);
--ha-color-on-danger-normal: var(--ha-color-red-40); --color-on-danger-normal: var(--color-red-40);
--ha-color-on-danger-loud: var(--white-color); --color-on-danger-loud: var(--white);
/* on warning */ /* on warning */
--ha-color-on-warning-quiet: var(--ha-color-orange-50); --color-on-warning-quiet: var(--color-orange-50);
--ha-color-on-warning-normal: var(--ha-color-orange-40); --color-on-warning-normal: var(--color-orange-40);
--ha-color-on-warning-loud: var(--white-color); --color-on-warning-loud: var(--white);
/* on success */ /* on success */
--ha-color-on-success-quiet: var(--ha-color-green-50); --color-on-success-quiet: var(--color-green-50);
--ha-color-on-success-normal: var(--ha-color-green-40); --color-on-success-normal: var(--color-green-40);
--ha-color-on-success-loud: var(--white-color); --color-on-success-loud: var(--white);
/* logo */
--color-logo-primary: var(--color-primary-50);
} }
`; `;
export const darkSemanticColorStyles = css` export const darkSemanticColorStyles = css`
html { html {
/* surface */
--color-surface-lower: var(--black);
--color-surface-low: var(--color-neutral-05);
--color-surface-default: var(--color-neutral-10);
/* text */ /* text */
--ha-color-text-primary: var(--white-color); --color-text-primary: var(--white);
--ha-color-text-secondary: var(--ha-color-neutral-80); --color-text-secondary: var(--color-neutral-80);
--ha-color-text-link: var(--ha-color-primary-60); --color-text-link: var(--color-primary-60);
/* border primary */ /* border primary */
--ha-color-border-normal: var(--ha-color-primary-50); --color-border-normal: var(--color-primary-50);
/* border neutral */ /* border neutral */
--ha-color-border-neutral-quiet: var(--ha-color-neutral-40); --color-border-neutral-quiet: var(--color-neutral-40);
--ha-color-border-neutral-normal: var(--ha-color-neutral-50); --color-border-neutral-normal: var(--color-neutral-50);
--ha-color-border-neutral-loud: var(--ha-color-neutral-70); --color-border-neutral-loud: var(--color-neutral-70);
/* border danger */ /* border danger */
--ha-color-border-danger-normal: var(--ha-color-red-50); --color-border-danger-normal: var(--color-red-50);
--ha-color-border-danger-loud: var(--ha-color-red-50); --color-border-danger-loud: var(--color-red-50);
/* border warning */ /* border warning */
--ha-color-border-warning-normal: var(--ha-color-orange-50); --color-border-warning-normal: var(--color-orange-50);
--ha-color-border-warning-loud: var(--ha-color-orange-50); --color-border-warning-loud: var(--color-orange-50);
/* fill primary quiet */ /* fill primary quiet */
--ha-color-fill-primary-quiet-resting: var(--ha-color-primary-05); --color-fill-primary-quiet-resting: var(--color-primary-05);
--ha-color-fill-primary-quiet-hover: var(--ha-color-primary-10); --color-fill-primary-quiet-hover: var(--color-primary-10);
--ha-color-fill-primary-quiet-active: var(--ha-color-primary-05); --color-fill-primary-quiet-active: var(--color-primary-05);
/* fill primary normal */ /* fill primary normal */
--ha-color-fill-primary-normal-resting: var(--ha-color-primary-10); --color-fill-primary-normal-resting: var(--color-primary-10);
--ha-color-fill-primary-normal-hover: var(--ha-color-primary-20); --color-fill-primary-normal-hover: var(--color-primary-20);
--ha-color-fill-primary-normal-active: var(--ha-color-primary-10); --color-fill-primary-normal-active: var(--color-primary-10);
/* fill neutral quiet */ /* fill neutral quiet */
--ha-color-fill-neutral-quiet-resting: var(--ha-color-neutral-05); --color-fill-neutral-quiet-resting: var(--color-neutral-05);
--ha-color-fill-neutral-quiet-hover: var(--ha-color-neutral-10); --color-fill-neutral-quiet-hover: var(--color-neutral-10);
--ha-color-fill-neutral-quiet-active: var(--ha-color-neutral-00); --color-fill-neutral-quiet-active: var(--color-neutral-00);
/* fill neutral normal */ /* fill neutral normal */
--ha-color-fill-neutral-normal-resting: var(--ha-color-neutral-10); --color-fill-neutral-normal-resting: var(--color-neutral-10);
--ha-color-fill-neutral-normal-hover: var(--ha-color-neutral-20); --color-fill-neutral-normal-hover: var(--color-neutral-20);
--ha-color-fill-neutral-normal-active: var(--ha-color-neutral-10); --color-fill-neutral-normal-active: var(--color-neutral-10);
/* fill disabled quiet */ /* fill disabled quiet */
--ha-color-fill-disabled-quiet-resting: var(--ha-color-neutral-10); --color-fill-disabled-quiet-resting: var(--color-neutral-10);
/* fill disabled normal */ /* fill disabled normal */
--ha-color-fill-disabled-normal-resting: var(--ha-color-neutral-20); --color-fill-disabled-normal-resting: var(--color-neutral-20);
/* fill disabled loud */ /* fill disabled loud */
--ha-color-fill-disabled-loud-resting: var(--ha-color-neutral-30); --color-fill-disabled-loud-resting: var(--color-neutral-30);
/* fill danger quiet */ /* fill danger quiet */
--ha-color-fill-danger-quiet-resting: var(--ha-color-red-05); --color-fill-danger-quiet-resting: var(--color-red-05);
--ha-color-fill-danger-quiet-hover: var(--ha-color-red-10); --color-fill-danger-quiet-hover: var(--color-red-10);
--ha-color-fill-danger-quiet-active: var(--ha-color-red-05); --color-fill-danger-quiet-active: var(--color-red-05);
/* fill danger normal */ /* fill danger normal */
--ha-color-fill-danger-normal-resting: var(--ha-color-red-10); --color-fill-danger-normal-resting: var(--color-red-10);
--ha-color-fill-danger-normal-hover: var(--ha-color-red-20); --color-fill-danger-normal-hover: var(--color-red-20);
--ha-color-fill-danger-normal-active: var(--ha-color-red-10); --color-fill-danger-normal-active: var(--color-red-10);
/* fill danger loud */ /* fill danger loud */
--ha-color-fill-danger-loud-resting: var(--ha-color-red-40); --color-fill-danger-loud-resting: var(--color-red-40);
--ha-color-fill-danger-loud-hover: var(--ha-color-red-30); --color-fill-danger-loud-hover: var(--color-red-30);
--ha-color-fill-danger-loud-active: var(--ha-color-red-40); --color-fill-danger-loud-active: var(--color-red-40);
/* fill warning quiet */ /* fill warning quiet */
--ha-color-fill-warning-quiet-resting: var(--ha-color-orange-05); --color-fill-warning-quiet-resting: var(--color-orange-05);
--ha-color-fill-warning-quiet-hover: var(--ha-color-orange-10); --color-fill-warning-quiet-hover: var(--color-orange-10);
--ha-color-fill-warning-quiet-active: var(--ha-color-orange-05); --color-fill-warning-quiet-active: var(--color-orange-05);
/* fill warning normal */ /* fill warning normal */
--ha-color-fill-warning-normal-resting: var(--ha-color-orange-10); --color-fill-warning-normal-resting: var(--color-orange-10);
--ha-color-fill-warning-normal-hover: var(--ha-color-orange-20); --color-fill-warning-normal-hover: var(--color-orange-20);
--ha-color-fill-warning-normal-active: var(--ha-color-orange-10); --color-fill-warning-normal-active: var(--color-orange-10);
/* fill warning loud */ /* fill warning loud */
--ha-color-fill-warning-loud-resting: var(--ha-color-orange-40); --color-fill-warning-loud-resting: var(--color-orange-40);
--ha-color-fill-warning-loud-hover: var(--ha-color-orange-30); --color-fill-warning-loud-hover: var(--color-orange-30);
--ha-color-fill-warning-loud-active: var(--ha-color-orange-40); --color-fill-warning-loud-active: var(--color-orange-40);
/* fill success quiet */ /* fill success quiet */
--ha-color-fill-success-quiet-resting: var(--ha-color-green-05); --color-fill-success-quiet-resting: var(--color-green-05);
--ha-color-fill-success-quiet-hover: var(--ha-color-green-10); --color-fill-success-quiet-hover: var(--color-green-10);
--ha-color-fill-success-quiet-active: var(--ha-color-green-05); --color-fill-success-quiet-active: var(--color-green-05);
/* fill success normal */ /* fill success normal */
--ha-color-fill-success-normal-resting: var(--ha-color-green-10); --color-fill-success-normal-resting: var(--color-green-10);
--ha-color-fill-success-normal-hover: var(--ha-color-green-20); --color-fill-success-normal-hover: var(--color-green-20);
--ha-color-fill-success-normal-active: var(--ha-color-green-10); --color-fill-success-normal-active: var(--color-green-10);
/* fill success loud */ /* fill success loud */
--ha-color-fill-success-loud-resting: var(--ha-color-green-40); --color-fill-success-loud-resting: var(--color-green-40);
--ha-color-fill-success-loud-hover: var(--ha-color-green-30); --color-fill-success-loud-hover: var(--color-green-30);
--ha-color-fill-success-loud-active: var(--ha-color-green-40); --color-fill-success-loud-active: var(--color-green-40);
/* on primary */ /* on primary */
--ha-color-on-primary-quiet: var(--ha-color-primary-70); --color-on-primary-quiet: var(--color-primary-70);
--ha-color-on-primary-normal: var(--ha-color-primary-60); --color-on-primary-normal: var(--color-primary-60);
/* on neutral */ /* on neutral */
--ha-color-on-neutral-quiet: var(--ha-color-neutral-70); --color-on-neutral-quiet: var(--color-neutral-70);
--ha-color-on-neutral-normal: var(--ha-color-neutral-60); --color-on-neutral-normal: var(--color-neutral-60);
--ha-color-on-neutral-loud: var(--white-color); --color-on-neutral-loud: var(--white);
/* on disabled */ /* on disabled */
--ha-color-on-disabled-quiet: var(--ha-color-neutral-40); --color-on-disabled-quiet: var(--color-neutral-40);
--ha-color-on-disabled-normal: var(--ha-color-neutral-50); --color-on-disabled-normal: var(--color-neutral-50);
--ha-color-on-disabled-loud: var(--ha-color-neutral-50); --color-on-disabled-loud: var(--color-neutral-50);
/* on danger */ /* on danger */
--ha-color-on-danger-quiet: var(--ha-color-red-70); --color-on-danger-quiet: var(--color-red-70);
--ha-color-on-danger-normal: var(--ha-color-red-60); --color-on-danger-normal: var(--color-red-60);
--ha-color-on-danger-loud: var(--white-color); --color-on-danger-loud: var(--white);
/* on warning */ /* on warning */
--ha-color-on-warning-quiet: var(--ha-color-orange-70); --color-on-warning-quiet: var(--color-orange-70);
--ha-color-on-warning-normal: var(--ha-color-orange-60); --color-on-warning-normal: var(--color-orange-60);
--ha-color-on-warning-loud: var(--white-color); --color-on-warning-loud: var(--white);
/* on success */ /* on success */
--ha-color-on-success-quiet: var(--ha-color-green-70); --color-on-success-quiet: var(--color-green-70);
--ha-color-on-success-normal: var(--ha-color-green-60); --color-on-success-normal: var(--color-green-60);
--ha-color-on-success-loud: var(--white-color); --color-on-success-loud: var(--white);
} }
`; `;

View File

@ -2,56 +2,56 @@ import { css } from "lit";
export const waColorStyles = css` export const waColorStyles = css`
html { html {
--wa-color-brand-fill-loud: var(--ha-color-fill-primary-loud-resting); --wa-color-brand-fill-loud: var(--color-fill-primary-loud-resting);
--wa-color-brand-fill-normal: var(--ha-color-fill-primary-normal-resting); --wa-color-brand-fill-normal: var(--color-fill-primary-normal-resting);
--wa-color-brand-fill-quiet: var(--ha-color-fill-primary-quiet-resting); --wa-color-brand-fill-quiet: var(--color-fill-primary-quiet-resting);
--wa-color-brand-border-loud: var(--ha-color-border-loud); --wa-color-brand-border-loud: var(--color-border-loud);
--wa-color-brand-border-normal: var(--ha-color-primary-50); --wa-color-brand-border-normal: var(--color-primary-50);
--wa-color-brand-border-quiet: var(--ha-color-border-quiet); --wa-color-brand-border-quiet: var(--color-border-quiet);
--wa-color-brand-on-loud: var(--ha-color-on-primary-loud); --wa-color-brand-on-loud: var(--color-on-primary-loud);
--wa-color-brand-on-normal: var(--ha-color-on-primary-normal); --wa-color-brand-on-normal: var(--color-on-primary-normal);
--wa-color-brand-on-quiet: var(--ha-color-on-primary-quiet); --wa-color-brand-on-quiet: var(--color-on-primary-quiet);
--wa-color-neutral-fill-loud: var(--ha-color-fill-neutral-loud-resting); --wa-color-neutral-fill-loud: var(--color-fill-neutral-loud-resting);
--wa-color-neutral-fill-normal: var(--ha-color-fill-neutral-normal-resting); --wa-color-neutral-fill-normal: var(--color-fill-neutral-normal-resting);
--wa-color-neutral-fill-quiet: var(--ha-color-fill-neutral-quiet-resting); --wa-color-neutral-fill-quiet: var(--color-fill-neutral-quiet-resting);
--wa-color-neutral-border-loud: var(--ha-color-border-neutral-loud); --wa-color-neutral-border-loud: var(--color-border-neutral-loud);
--wa-color-neutral-border-normal: var(--ha-color-border-neutral-normal); --wa-color-neutral-border-normal: var(--color-border-neutral-normal);
--wa-color-neutral-border-quiet: var(--ha-color-border-neutral-quiet); --wa-color-neutral-border-quiet: var(--color-border-neutral-quiet);
--wa-color-neutral-on-loud: var(--ha-color-on-neutral-loud); --wa-color-neutral-on-loud: var(--color-on-neutral-loud);
--wa-color-neutral-on-normal: var(--ha-color-on-neutral-normal); --wa-color-neutral-on-normal: var(--color-on-neutral-normal);
--wa-color-neutral-on-quiet: var(--ha-color-on-neutral-quiet); --wa-color-neutral-on-quiet: var(--color-on-neutral-quiet);
--wa-color-success-fill-loud: var(--ha-color-fill-success-loud-resting); --wa-color-success-fill-loud: var(--color-fill-success-loud-resting);
--wa-color-success-fill-normal: var(--ha-color-fill-success-normal-resting); --wa-color-success-fill-normal: var(--color-fill-success-normal-resting);
--wa-color-success-fill-quiet: var(--ha-color-fill-success-quiet-resting); --wa-color-success-fill-quiet: var(--color-fill-success-quiet-resting);
--wa-color-success-border-loud: var(--ha-color-border-success-loud); --wa-color-success-border-loud: var(--color-border-success-loud);
--wa-color-success-border-normal: var(--ha-color-border-success-normal); --wa-color-success-border-normal: var(--color-border-success-normal);
--wa-color-success-border-quiet: var(--ha-color-border-success-quiet); --wa-color-success-border-quiet: var(--color-border-success-quiet);
--wa-color-success-on-loud: var(--ha-color-on-success-loud); --wa-color-success-on-loud: var(--color-on-success-loud);
--wa-color-success-on-normal: var(--ha-color-on-success-normal); --wa-color-success-on-normal: var(--color-on-success-normal);
--wa-color-success-on-quiet: var(--ha-color-on-success-quiet); --wa-color-success-on-quiet: var(--color-on-success-quiet);
--wa-color-warning-fill-loud: var(--ha-color-fill-warning-loud-resting); --wa-color-warning-fill-loud: var(--color-fill-warning-loud-resting);
--wa-color-warning-fill-normal: var(--ha-color-fill-warning-normal-resting); --wa-color-warning-fill-normal: var(--color-fill-warning-normal-resting);
--wa-color-warning-fill-quiet: var(--ha-color-fill-warning-quiet-resting); --wa-color-warning-fill-quiet: var(--color-fill-warning-quiet-resting);
--wa-color-warning-border-loud: var(--ha-color-border-warning-loud); --wa-color-warning-border-loud: var(--color-border-warning-loud);
--wa-color-warning-border-normal: var(--ha-color-border-warning-normal); --wa-color-warning-border-normal: var(--color-border-warning-normal);
--wa-color-warning-border-quiet: var(--ha-color-border-warning-quiet); --wa-color-warning-border-quiet: var(--color-border-warning-quiet);
--wa-color-warning-on-loud: var(--ha-color-on-warning-loud); --wa-color-warning-on-loud: var(--color-on-warning-loud);
--wa-color-warning-on-normal: var(--ha-color-on-warning-normal); --wa-color-warning-on-normal: var(--color-on-warning-normal);
--wa-color-warning-on-quiet: var(--ha-color-on-warning-quiet); --wa-color-warning-on-quiet: var(--color-on-warning-quiet);
--wa-color-danger-fill-loud: var(--ha-color-fill-danger-loud-resting); --wa-color-danger-fill-loud: var(--color-fill-danger-loud-resting);
--wa-color-danger-fill-normal: var(--ha-color-fill-danger-normal-resting); --wa-color-danger-fill-normal: var(--color-fill-danger-normal-resting);
--wa-color-danger-fill-quiet: var(--ha-color-fill-danger-quiet-resting); --wa-color-danger-fill-quiet: var(--color-fill-danger-quiet-resting);
--wa-color-danger-border-loud: var(--ha-color-border-danger-loud); --wa-color-danger-border-loud: var(--color-border-danger-loud);
--wa-color-danger-border-normal: var(--ha-color-border-danger-normal); --wa-color-danger-border-normal: var(--color-border-danger-normal);
--wa-color-danger-border-quiet: var(--ha-color-border-danger-quiet); --wa-color-danger-border-quiet: var(--color-border-danger-quiet);
--wa-color-danger-on-loud: var(--ha-color-on-danger-loud); --wa-color-danger-on-loud: var(--color-on-danger-loud);
--wa-color-danger-on-normal: var(--ha-color-on-danger-normal); --wa-color-danger-on-normal: var(--color-on-danger-normal);
--wa-color-danger-on-quiet: var(--ha-color-on-danger-quiet); --wa-color-danger-on-quiet: var(--color-on-danger-quiet);
--wa-focus-ring-color: var(--ha-color-neutral-60); --wa-focus-ring-color: var(--color-neutral-60);
} }
`; `;

View File

@ -1,24 +0,0 @@
import { css } from "lit";
import { extractDerivedVars } from "../../common/style/derived-css-vars";
export const coreStyles = css`
html {
--ha-border-width-sm: 1px;
--ha-border-width-md: 2px;
--ha-border-width-lg: 3px;
--ha-border-radius-sm: 4px;
--ha-border-radius-md: 8px;
--ha-border-radius-lg: 12px;
--ha-border-radius-xl: 16px;
--ha-border-radius-2xl: 24px;
--ha-border-radius-3xl: 28px;
--ha-border-radius-4xl: 32px;
--ha-border-radius-5xl: 36px;
--ha-border-radius-pill: 9999px;
--ha-border-radius-circle: 50%;
--ha-border-radius-square: 0;
}
`;
export const coreDerivedVariables = extractDerivedVars(coreStyles);

View File

@ -1,6 +1,5 @@
import { fontStyles } from "../roboto"; import { fontStyles } from "../roboto";
import { colorDerivedVariables, colorStylesCollection } from "./color"; import { colorDerivedVariables, colorStylesCollection } from "./color";
import { coreDerivedVariables, coreStyles } from "./core.globals";
import { mainDerivedVariables, mainStyles } from "./main.globals"; import { mainDerivedVariables, mainStyles } from "./main.globals";
import { import {
typographyDerivedVariables, typographyDerivedVariables,
@ -9,7 +8,6 @@ import {
import { waMainDerivedVariables, waMainStyles } from "./wa.globals"; import { waMainDerivedVariables, waMainStyles } from "./wa.globals";
export const themeStyles = [ export const themeStyles = [
coreStyles.toString(),
mainStyles.toString(), mainStyles.toString(),
typographyStyles.toString(), typographyStyles.toString(),
...colorStylesCollection, ...colorStylesCollection,
@ -18,7 +16,6 @@ export const themeStyles = [
].join(""); ].join("");
export const derivedStyles = { export const derivedStyles = {
...coreDerivedVariables,
...mainDerivedVariables, ...mainDerivedVariables,
...typographyDerivedVariables, ...typographyDerivedVariables,
...colorDerivedVariables, ...colorDerivedVariables,

View File

@ -1972,11 +1972,11 @@
}, },
"google_home": { "google_home": {
"header": "Share from Google Home", "header": "Share from Google Home",
"step_1": "Find your device in the Google Home app. Tap the gear icon to open the device settings, then tap on Device information.", "step_1": "Find your device in the Google Home app. Tap the gear icon to open the device settings.",
"step_2": "Tap {linked_matter_apps_services}.", "step_2": "Tap {linked_matter_apps_services}.",
"step_3": "Tap {link_apps_services} and choose {home_assistant} from the list.", "step_3": "Tap {link_apps_services} and choose {home_assistant} from the list.",
"linked_matter_apps_services": "Linked Matter apps and services", "linked_matter_apps_services": "Linked Matter apps and services",
"link_apps_services": "Link apps and services", "link_apps_services": "Link apps & services",
"no_home_assistant": "I can't find Home Assistant on the list", "no_home_assistant": "I can't find Home Assistant on the list",
"redirect": "You are redirected to the Home Assistant app. Please follow the instructions." "redirect": "You are redirected to the Home Assistant app. Please follow the instructions."
}, },
@ -2275,9 +2275,9 @@
}, },
"ai_task": { "ai_task": {
"header": "AI suggestions", "header": "AI suggestions",
"description": "Home Assistant can use generative AI to help you with tasks. Look for the button with the {button} icon throughout Home Assistant to get suggestions. Select an AI task entity to use this feature.", "description": "Home Assistant can use generative AI to help you with tasks like writing automations, creating scripts, and more. Look for the button with the {button} icon throughout Home Assistant to get suggestions.",
"gen_data_header": "Data generation tasks", "gen_data_header": "Data generation tasks",
"gen_data_description": "Suggest automation names." "gen_data_description": "Suggest automation names or dashboards."
}, },
"category": { "category": {
"caption": "Categories", "caption": "Categories",
@ -4418,9 +4418,9 @@
"no_conditions": "[%key:ui::panel::config::devices::automation::conditions::no_conditions%]", "no_conditions": "[%key:ui::panel::config::devices::automation::conditions::no_conditions%]",
"sequence": "Actions", "sequence": "Actions",
"description": { "description": {
"picker": "Choose what to do based on conditions (Similar to If-then, but more powerful).", "picker": "Choose what to do based on conditions (Similar to If-Then, but more powerful).",
"full": "Choose {number, plural,\n one {an option}\n other{between {number} options}\n}", "full": "Choose {number, plural,\n one {an action}\n other{between {number} actions}\n}",
"no_action": "Choose an option" "no_action": "Choose an action"
} }
}, },
"if": { "if": {
@ -5633,6 +5633,8 @@
"description_publish": "Publish a packet", "description_publish": "Publish a packet",
"topic": "Topic", "topic": "Topic",
"payload": "Payload (template allowed)", "payload": "Payload (template allowed)",
"payload_no_template": "Payload",
"allow_template": "Allow template",
"publish": "Publish", "publish": "Publish",
"description_listen": "Listen to a topic", "description_listen": "Listen to a topic",
"json_formatting": "Format JSON content", "json_formatting": "Format JSON content",
@ -5919,11 +5921,6 @@
"restoring": "Restoring backup", "restoring": "Restoring backup",
"migrate": "Migrate adapter" "migrate": "Migrate adapter"
}, },
"data_collection": {
"title": "Third-party data reporting",
"description": "Enable the reporting of anonymized telemetry and statistics to the Z-Wave JS organization. This data will be used to focus development efforts and improve the user experience. Information about the data that is collected and how it is used, including an example of the data collected, can be found in the {documentation_link}.",
"documentation_link": "Z-Wave JS data collection documentation"
},
"statistics": { "statistics": {
"title": "Adapter statistics", "title": "Adapter statistics",
"messages_tx": { "messages_tx": {
@ -6617,8 +6614,7 @@
"description": "{percent_used} used - {free_space} free", "description": "{percent_used} used - {free_space} free",
"used_space": "Used space", "used_space": "Used space",
"detailed_description": "{used} used of {total} total, {free_space} remaining", "detailed_description": "{used} used of {total} total, {free_space} remaining",
"lifetime_used": "Lifetime used", "emmc_lifetime_used": "eMMC lifetime used",
"lifetime_used_description": "The drives wear level is shown as a percentage, based on endurance indicators reported by the device via NVMe SMART or eMMC lifetime estimate fields.",
"disk_metrics": "Disk metrics", "disk_metrics": "Disk metrics",
"datadisk": { "datadisk": {
"title": "Move data disk", "title": "Move data disk",
@ -7283,9 +7279,6 @@
"or": { "or": {
"label": "Or" "label": "Or"
}, },
"not": {
"label": "Not"
},
"and": { "and": {
"label": "And" "label": "And"
} }
@ -7796,9 +7789,6 @@
"edit": "Edit feature", "edit": "Edit feature",
"remove": "Remove feature", "remove": "Remove feature",
"types": { "types": {
"button": {
"label": "Button"
},
"cover-open-close": { "cover-open-close": {
"label": "Cover open/close" "label": "Cover open/close"
}, },
@ -9438,7 +9428,7 @@
"operating_system": "Operating system", "operating_system": "Operating system",
"docker_version": "Docker version", "docker_version": "Docker version",
"deployment": "Deployment", "deployment": "Deployment",
"lifetime_used": "Lifetime used", "emmc_lifetime_used": "eMMC lifetime used",
"reboot_host": "Reboot host", "reboot_host": "Reboot host",
"confirm_reboot": "Are you sure you want to reboot the host?", "confirm_reboot": "Are you sure you want to reboot the host?",
"confirm_shutdown": "Are you sure you want to shut down the host?", "confirm_shutdown": "Are you sure you want to shut down the host?",

667
yarn.lock

File diff suppressed because it is too large Load Diff