20240930.0 (#22166)

This commit is contained in:
Bram Kragten 2024-09-30 17:38:30 +02:00 committed by GitHub
commit 268eb4317c
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
33 changed files with 225 additions and 173 deletions

View File

@ -21,7 +21,7 @@ jobs:
url: ${{ steps.deploy.outputs.NETLIFY_LIVE_URL || steps.deploy.outputs.NETLIFY_URL }} url: ${{ steps.deploy.outputs.NETLIFY_LIVE_URL || steps.deploy.outputs.NETLIFY_URL }}
steps: steps:
- name: Check out files from GitHub - name: Check out files from GitHub
uses: actions/checkout@v4.1.7 uses: actions/checkout@v4.2.0
with: with:
ref: dev ref: dev
@ -57,7 +57,7 @@ jobs:
url: ${{ steps.deploy.outputs.NETLIFY_LIVE_URL || steps.deploy.outputs.NETLIFY_URL }} url: ${{ steps.deploy.outputs.NETLIFY_LIVE_URL || steps.deploy.outputs.NETLIFY_URL }}
steps: steps:
- name: Check out files from GitHub - name: Check out files from GitHub
uses: actions/checkout@v4.1.7 uses: actions/checkout@v4.2.0
with: with:
ref: master ref: master

View File

@ -24,7 +24,7 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Check out files from GitHub - name: Check out files from GitHub
uses: actions/checkout@v4.1.7 uses: actions/checkout@v4.2.0
- name: Setup Node - name: Setup Node
uses: actions/setup-node@v4.0.4 uses: actions/setup-node@v4.0.4
with: with:
@ -58,7 +58,7 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Check out files from GitHub - name: Check out files from GitHub
uses: actions/checkout@v4.1.7 uses: actions/checkout@v4.2.0
- name: Setup Node - name: Setup Node
uses: actions/setup-node@v4.0.4 uses: actions/setup-node@v4.0.4
with: with:
@ -76,7 +76,7 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Check out files from GitHub - name: Check out files from GitHub
uses: actions/checkout@v4.1.7 uses: actions/checkout@v4.2.0
- name: Setup Node - name: Setup Node
uses: actions/setup-node@v4.0.4 uses: actions/setup-node@v4.0.4
with: with:
@ -100,7 +100,7 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Check out files from GitHub - name: Check out files from GitHub
uses: actions/checkout@v4.1.7 uses: actions/checkout@v4.2.0
- name: Setup Node - name: Setup Node
uses: actions/setup-node@v4.0.4 uses: actions/setup-node@v4.0.4
with: with:

View File

@ -23,7 +23,7 @@ jobs:
steps: steps:
- name: Checkout repository - name: Checkout repository
uses: actions/checkout@v4.1.7 uses: actions/checkout@v4.2.0
with: with:
# We must fetch at least the immediate parents so that if this is # We must fetch at least the immediate parents so that if this is
# a pull request then we can checkout the head. # a pull request then we can checkout the head.

View File

@ -22,7 +22,7 @@ jobs:
url: ${{ steps.deploy.outputs.NETLIFY_LIVE_URL || steps.deploy.outputs.NETLIFY_URL }} url: ${{ steps.deploy.outputs.NETLIFY_LIVE_URL || steps.deploy.outputs.NETLIFY_URL }}
steps: steps:
- name: Check out files from GitHub - name: Check out files from GitHub
uses: actions/checkout@v4.1.7 uses: actions/checkout@v4.2.0
with: with:
ref: dev ref: dev
@ -58,7 +58,7 @@ jobs:
url: ${{ steps.deploy.outputs.NETLIFY_LIVE_URL || steps.deploy.outputs.NETLIFY_URL }} url: ${{ steps.deploy.outputs.NETLIFY_LIVE_URL || steps.deploy.outputs.NETLIFY_URL }}
steps: steps:
- name: Check out files from GitHub - name: Check out files from GitHub
uses: actions/checkout@v4.1.7 uses: actions/checkout@v4.2.0
with: with:
ref: master ref: master

View File

@ -16,7 +16,7 @@ jobs:
url: ${{ steps.deploy.outputs.NETLIFY_LIVE_URL || steps.deploy.outputs.NETLIFY_URL }} url: ${{ steps.deploy.outputs.NETLIFY_LIVE_URL || steps.deploy.outputs.NETLIFY_URL }}
steps: steps:
- name: Check out files from GitHub - name: Check out files from GitHub
uses: actions/checkout@v4.1.7 uses: actions/checkout@v4.2.0
- name: Setup Node - name: Setup Node
uses: actions/setup-node@v4.0.4 uses: actions/setup-node@v4.0.4

View File

@ -21,7 +21,7 @@ jobs:
if: github.repository == 'home-assistant/frontend' && contains(github.event.pull_request.labels.*.name, 'needs design preview') if: github.repository == 'home-assistant/frontend' && contains(github.event.pull_request.labels.*.name, 'needs design preview')
steps: steps:
- name: Check out files from GitHub - name: Check out files from GitHub
uses: actions/checkout@v4.1.7 uses: actions/checkout@v4.2.0
- name: Setup Node - name: Setup Node
uses: actions/setup-node@v4.0.4 uses: actions/setup-node@v4.0.4

View File

@ -20,7 +20,7 @@ jobs:
contents: write contents: write
steps: steps:
- name: Checkout the repository - name: Checkout the repository
uses: actions/checkout@v4.1.7 uses: actions/checkout@v4.2.0
- name: Set up Python ${{ env.PYTHON_VERSION }} - name: Set up Python ${{ env.PYTHON_VERSION }}
uses: actions/setup-python@v5 uses: actions/setup-python@v5

View File

@ -23,7 +23,7 @@ jobs:
contents: write # Required to upload release assets contents: write # Required to upload release assets
steps: steps:
- name: Checkout the repository - name: Checkout the repository
uses: actions/checkout@v4.1.7 uses: actions/checkout@v4.2.0
- name: Verify version - name: Verify version
uses: home-assistant/actions/helpers/verify-version@master uses: home-assistant/actions/helpers/verify-version@master

View File

@ -13,7 +13,7 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Checkout the repository - name: Checkout the repository
uses: actions/checkout@v4.1.7 uses: actions/checkout@v4.2.0
- name: Upload Translations - name: Upload Translations
run: | run: |

View File

@ -27,3 +27,5 @@ A complete guide can be found at the following [link](https://www.home-assistant
Home Assistant is open-source and Apache 2 licensed. Feel free to browse the repository, learn and reuse parts in your own projects. Home Assistant is open-source and Apache 2 licensed. Feel free to browse the repository, learn and reuse parts in your own projects.
We use [BrowserStack](https://www.browserstack.com) to test Home Assistant on a large variety of devices. We use [BrowserStack](https://www.browserstack.com) to test Home Assistant on a large variety of devices.
[![Home Assistant - A project from the Open Home Foundation](https://www.openhomefoundation.org/badges/home-assistant.png)](https://www.openhomefoundation.org/)

View File

@ -142,7 +142,7 @@ export class DemoAutomationDescribeAction extends LitElement {
<div class="action"> <div class="action">
<span> <span>
${this._action ${this._action
? describeAction(this.hass, [], [], [], this._action) ? describeAction(this.hass, [], [], this._action)
: "<invalid YAML>"} : "<invalid YAML>"}
</span> </span>
<ha-yaml-editor <ha-yaml-editor
@ -155,7 +155,7 @@ export class DemoAutomationDescribeAction extends LitElement {
${ACTIONS.map( ${ACTIONS.map(
(conf) => html` (conf) => html`
<div class="action"> <div class="action">
<span>${describeAction(this.hass, [], [], [], conf as any)}</span> <span>${describeAction(this.hass, [], [], conf as any)}</span>
<pre>${dump(conf)}</pre> <pre>${dump(conf)}</pre>
</div> </div>
` `

View File

@ -33,7 +33,7 @@
"@codemirror/legacy-modes": "6.4.1", "@codemirror/legacy-modes": "6.4.1",
"@codemirror/search": "6.5.6", "@codemirror/search": "6.5.6",
"@codemirror/state": "6.4.1", "@codemirror/state": "6.4.1",
"@codemirror/view": "6.33.0", "@codemirror/view": "6.34.0",
"@egjs/hammerjs": "2.0.17", "@egjs/hammerjs": "2.0.17",
"@formatjs/intl-datetimeformat": "6.12.5", "@formatjs/intl-datetimeformat": "6.12.5",
"@formatjs/intl-displaynames": "6.6.8", "@formatjs/intl-displaynames": "6.6.8",
@ -229,7 +229,7 @@
"open": "10.1.0", "open": "10.1.0",
"pinst": "3.0.0", "pinst": "3.0.0",
"prettier": "3.3.3", "prettier": "3.3.3",
"rollup": "2.79.1", "rollup": "2.79.2",
"rollup-plugin-string": "3.0.0", "rollup-plugin-string": "3.0.0",
"rollup-plugin-terser": "7.0.2", "rollup-plugin-terser": "7.0.2",
"rollup-plugin-visualizer": "5.12.0", "rollup-plugin-visualizer": "5.12.0",
@ -241,7 +241,7 @@
"transform-async-modules-webpack-plugin": "1.1.1", "transform-async-modules-webpack-plugin": "1.1.1",
"ts-lit-plugin": "2.0.2", "ts-lit-plugin": "2.0.2",
"typescript": "5.6.2", "typescript": "5.6.2",
"webpack": "5.94.0", "webpack": "5.95.0",
"webpack-cli": "5.1.4", "webpack-cli": "5.1.4",
"webpack-dev-server": "5.1.0", "webpack-dev-server": "5.1.0",
"webpack-manifest-plugin": "5.0.0", "webpack-manifest-plugin": "5.0.0",

View File

@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
[project] [project]
name = "home-assistant-frontend" name = "home-assistant-frontend"
version = "20240927.0" version = "20240930.0"
license = {text = "Apache-2.0"} license = {text = "Apache-2.0"}
description = "The Home Assistant frontend" description = "The Home Assistant frontend"
readme = "README.md" readme = "README.md"

View File

@ -1,36 +1,36 @@
import { theme2hex } from "./convert-color"; import { theme2hex } from "./convert-color";
export const COLORS = [ export const COLORS = [
"#44739e", "#4269d0",
"#984ea3", "#f4bd4a",
"#00d2d5", "#ff725c",
"#ff7f00", "#6cc5b0",
"#af8d00", "#a463f2",
"#7f80cd", "#ff8ab7",
"#b3e900", "#9c6b4e",
"#c42e60", "#97bbf5",
"#a65628", "#01ab63",
"#f781bf", "#9498a0",
"#8dd3c7", "#094bad",
"#bebada", "#c99000",
"#fb8072", "#d84f3e",
"#80b1d3", "#49a28f",
"#fdb462", "#048732",
"#fccde5", "#d96895",
"#bc80bd", "#8043ce",
"#ffed6f", "#7599d1",
"#c4eaff", "#7a4c31",
"#cf8c00", "#74787f",
"#1b9e77", "#6989f4",
"#d95f02", "#ffd444",
"#e7298a", "#ff957c",
"#e6ab02", "#8fe9d3",
"#a6761d", "#62cc71",
"#0097ff", "#ffadda",
"#00d067", "#c884ff",
"#f43600", "#badeff",
"#4ba93b", "#bf8b6d",
"#5779bb", "#b6bac2",
"#927acc", "#927acc",
"#97ee3f", "#97ee3f",
"#bf3947", "#bf3947",

View File

@ -1011,6 +1011,7 @@ export class HaDataTable extends LitElement {
/* @noflip */ /* @noflip */
padding-inline-end: initial; padding-inline-end: initial;
width: 60px; width: 60px;
min-width: 60px;
} }
.mdc-data-table__table { .mdc-data-table__table {

View File

@ -1,10 +1,17 @@
import { TextAreaCharCounter } from "@material/mwc-textfield/mwc-textfield-base"; import { TextAreaCharCounter } from "@material/mwc-textfield/mwc-textfield-base";
import { mdiEye, mdiEyeOff } from "@mdi/js"; import { mdiEye, mdiEyeOff } from "@mdi/js";
import { LitElement, css, html } from "lit"; import { LitElement, css, html } from "lit";
import { customElement, eventOptions, property, state } from "lit/decorators"; import {
customElement,
eventOptions,
property,
query,
state,
} from "lit/decorators";
import { HomeAssistant } from "../types"; import { HomeAssistant } from "../types";
import "./ha-icon-button"; import "./ha-icon-button";
import "./ha-textfield"; import "./ha-textfield";
import type { HaTextField } from "./ha-textfield";
@customElement("ha-password-field") @customElement("ha-password-field")
export class HaPasswordField extends LitElement { export class HaPasswordField extends LitElement {
@ -75,6 +82,8 @@ export class HaPasswordField extends LitElement {
@state() private _unmaskedPassword = false; @state() private _unmaskedPassword = false;
@query("ha-textfield") private _textField!: HaTextField;
protected render() { protected render() {
return html`<ha-textfield return html`<ha-textfield
.invalid=${this.invalid} .invalid=${this.invalid}
@ -122,6 +131,22 @@ export class HaPasswordField extends LitElement {
></ha-icon-button>`; ></ha-icon-button>`;
} }
public checkValidity(): boolean {
return this._textField.checkValidity();
}
public reportValidity(): boolean {
return this._textField.reportValidity();
}
public setCustomValidity(message: string): void {
return this._textField.setCustomValidity(message);
}
public layout(): Promise<void> {
return this._textField.layout();
}
private _toggleUnmaskedPassword(): void { private _toggleUnmaskedPassword(): void {
this._unmaskedPassword = !this._unmaskedPassword; this._unmaskedPassword = !this._unmaskedPassword;
} }

View File

@ -805,7 +805,8 @@ export class HaServiceControl extends LitElement {
const value = ev.detail.value; const value = ev.detail.value;
if ( if (
this._value?.data?.[key] === value || this._value?.data?.[key] === value ||
(!this._value?.data?.[key] && (value === "" || value === undefined)) ((!this._value?.data || !(key in this._value.data)) &&
(value === "" || value === undefined))
) { ) {
return; return;
} }

View File

@ -18,7 +18,7 @@ import type { HaCodeEditor } from "./ha-code-editor";
import "./ha-button"; import "./ha-button";
const isEmpty = (obj: Record<string, unknown>): boolean => { const isEmpty = (obj: Record<string, unknown>): boolean => {
if (typeof obj !== "object") { if (typeof obj !== "object" || obj === null) {
return false; return false;
} }
for (const key in obj) { for (const key in obj) {
@ -59,14 +59,13 @@ export class HaYamlEditor extends LitElement {
public setValue(value): void { public setValue(value): void {
try { try {
this._yaml = this._yaml = !isEmpty(value)
value && !isEmpty(value) ? dump(value, {
? dump(value, { schema: this.yamlSchema,
schema: this.yamlSchema, quotingType: '"',
quotingType: '"', noRefs: true,
noRefs: true, })
}) : "";
: "";
} catch (err: any) { } catch (err: any) {
// eslint-disable-next-line no-console // eslint-disable-next-line no-console
console.error(err, value); console.error(err, value);
@ -75,7 +74,7 @@ export class HaYamlEditor extends LitElement {
} }
protected firstUpdated(): void { protected firstUpdated(): void {
if (this.defaultValue) { if (this.defaultValue !== undefined) {
this.setValue(this.defaultValue); this.setValue(this.defaultValue);
} }
} }

View File

@ -22,13 +22,8 @@ import { formatDateTimeWithSeconds } from "../../common/datetime/format_date_tim
import { relativeTime } from "../../common/datetime/relative_time"; import { relativeTime } from "../../common/datetime/relative_time";
import { fireEvent } from "../../common/dom/fire_event"; import { fireEvent } from "../../common/dom/fire_event";
import { toggleAttribute } from "../../common/dom/toggle_attribute"; import { toggleAttribute } from "../../common/dom/toggle_attribute";
import { import { fullEntitiesContext, labelsContext } from "../../data/context";
floorsContext,
fullEntitiesContext,
labelsContext,
} from "../../data/context";
import { EntityRegistryEntry } from "../../data/entity_registry"; import { EntityRegistryEntry } from "../../data/entity_registry";
import { FloorRegistryEntry } from "../../data/floor_registry";
import { LabelRegistryEntry } from "../../data/label_registry"; import { LabelRegistryEntry } from "../../data/label_registry";
import { LogbookEntry } from "../../data/logbook"; import { LogbookEntry } from "../../data/logbook";
import { import {
@ -206,7 +201,6 @@ class ActionRenderer {
private hass: HomeAssistant, private hass: HomeAssistant,
private entityReg: EntityRegistryEntry[], private entityReg: EntityRegistryEntry[],
private labelReg: LabelRegistryEntry[], private labelReg: LabelRegistryEntry[],
private floorReg: FloorRegistryEntry[],
private entries: TemplateResult[], private entries: TemplateResult[],
private trace: AutomationTraceExtended, private trace: AutomationTraceExtended,
private logbookRenderer: LogbookRenderer, private logbookRenderer: LogbookRenderer,
@ -325,7 +319,6 @@ class ActionRenderer {
this.hass, this.hass,
this.entityReg, this.entityReg,
this.labelReg, this.labelReg,
this.floorReg,
data, data,
actionType actionType
), ),
@ -493,13 +486,7 @@ class ActionRenderer {
const name = const name =
repeatConfig.alias || repeatConfig.alias ||
describeAction( describeAction(this.hass, this.entityReg, this.labelReg, repeatConfig);
this.hass,
this.entityReg,
this.labelReg,
this.floorReg,
repeatConfig
);
this._renderEntry(repeatPath, name, undefined, disabled); this._renderEntry(repeatPath, name, undefined, disabled);
@ -597,7 +584,6 @@ class ActionRenderer {
this.hass, this.hass,
this.entityReg, this.entityReg,
this.labelReg, this.labelReg,
this.floorReg,
sequenceConfig, sequenceConfig,
"sequence" "sequence"
), ),
@ -694,10 +680,6 @@ export class HaAutomationTracer extends LitElement {
@consume({ context: labelsContext, subscribe: true }) @consume({ context: labelsContext, subscribe: true })
_labelReg!: LabelRegistryEntry[]; _labelReg!: LabelRegistryEntry[];
@state()
@consume({ context: floorsContext, subscribe: true })
_floorReg!: FloorRegistryEntry[];
protected render() { protected render() {
if (!this.trace) { if (!this.trace) {
return nothing; return nothing;
@ -715,7 +697,6 @@ export class HaAutomationTracer extends LitElement {
this.hass, this.hass,
this._entityReg, this._entityReg,
this._labelReg, this._labelReg,
this._floorReg,
entries, entries,
this.trace, this.trace,
logbookRenderer, logbookRenderer,

View File

@ -2,7 +2,6 @@ import { createContext } from "@lit-labs/context";
import { HassConfig } from "home-assistant-js-websocket"; import { HassConfig } from "home-assistant-js-websocket";
import { HomeAssistant } from "../types"; import { HomeAssistant } from "../types";
import { EntityRegistryEntry } from "./entity_registry"; import { EntityRegistryEntry } from "./entity_registry";
import { FloorRegistryEntry } from "./floor_registry";
import { LabelRegistryEntry } from "./label_registry"; import { LabelRegistryEntry } from "./label_registry";
export const connectionContext = export const connectionContext =
@ -28,6 +27,4 @@ export const panelsContext = createContext<HomeAssistant["panels"]>("panels");
export const fullEntitiesContext = export const fullEntitiesContext =
createContext<EntityRegistryEntry[]>("extendedEntities"); createContext<EntityRegistryEntry[]>("extendedEntities");
export const floorsContext = createContext<FloorRegistryEntry[]>("floors");
export const labelsContext = createContext<LabelRegistryEntry[]>("labels"); export const labelsContext = createContext<LabelRegistryEntry[]>("labels");

View File

@ -14,7 +14,6 @@ import {
computeEntityRegistryName, computeEntityRegistryName,
entityRegistryById, entityRegistryById,
} from "./entity_registry"; } from "./entity_registry";
import { FloorRegistryEntry } from "./floor_registry";
import { domainToName } from "./integration"; import { domainToName } from "./integration";
import { LabelRegistryEntry } from "./label_registry"; import { LabelRegistryEntry } from "./label_registry";
import { import {
@ -44,7 +43,6 @@ export const describeAction = <T extends ActionType>(
hass: HomeAssistant, hass: HomeAssistant,
entityRegistry: EntityRegistryEntry[], entityRegistry: EntityRegistryEntry[],
labelRegistry: LabelRegistryEntry[], labelRegistry: LabelRegistryEntry[],
floorRegistry: FloorRegistryEntry[],
action: ActionTypes[T], action: ActionTypes[T],
actionType?: T, actionType?: T,
ignoreAlias = false ignoreAlias = false
@ -54,7 +52,6 @@ export const describeAction = <T extends ActionType>(
hass, hass,
entityRegistry, entityRegistry,
labelRegistry, labelRegistry,
floorRegistry,
action, action,
actionType, actionType,
ignoreAlias ignoreAlias
@ -78,7 +75,6 @@ const tryDescribeAction = <T extends ActionType>(
hass: HomeAssistant, hass: HomeAssistant,
entityRegistry: EntityRegistryEntry[], entityRegistry: EntityRegistryEntry[],
labelRegistry: LabelRegistryEntry[], labelRegistry: LabelRegistryEntry[],
floorRegistry: FloorRegistryEntry[],
action: ActionTypes[T], action: ActionTypes[T],
actionType?: T, actionType?: T,
ignoreAlias = false ignoreAlias = false
@ -168,9 +164,7 @@ const tryDescribeAction = <T extends ActionType>(
); );
} }
} else if (key === "floor_id") { } else if (key === "floor_id") {
const floor = floorRegistry.find( const floor = hass.floors[targetThing] ?? undefined;
(flr) => flr.floor_id === targetThing
);
if (floor?.name) { if (floor?.name) {
targets.push(floor.name); targets.push(floor.name);
} else { } else {

View File

@ -144,7 +144,7 @@ export class HaVoiceAssistantSetupStepPipeline extends LitElement {
{ option: "preferred" }, { option: "preferred" },
{ entity_id: this.assistConfiguration?.pipeline_entity_id } { entity_id: this.assistConfiguration?.pipeline_entity_id }
); );
this._nextStep(STEP.SUCCESS); fireEvent(this, "next-step", { step: STEP.SUCCESS, noPrevious: true });
return; return;
} }
} }
@ -210,15 +210,15 @@ export class HaVoiceAssistantSetupStepPipeline extends LitElement {
{ option: cloudPipeline.name }, { option: cloudPipeline.name },
{ entity_id: this.assistConfiguration?.pipeline_entity_id } { entity_id: this.assistConfiguration?.pipeline_entity_id }
); );
this._nextStep(STEP.SUCCESS); fireEvent(this, "next-step", { step: STEP.SUCCESS, noPrevious: true });
} }
private async _setupCloud() { private async _setupCloud() {
fireEvent(this, "next-step", { step: STEP.CLOUD }); this._nextStep(STEP.CLOUD);
} }
private async _thisSystem() { private async _thisSystem() {
fireEvent(this, "next-step", { step: STEP.ADDONS }); this._nextStep(STEP.ADDONS);
} }
private _skip() { private _skip() {

View File

@ -14,6 +14,7 @@ import {
import { import {
assistSatelliteAnnounce, assistSatelliteAnnounce,
AssistSatelliteConfiguration, AssistSatelliteConfiguration,
setWakeWords,
} from "../../data/assist_satellite"; } from "../../data/assist_satellite";
import { fetchCloudStatus } from "../../data/cloud"; import { fetchCloudStatus } from "../../data/cloud";
import { showVoiceAssistantPipelineDetailDialog } from "../../panels/config/voice-assistants/show-dialog-voice-assistant-pipeline-detail"; import { showVoiceAssistantPipelineDetailDialog } from "../../panels/config/voice-assistants/show-dialog-voice-assistant-pipeline-detail";
@ -21,6 +22,8 @@ import "../../panels/lovelace/entity-rows/hui-select-entity-row";
import { HomeAssistant } from "../../types"; import { HomeAssistant } from "../../types";
import { AssistantSetupStyles } from "./styles"; import { AssistantSetupStyles } from "./styles";
import { STEP } from "./voice-assistant-setup-dialog"; import { STEP } from "./voice-assistant-setup-dialog";
import { setSelectOption } from "../../data/select";
import { InputSelectEntity } from "../../data/input_select";
@customElement("ha-voice-assistant-setup-step-success") @customElement("ha-voice-assistant-setup-step-success")
export class HaVoiceAssistantSetupStepSuccess extends LitElement { export class HaVoiceAssistantSetupStepSuccess extends LitElement {
@ -58,7 +61,9 @@ export class HaVoiceAssistantSetupStepSuccess extends LitElement {
protected override render() { protected override render() {
const pipelineEntity = this.assistConfiguration const pipelineEntity = this.assistConfiguration
? this.hass.states[this.assistConfiguration.pipeline_entity_id] ? (this.hass.states[
this.assistConfiguration.pipeline_entity_id
] as InputSelectEntity)
: undefined; : undefined;
return html`<div class="content"> return html`<div class="content">
@ -69,46 +74,53 @@ export class HaVoiceAssistantSetupStepSuccess extends LitElement {
settings, you can change that below. settings, you can change that below.
</p> </p>
<div class="rows"> <div class="rows">
<div class="row"> ${this.assistConfiguration &&
<ha-select this.assistConfiguration.available_wake_words.length > 1
.label=${"Wake word"} ? html` <div class="row">
@closed=${stopPropagation} <ha-select
fixedMenuPosition .label=${"Wake word"}
naturalMenuWidth @closed=${stopPropagation}
.value=${this.assistConfiguration?.active_wake_words[0]} fixedMenuPosition
> naturalMenuWidth
${this.assistConfiguration?.available_wake_words.map( .value=${this.assistConfiguration.active_wake_words[0]}
(wakeword) => @selected=${this._wakeWordPicked}
html`<ha-list-item .value=${wakeword.id}> >
${wakeword.wake_word} ${this.assistConfiguration.available_wake_words.map(
</ha-list-item>` (wakeword) =>
)} html`<ha-list-item .value=${wakeword.id}>
</ha-select> ${wakeword.wake_word}
<ha-button @click=${this._testWakeWord}> </ha-list-item>`
<ha-svg-icon slot="icon" .path=${mdiMicrophone}></ha-svg-icon> )}
Test </ha-select>
</ha-button> <ha-button @click=${this._testWakeWord}>
</div> <ha-svg-icon slot="icon" .path=${mdiMicrophone}></ha-svg-icon>
<div class="row"> Test
<ha-select </ha-button>
.label=${"Assistant"} </div>`
@closed=${stopPropagation} : nothing}
.value=${pipelineEntity?.state} ${pipelineEntity
fixedMenuPosition ? html`<div class="row">
naturalMenuWidth <ha-select
> .label=${"Assistant"}
${pipelineEntity?.attributes.options.map( @closed=${stopPropagation}
(pipeline) => .value=${pipelineEntity?.state}
html`<ha-list-item .value=${pipeline}> fixedMenuPosition
${this.hass.formatEntityState(pipelineEntity, pipeline)} naturalMenuWidth
</ha-list-item>` @selected=${this._pipelinePicked}
)} >
</ha-select> ${pipelineEntity?.attributes.options.map(
<ha-button @click=${this._openPipeline}> (pipeline) =>
<ha-svg-icon slot="icon" .path=${mdiCog}></ha-svg-icon> html`<ha-list-item .value=${pipeline}>
Edit ${this.hass.formatEntityState(pipelineEntity, pipeline)}
</ha-button> </ha-list-item>`
</div> )}
</ha-select>
<ha-button @click=${this._openPipeline}>
<ha-svg-icon slot="icon" .path=${mdiCog}></ha-svg-icon>
Edit
</ha-button>
</div>`
: nothing}
${this._ttsSettings ${this._ttsSettings
? html`<div class="row"> ? html`<div class="row">
<ha-tts-voice-picker <ha-tts-voice-picker
@ -156,6 +168,25 @@ export class HaVoiceAssistantSetupStepSuccess extends LitElement {
return [pipeline, pipelines.preferred_pipeline]; return [pipeline, pipelines.preferred_pipeline];
} }
private async _wakeWordPicked(ev) {
const option = ev.target.value;
await setWakeWords(this.hass, this.assistEntityId!, [option]);
}
private _pipelinePicked(ev) {
const stateObj = this.hass!.states[
this.assistConfiguration!.pipeline_entity_id
] as InputSelectEntity;
const option = ev.target.value;
if (
option === stateObj.state ||
!stateObj.attributes.options.includes(option)
) {
return;
}
setSelectOption(this.hass!, stateObj.entity_id, option);
}
private async _setTtsSettings() { private async _setTtsSettings() {
const [pipeline] = await this._getPipeline(); const [pipeline] = await this._getPipeline();
if (!pipeline) { if (!pipeline) {
@ -197,6 +228,7 @@ export class HaVoiceAssistantSetupStepSuccess extends LitElement {
fireEvent(this, "next-step", { fireEvent(this, "next-step", {
step: STEP.WAKEWORD, step: STEP.WAKEWORD,
nextStep: STEP.SUCCESS, nextStep: STEP.SUCCESS,
updateConfig: true,
}); });
} }

View File

@ -43,13 +43,8 @@ import type { HaYamlEditor } from "../../../../components/ha-yaml-editor";
import { ACTION_ICONS, YAML_ONLY_ACTION_TYPES } from "../../../../data/action"; import { ACTION_ICONS, YAML_ONLY_ACTION_TYPES } from "../../../../data/action";
import { AutomationClipboard } from "../../../../data/automation"; import { AutomationClipboard } from "../../../../data/automation";
import { validateConfig } from "../../../../data/config"; import { validateConfig } from "../../../../data/config";
import { import { fullEntitiesContext, labelsContext } from "../../../../data/context";
floorsContext,
fullEntitiesContext,
labelsContext,
} from "../../../../data/context";
import { EntityRegistryEntry } from "../../../../data/entity_registry"; import { EntityRegistryEntry } from "../../../../data/entity_registry";
import { FloorRegistryEntry } from "../../../../data/floor_registry";
import { LabelRegistryEntry } from "../../../../data/label_registry"; import { LabelRegistryEntry } from "../../../../data/label_registry";
import { import {
Action, Action,
@ -159,10 +154,6 @@ export default class HaAutomationActionRow extends LitElement {
@consume({ context: labelsContext, subscribe: true }) @consume({ context: labelsContext, subscribe: true })
_labelReg!: LabelRegistryEntry[]; _labelReg!: LabelRegistryEntry[];
@state()
@consume({ context: floorsContext, subscribe: true })
_floorReg!: FloorRegistryEntry[];
@state() private _warnings?: string[]; @state() private _warnings?: string[];
@state() private _uiModeAvailable = true; @state() private _uiModeAvailable = true;
@ -231,7 +222,6 @@ export default class HaAutomationActionRow extends LitElement {
this.hass, this.hass,
this._entityReg, this._entityReg,
this._labelReg, this._labelReg,
this._floorReg,
this.action this.action
) )
)} )}
@ -603,7 +593,6 @@ export default class HaAutomationActionRow extends LitElement {
this.hass, this.hass,
this._entityReg, this._entityReg,
this._labelReg, this._labelReg,
this._floorReg,
this.action, this.action,
undefined, undefined,
true true

View File

@ -41,7 +41,9 @@ class DialogAutomationRename extends LitElement implements HassDialog {
this._newIcon = "icon" in params.config ? params.config.icon : undefined; this._newIcon = "icon" in params.config ? params.config.icon : undefined;
this._newName = this._newName =
params.config.alias || params.config.alias ||
this.hass.localize("ui.panel.config.automation.editor.default_name"); this.hass.localize(
`ui.panel.config.${this._params.domain}.editor.default_name`
);
this._newDescription = params.config.description || ""; this._newDescription = params.config.description || "";
} }
@ -83,7 +85,7 @@ class DialogAutomationRename extends LitElement implements HassDialog {
dialogInitialFocus dialogInitialFocus
.value=${this._newName} .value=${this._newName}
.placeholder=${this.hass.localize( .placeholder=${this.hass.localize(
"ui.panel.config.automation.editor.default_name" `ui.panel.config.${this._params.domain}.editor.default_name`
)} )}
.label=${this.hass.localize( .label=${this.hass.localize(
"ui.panel.config.automation.editor.alias" "ui.panel.config.automation.editor.alias"

View File

@ -1,8 +1,8 @@
import "@material/mwc-button"; import "@material/mwc-button";
import "@material/mwc-list/mwc-list"; import "@material/mwc-list/mwc-list";
import { mdiDeleteForever, mdiDotsVertical } from "@mdi/js";
import { css, html, LitElement, TemplateResult } from "lit"; import { css, html, LitElement, TemplateResult } from "lit";
import { customElement, property, query, state } from "lit/decorators"; import { customElement, property, query, state } from "lit/decorators";
import { mdiDeleteForever, mdiDotsVertical } from "@mdi/js";
import { fireEvent } from "../../../../common/dom/fire_event"; import { fireEvent } from "../../../../common/dom/fire_event";
import { navigate } from "../../../../common/navigate"; import { navigate } from "../../../../common/navigate";
import "../../../../components/buttons/ha-progress-button"; import "../../../../components/buttons/ha-progress-button";
@ -10,8 +10,11 @@ import "../../../../components/ha-alert";
import "../../../../components/ha-card"; import "../../../../components/ha-card";
import "../../../../components/ha-icon-next"; import "../../../../components/ha-icon-next";
import "../../../../components/ha-list-item"; import "../../../../components/ha-list-item";
import type { HaTextField } from "../../../../components/ha-textfield"; import "../../../../components/ha-password-field";
import type { HaPasswordField } from "../../../../components/ha-password-field";
import "../../../../components/ha-textfield"; import "../../../../components/ha-textfield";
import type { HaTextField } from "../../../../components/ha-textfield";
import { setAssistPipelinePreferred } from "../../../../data/assist_pipeline";
import { cloudLogin, removeCloudData } from "../../../../data/cloud"; import { cloudLogin, removeCloudData } from "../../../../data/cloud";
import { import {
showAlertDialog, showAlertDialog,
@ -21,8 +24,6 @@ import "../../../../layouts/hass-subpage";
import { haStyle } from "../../../../resources/styles"; import { haStyle } from "../../../../resources/styles";
import { HomeAssistant } from "../../../../types"; import { HomeAssistant } from "../../../../types";
import "../../ha-config-section"; import "../../ha-config-section";
import { setAssistPipelinePreferred } from "../../../../data/assist_pipeline";
import "../../../../components/ha-password-field";
@customElement("cloud-login") @customElement("cloud-login")
export class CloudLogin extends LitElement { export class CloudLogin extends LitElement {
@ -44,7 +45,7 @@ export class CloudLogin extends LitElement {
@query("#email", true) private _emailField!: HaTextField; @query("#email", true) private _emailField!: HaTextField;
@query("#password", true) private _passwordField!: HaTextField; @query("#password", true) private _passwordField!: HaPasswordField;
protected render(): TemplateResult { protected render(): TemplateResult {
return html` return html`

View File

@ -37,6 +37,7 @@ export const DEFAULT_CONFIG: Partial<EntityHeadingBadgeConfig> = {
const entityConfigStruct = object({ const entityConfigStruct = object({
type: optional(string()), type: optional(string()),
entity: string(), entity: string(),
name: optional(string()),
icon: optional(string()), icon: optional(string()),
state_content: optional(union([string(), array(string())])), state_content: optional(union([string(), array(string())])),
show_state: optional(boolean()), show_state: optional(boolean()),
@ -86,6 +87,12 @@ export class HuiHeadingEntityEditor
name: "", name: "",
type: "grid", type: "grid",
schema: [ schema: [
{
name: "name",
selector: {
text: {},
},
},
{ {
name: "icon", name: "icon",
selector: { icon: {} }, selector: { icon: {} },
@ -128,7 +135,7 @@ export class HuiHeadingEntityEditor
}, },
{ {
name: "state_content", name: "state_content",
selector: { ui_state_content: {} }, selector: { ui_state_content: { allow_name: true } },
context: { filter_entity: "entity" }, context: { filter_entity: "entity" },
}, },
], ],
@ -269,6 +276,10 @@ export class HuiHeadingEntityEditor
return this.hass!.localize( return this.hass!.localize(
`ui.panel.lovelace.editor.card.heading.entity_config.${schema.name}_helper` `ui.panel.lovelace.editor.card.heading.entity_config.${schema.name}_helper`
); );
case "name":
return this.hass!.localize(
`ui.panel.lovelace.editor.card.heading.entity_config.name_helper`
);
default: default:
return undefined; return undefined;
} }

View File

@ -125,12 +125,15 @@ export class HuiEntityHeadingBadge
"--icon-color": color, "--icon-color": color,
}; };
const name = config.name || stateObj.attributes.friendly_name;
return html` return html`
<ha-heading-badge <ha-heading-badge
.type=${hasAction(config.tap_action) ? "button" : "text"} .type=${hasAction(config.tap_action) ? "button" : "text"}
@action=${this._handleAction} @action=${this._handleAction}
.actionHandler=${actionHandler()} .actionHandler=${actionHandler()}
style=${styleMap(style)} style=${styleMap(style)}
.title=${name}
> >
${config.show_icon ${config.show_icon
? html` ? html`
@ -148,6 +151,8 @@ export class HuiEntityHeadingBadge
.hass=${this.hass} .hass=${this.hass}
.stateObj=${stateObj} .stateObj=${stateObj}
.content=${config.state_content} .content=${config.state_content}
.name=${config.name}
dash-unavailable
></state-display> ></state-display>
` `
: nothing} : nothing}

View File

@ -16,6 +16,7 @@ export interface ErrorBadgeConfig extends LovelaceHeadingBadgeConfig {
export interface EntityHeadingBadgeConfig extends LovelaceHeadingBadgeConfig { export interface EntityHeadingBadgeConfig extends LovelaceHeadingBadgeConfig {
type?: "entity"; type?: "entity";
entity: string; entity: string;
name?: string;
state_content?: string | string[]; state_content?: string | string[];
icon?: string; icon?: string;
show_state?: boolean; show_state?: boolean;

View File

@ -57,6 +57,9 @@ class StateDisplay extends LitElement {
@property({ attribute: false }) public name?: string; @property({ attribute: false }) public name?: string;
@property({ type: Boolean, attribute: "dash-unavailable" })
public dashUnavailable?: boolean;
protected createRenderRoot() { protected createRenderRoot() {
return this; return this;
} }
@ -73,6 +76,9 @@ class StateDisplay extends LitElement {
const domain = computeStateDomain(stateObj); const domain = computeStateDomain(stateObj);
if (content === "state") { if (content === "state") {
if (this.dashUnavailable && isUnavailableState(stateObj.state)) {
return "—";
}
if ( if (
(stateObj.attributes.device_class === SENSOR_DEVICE_CLASS_TIMESTAMP || (stateObj.attributes.device_class === SENSOR_DEVICE_CLASS_TIMESTAMP ||
TIMESTAMP_STATE_DOMAINS.includes(domain)) && TIMESTAMP_STATE_DOMAINS.includes(domain)) &&

View File

@ -6026,6 +6026,8 @@
"entity_config": { "entity_config": {
"color": "[%key:ui::panel::lovelace::editor::card::tile::color%]", "color": "[%key:ui::panel::lovelace::editor::card::tile::color%]",
"color_helper": "[%key:ui::panel::lovelace::editor::card::tile::color_helper%]", "color_helper": "[%key:ui::panel::lovelace::editor::card::tile::color_helper%]",
"name": "[%key:ui::panel::lovelace::editor::card::generic::name%]",
"name_helper": "Visible if selected in state content",
"visibility": "Visibility", "visibility": "Visibility",
"visibility_explanation": "The entity will be shown when ALL conditions below are fulfilled. If no conditions are set, the entity will always be shown.", "visibility_explanation": "The entity will be shown when ALL conditions below are fulfilled. If no conditions are set, the entity will always be shown.",
"appearance": "Appearance", "appearance": "Appearance",

View File

@ -67,6 +67,9 @@
"fr": { "fr": {
"nativeName": "Français" "nativeName": "Français"
}, },
"ga": {
"nativeName": "Gaeilge"
},
"gl": { "gl": {
"nativeName": "Galego" "nativeName": "Galego"
}, },

View File

@ -1511,14 +1511,14 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"@codemirror/view@npm:6.33.0, @codemirror/view@npm:^6.0.0, @codemirror/view@npm:^6.17.0, @codemirror/view@npm:^6.23.0, @codemirror/view@npm:^6.27.0": "@codemirror/view@npm:6.34.0, @codemirror/view@npm:^6.0.0, @codemirror/view@npm:^6.17.0, @codemirror/view@npm:^6.23.0, @codemirror/view@npm:^6.27.0":
version: 6.33.0 version: 6.34.0
resolution: "@codemirror/view@npm:6.33.0" resolution: "@codemirror/view@npm:6.34.0"
dependencies: dependencies:
"@codemirror/state": "npm:^6.4.0" "@codemirror/state": "npm:^6.4.0"
style-mod: "npm:^4.1.0" style-mod: "npm:^4.1.0"
w3c-keyname: "npm:^2.2.4" w3c-keyname: "npm:^2.2.4"
checksum: 10/240f1b5ed6ddbc928b220e241e7c67d2f8aaa04af337729cd80ea435c84fca02fe4136d2d4750a978d39c20e56f5ce332e6af2620c2e72d7bede35eebbf9e8ee checksum: 10/df790659d229b2bd5867d8d424c7d911bf4800e893cf71cf1caf03797a70a1af561a05ce81a03f2e326320eb0a16db078a5ba4af2f89d790b578de94ea83f6ea
languageName: node languageName: node
linkType: hard linkType: hard
@ -8908,7 +8908,7 @@ __metadata:
"@codemirror/legacy-modes": "npm:6.4.1" "@codemirror/legacy-modes": "npm:6.4.1"
"@codemirror/search": "npm:6.5.6" "@codemirror/search": "npm:6.5.6"
"@codemirror/state": "npm:6.4.1" "@codemirror/state": "npm:6.4.1"
"@codemirror/view": "npm:6.33.0" "@codemirror/view": "npm:6.34.0"
"@egjs/hammerjs": "npm:2.0.17" "@egjs/hammerjs": "npm:2.0.17"
"@formatjs/intl-datetimeformat": "npm:6.12.5" "@formatjs/intl-datetimeformat": "npm:6.12.5"
"@formatjs/intl-displaynames": "npm:6.6.8" "@formatjs/intl-displaynames": "npm:6.6.8"
@ -9074,7 +9074,7 @@ __metadata:
qr-scanner: "npm:1.4.2" qr-scanner: "npm:1.4.2"
qrcode: "npm:1.5.4" qrcode: "npm:1.5.4"
roboto-fontface: "npm:0.10.0" roboto-fontface: "npm:0.10.0"
rollup: "npm:2.79.1" rollup: "npm:2.79.2"
rollup-plugin-string: "npm:3.0.0" rollup-plugin-string: "npm:3.0.0"
rollup-plugin-terser: "npm:7.0.2" rollup-plugin-terser: "npm:7.0.2"
rollup-plugin-visualizer: "npm:5.12.0" rollup-plugin-visualizer: "npm:5.12.0"
@ -9099,7 +9099,7 @@ __metadata:
vis-network: "npm:9.1.9" vis-network: "npm:9.1.9"
vue: "npm:2.7.16" vue: "npm:2.7.16"
vue2-daterange-picker: "npm:0.6.8" vue2-daterange-picker: "npm:0.6.8"
webpack: "npm:5.94.0" webpack: "npm:5.95.0"
webpack-cli: "npm:5.1.4" webpack-cli: "npm:5.1.4"
webpack-dev-server: "npm:5.1.0" webpack-dev-server: "npm:5.1.0"
webpack-manifest-plugin: "npm:5.0.0" webpack-manifest-plugin: "npm:5.0.0"
@ -12750,9 +12750,9 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"rollup@npm:2.79.1, rollup@npm:^2.43.1, rollup@npm:^2.67.0": "rollup@npm:2.79.2, rollup@npm:^2.43.1, rollup@npm:^2.67.0":
version: 2.79.1 version: 2.79.2
resolution: "rollup@npm:2.79.1" resolution: "rollup@npm:2.79.2"
dependencies: dependencies:
fsevents: "npm:~2.3.2" fsevents: "npm:~2.3.2"
dependenciesMeta: dependenciesMeta:
@ -12760,7 +12760,7 @@ __metadata:
optional: true optional: true
bin: bin:
rollup: dist/bin/rollup rollup: dist/bin/rollup
checksum: 10/df087b701304432f30922bbee5f534ab189aa6938bd383b5686c03147e0d00cd1789ea10a462361326ce6b6ebe448ce272ad3f3cc40b82eeb3157df12f33663c checksum: 10/095ba0a82811b1866a76d826987743278db0a87c45092656986bfff490326b66187d5f9ff0c24cf8d5682bc470aa00c36654e0044d6b6335ac0c1201b8280880
languageName: node languageName: node
linkType: hard linkType: hard
@ -14902,9 +14902,9 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"webpack@npm:5.94.0": "webpack@npm:5.95.0":
version: 5.94.0 version: 5.95.0
resolution: "webpack@npm:5.94.0" resolution: "webpack@npm:5.95.0"
dependencies: dependencies:
"@types/estree": "npm:^1.0.5" "@types/estree": "npm:^1.0.5"
"@webassemblyjs/ast": "npm:^1.12.1" "@webassemblyjs/ast": "npm:^1.12.1"
@ -14934,7 +14934,7 @@ __metadata:
optional: true optional: true
bin: bin:
webpack: bin/webpack.js webpack: bin/webpack.js
checksum: 10/648449c5fbbb0839814116e3b2b044ac6c75a7ba272435155ddeb1e64dfaa2f8079be3adfbb691f648b69900756ce0f6fb73beab0ced3cf5e0fd46868b4593a6 checksum: 10/0377ad3a550b041f26237c96fb55754625b0ce6bae83c1c2447e3262ad056b0b0ad770dcbb92b59f188e9a2bd56155ce910add17dcf023cfbe78bdec774380c1
languageName: node languageName: node
linkType: hard linkType: hard