diff --git a/.github/workflows/cast_deployment.yaml b/.github/workflows/cast_deployment.yaml index e55bbd8526d3..d28ec61287e5 100644 --- a/.github/workflows/cast_deployment.yaml +++ b/.github/workflows/cast_deployment.yaml @@ -21,7 +21,7 @@ jobs: url: ${{ steps.deploy.outputs.NETLIFY_LIVE_URL || steps.deploy.outputs.NETLIFY_URL }} steps: - name: Check out files from GitHub - uses: actions/checkout@v4.1.7 + uses: actions/checkout@v4.2.0 with: ref: dev @@ -57,7 +57,7 @@ jobs: url: ${{ steps.deploy.outputs.NETLIFY_LIVE_URL || steps.deploy.outputs.NETLIFY_URL }} steps: - name: Check out files from GitHub - uses: actions/checkout@v4.1.7 + uses: actions/checkout@v4.2.0 with: ref: master diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index bd2a90360400..07ddb41ee93c 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -24,7 +24,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Check out files from GitHub - uses: actions/checkout@v4.1.7 + uses: actions/checkout@v4.2.0 - name: Setup Node uses: actions/setup-node@v4.0.4 with: @@ -58,7 +58,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Check out files from GitHub - uses: actions/checkout@v4.1.7 + uses: actions/checkout@v4.2.0 - name: Setup Node uses: actions/setup-node@v4.0.4 with: @@ -76,7 +76,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Check out files from GitHub - uses: actions/checkout@v4.1.7 + uses: actions/checkout@v4.2.0 - name: Setup Node uses: actions/setup-node@v4.0.4 with: @@ -100,7 +100,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Check out files from GitHub - uses: actions/checkout@v4.1.7 + uses: actions/checkout@v4.2.0 - name: Setup Node uses: actions/setup-node@v4.0.4 with: diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index 4648c3aa1144..58358a653963 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -23,7 +23,7 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@v4.1.7 + uses: actions/checkout@v4.2.0 with: # We must fetch at least the immediate parents so that if this is # a pull request then we can checkout the head. diff --git a/.github/workflows/demo_deployment.yaml b/.github/workflows/demo_deployment.yaml index 4a1e65ba893e..d28e877b2136 100644 --- a/.github/workflows/demo_deployment.yaml +++ b/.github/workflows/demo_deployment.yaml @@ -22,7 +22,7 @@ jobs: url: ${{ steps.deploy.outputs.NETLIFY_LIVE_URL || steps.deploy.outputs.NETLIFY_URL }} steps: - name: Check out files from GitHub - uses: actions/checkout@v4.1.7 + uses: actions/checkout@v4.2.0 with: ref: dev @@ -58,7 +58,7 @@ jobs: url: ${{ steps.deploy.outputs.NETLIFY_LIVE_URL || steps.deploy.outputs.NETLIFY_URL }} steps: - name: Check out files from GitHub - uses: actions/checkout@v4.1.7 + uses: actions/checkout@v4.2.0 with: ref: master diff --git a/.github/workflows/design_deployment.yaml b/.github/workflows/design_deployment.yaml index 7904c7269ae3..e172408c2225 100644 --- a/.github/workflows/design_deployment.yaml +++ b/.github/workflows/design_deployment.yaml @@ -16,7 +16,7 @@ jobs: url: ${{ steps.deploy.outputs.NETLIFY_LIVE_URL || steps.deploy.outputs.NETLIFY_URL }} steps: - name: Check out files from GitHub - uses: actions/checkout@v4.1.7 + uses: actions/checkout@v4.2.0 - name: Setup Node uses: actions/setup-node@v4.0.4 diff --git a/.github/workflows/design_preview.yaml b/.github/workflows/design_preview.yaml index 79c18b066e4a..bfd8cdaabd27 100644 --- a/.github/workflows/design_preview.yaml +++ b/.github/workflows/design_preview.yaml @@ -21,7 +21,7 @@ jobs: if: github.repository == 'home-assistant/frontend' && contains(github.event.pull_request.labels.*.name, 'needs design preview') steps: - name: Check out files from GitHub - uses: actions/checkout@v4.1.7 + uses: actions/checkout@v4.2.0 - name: Setup Node uses: actions/setup-node@v4.0.4 diff --git a/.github/workflows/nightly.yaml b/.github/workflows/nightly.yaml index f6ef1bbabd68..ad7b51088737 100644 --- a/.github/workflows/nightly.yaml +++ b/.github/workflows/nightly.yaml @@ -20,7 +20,7 @@ jobs: contents: write steps: - name: Checkout the repository - uses: actions/checkout@v4.1.7 + uses: actions/checkout@v4.2.0 - name: Set up Python ${{ env.PYTHON_VERSION }} uses: actions/setup-python@v5 diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index 6370fac929c5..1e258cf56a22 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -23,7 +23,7 @@ jobs: contents: write # Required to upload release assets steps: - name: Checkout the repository - uses: actions/checkout@v4.1.7 + uses: actions/checkout@v4.2.0 - name: Verify version uses: home-assistant/actions/helpers/verify-version@master diff --git a/.github/workflows/translations.yaml b/.github/workflows/translations.yaml index c7b15fe7db4c..c76a1d4c74d8 100644 --- a/.github/workflows/translations.yaml +++ b/.github/workflows/translations.yaml @@ -13,7 +13,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout the repository - uses: actions/checkout@v4.1.7 + uses: actions/checkout@v4.2.0 - name: Upload Translations run: | diff --git a/README.md b/README.md index 685dddba0914..0e6f470a017b 100644 --- a/README.md +++ b/README.md @@ -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. 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/) diff --git a/gallery/src/pages/automation/describe-action.ts b/gallery/src/pages/automation/describe-action.ts index 39544cc7f2e4..9e23939871d0 100644 --- a/gallery/src/pages/automation/describe-action.ts +++ b/gallery/src/pages/automation/describe-action.ts @@ -142,7 +142,7 @@ export class DemoAutomationDescribeAction extends LitElement {
${this._action - ? describeAction(this.hass, [], [], [], this._action) + ? describeAction(this.hass, [], [], this._action) : ""} html`
- ${describeAction(this.hass, [], [], [], conf as any)} + ${describeAction(this.hass, [], [], conf as any)}
${dump(conf)}
` diff --git a/package.json b/package.json index 9f8b3cf1c65e..89b5eaef59d4 100644 --- a/package.json +++ b/package.json @@ -33,7 +33,7 @@ "@codemirror/legacy-modes": "6.4.1", "@codemirror/search": "6.5.6", "@codemirror/state": "6.4.1", - "@codemirror/view": "6.33.0", + "@codemirror/view": "6.34.0", "@egjs/hammerjs": "2.0.17", "@formatjs/intl-datetimeformat": "6.12.5", "@formatjs/intl-displaynames": "6.6.8", @@ -229,7 +229,7 @@ "open": "10.1.0", "pinst": "3.0.0", "prettier": "3.3.3", - "rollup": "2.79.1", + "rollup": "2.79.2", "rollup-plugin-string": "3.0.0", "rollup-plugin-terser": "7.0.2", "rollup-plugin-visualizer": "5.12.0", @@ -241,7 +241,7 @@ "transform-async-modules-webpack-plugin": "1.1.1", "ts-lit-plugin": "2.0.2", "typescript": "5.6.2", - "webpack": "5.94.0", + "webpack": "5.95.0", "webpack-cli": "5.1.4", "webpack-dev-server": "5.1.0", "webpack-manifest-plugin": "5.0.0", diff --git a/pyproject.toml b/pyproject.toml index 4d844997a4e2..8c28ad2712ce 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta" [project] name = "home-assistant-frontend" -version = "20240927.0" +version = "20240930.0" license = {text = "Apache-2.0"} description = "The Home Assistant frontend" readme = "README.md" diff --git a/src/common/color/colors.ts b/src/common/color/colors.ts index a7f246e31e8a..a661562eadbe 100644 --- a/src/common/color/colors.ts +++ b/src/common/color/colors.ts @@ -1,36 +1,36 @@ import { theme2hex } from "./convert-color"; export const COLORS = [ - "#44739e", - "#984ea3", - "#00d2d5", - "#ff7f00", - "#af8d00", - "#7f80cd", - "#b3e900", - "#c42e60", - "#a65628", - "#f781bf", - "#8dd3c7", - "#bebada", - "#fb8072", - "#80b1d3", - "#fdb462", - "#fccde5", - "#bc80bd", - "#ffed6f", - "#c4eaff", - "#cf8c00", - "#1b9e77", - "#d95f02", - "#e7298a", - "#e6ab02", - "#a6761d", - "#0097ff", - "#00d067", - "#f43600", - "#4ba93b", - "#5779bb", + "#4269d0", + "#f4bd4a", + "#ff725c", + "#6cc5b0", + "#a463f2", + "#ff8ab7", + "#9c6b4e", + "#97bbf5", + "#01ab63", + "#9498a0", + "#094bad", + "#c99000", + "#d84f3e", + "#49a28f", + "#048732", + "#d96895", + "#8043ce", + "#7599d1", + "#7a4c31", + "#74787f", + "#6989f4", + "#ffd444", + "#ff957c", + "#8fe9d3", + "#62cc71", + "#ffadda", + "#c884ff", + "#badeff", + "#bf8b6d", + "#b6bac2", "#927acc", "#97ee3f", "#bf3947", diff --git a/src/components/data-table/ha-data-table.ts b/src/components/data-table/ha-data-table.ts index 77550488c923..e0ab768d5b34 100644 --- a/src/components/data-table/ha-data-table.ts +++ b/src/components/data-table/ha-data-table.ts @@ -1011,6 +1011,7 @@ export class HaDataTable extends LitElement { /* @noflip */ padding-inline-end: initial; width: 60px; + min-width: 60px; } .mdc-data-table__table { diff --git a/src/components/ha-password-field.ts b/src/components/ha-password-field.ts index 86127030533f..d97c23c4de6f 100644 --- a/src/components/ha-password-field.ts +++ b/src/components/ha-password-field.ts @@ -1,10 +1,17 @@ import { TextAreaCharCounter } from "@material/mwc-textfield/mwc-textfield-base"; import { mdiEye, mdiEyeOff } from "@mdi/js"; 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 "./ha-icon-button"; import "./ha-textfield"; +import type { HaTextField } from "./ha-textfield"; @customElement("ha-password-field") export class HaPasswordField extends LitElement { @@ -75,6 +82,8 @@ export class HaPasswordField extends LitElement { @state() private _unmaskedPassword = false; + @query("ha-textfield") private _textField!: HaTextField; + protected render() { return html``; } + 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 { + return this._textField.layout(); + } + private _toggleUnmaskedPassword(): void { this._unmaskedPassword = !this._unmaskedPassword; } diff --git a/src/components/ha-service-control.ts b/src/components/ha-service-control.ts index 481160fd786a..6be50e0191d1 100644 --- a/src/components/ha-service-control.ts +++ b/src/components/ha-service-control.ts @@ -805,7 +805,8 @@ export class HaServiceControl extends LitElement { const value = ev.detail.value; if ( this._value?.data?.[key] === value || - (!this._value?.data?.[key] && (value === "" || value === undefined)) + ((!this._value?.data || !(key in this._value.data)) && + (value === "" || value === undefined)) ) { return; } diff --git a/src/components/ha-yaml-editor.ts b/src/components/ha-yaml-editor.ts index 1eb94c0aeab9..4782b4463702 100644 --- a/src/components/ha-yaml-editor.ts +++ b/src/components/ha-yaml-editor.ts @@ -18,7 +18,7 @@ import type { HaCodeEditor } from "./ha-code-editor"; import "./ha-button"; const isEmpty = (obj: Record): boolean => { - if (typeof obj !== "object") { + if (typeof obj !== "object" || obj === null) { return false; } for (const key in obj) { @@ -59,14 +59,13 @@ export class HaYamlEditor extends LitElement { public setValue(value): void { try { - this._yaml = - value && !isEmpty(value) - ? dump(value, { - schema: this.yamlSchema, - quotingType: '"', - noRefs: true, - }) - : ""; + this._yaml = !isEmpty(value) + ? dump(value, { + schema: this.yamlSchema, + quotingType: '"', + noRefs: true, + }) + : ""; } catch (err: any) { // eslint-disable-next-line no-console console.error(err, value); @@ -75,7 +74,7 @@ export class HaYamlEditor extends LitElement { } protected firstUpdated(): void { - if (this.defaultValue) { + if (this.defaultValue !== undefined) { this.setValue(this.defaultValue); } } diff --git a/src/components/trace/hat-trace-timeline.ts b/src/components/trace/hat-trace-timeline.ts index e6be959c9234..8cd67a2f4197 100644 --- a/src/components/trace/hat-trace-timeline.ts +++ b/src/components/trace/hat-trace-timeline.ts @@ -22,13 +22,8 @@ import { formatDateTimeWithSeconds } from "../../common/datetime/format_date_tim import { relativeTime } from "../../common/datetime/relative_time"; import { fireEvent } from "../../common/dom/fire_event"; import { toggleAttribute } from "../../common/dom/toggle_attribute"; -import { - floorsContext, - fullEntitiesContext, - labelsContext, -} from "../../data/context"; +import { fullEntitiesContext, labelsContext } from "../../data/context"; import { EntityRegistryEntry } from "../../data/entity_registry"; -import { FloorRegistryEntry } from "../../data/floor_registry"; import { LabelRegistryEntry } from "../../data/label_registry"; import { LogbookEntry } from "../../data/logbook"; import { @@ -206,7 +201,6 @@ class ActionRenderer { private hass: HomeAssistant, private entityReg: EntityRegistryEntry[], private labelReg: LabelRegistryEntry[], - private floorReg: FloorRegistryEntry[], private entries: TemplateResult[], private trace: AutomationTraceExtended, private logbookRenderer: LogbookRenderer, @@ -325,7 +319,6 @@ class ActionRenderer { this.hass, this.entityReg, this.labelReg, - this.floorReg, data, actionType ), @@ -493,13 +486,7 @@ class ActionRenderer { const name = repeatConfig.alias || - describeAction( - this.hass, - this.entityReg, - this.labelReg, - this.floorReg, - repeatConfig - ); + describeAction(this.hass, this.entityReg, this.labelReg, repeatConfig); this._renderEntry(repeatPath, name, undefined, disabled); @@ -597,7 +584,6 @@ class ActionRenderer { this.hass, this.entityReg, this.labelReg, - this.floorReg, sequenceConfig, "sequence" ), @@ -694,10 +680,6 @@ export class HaAutomationTracer extends LitElement { @consume({ context: labelsContext, subscribe: true }) _labelReg!: LabelRegistryEntry[]; - @state() - @consume({ context: floorsContext, subscribe: true }) - _floorReg!: FloorRegistryEntry[]; - protected render() { if (!this.trace) { return nothing; @@ -715,7 +697,6 @@ export class HaAutomationTracer extends LitElement { this.hass, this._entityReg, this._labelReg, - this._floorReg, entries, this.trace, logbookRenderer, diff --git a/src/data/context.ts b/src/data/context.ts index 75ebe5ae3d4f..35134384b8e2 100644 --- a/src/data/context.ts +++ b/src/data/context.ts @@ -2,7 +2,6 @@ import { createContext } from "@lit-labs/context"; import { HassConfig } from "home-assistant-js-websocket"; import { HomeAssistant } from "../types"; import { EntityRegistryEntry } from "./entity_registry"; -import { FloorRegistryEntry } from "./floor_registry"; import { LabelRegistryEntry } from "./label_registry"; export const connectionContext = @@ -28,6 +27,4 @@ export const panelsContext = createContext("panels"); export const fullEntitiesContext = createContext("extendedEntities"); -export const floorsContext = createContext("floors"); - export const labelsContext = createContext("labels"); diff --git a/src/data/script_i18n.ts b/src/data/script_i18n.ts index b623aba7dba5..75928b4bbeef 100644 --- a/src/data/script_i18n.ts +++ b/src/data/script_i18n.ts @@ -14,7 +14,6 @@ import { computeEntityRegistryName, entityRegistryById, } from "./entity_registry"; -import { FloorRegistryEntry } from "./floor_registry"; import { domainToName } from "./integration"; import { LabelRegistryEntry } from "./label_registry"; import { @@ -44,7 +43,6 @@ export const describeAction = ( hass: HomeAssistant, entityRegistry: EntityRegistryEntry[], labelRegistry: LabelRegistryEntry[], - floorRegistry: FloorRegistryEntry[], action: ActionTypes[T], actionType?: T, ignoreAlias = false @@ -54,7 +52,6 @@ export const describeAction = ( hass, entityRegistry, labelRegistry, - floorRegistry, action, actionType, ignoreAlias @@ -78,7 +75,6 @@ const tryDescribeAction = ( hass: HomeAssistant, entityRegistry: EntityRegistryEntry[], labelRegistry: LabelRegistryEntry[], - floorRegistry: FloorRegistryEntry[], action: ActionTypes[T], actionType?: T, ignoreAlias = false @@ -168,9 +164,7 @@ const tryDescribeAction = ( ); } } else if (key === "floor_id") { - const floor = floorRegistry.find( - (flr) => flr.floor_id === targetThing - ); + const floor = hass.floors[targetThing] ?? undefined; if (floor?.name) { targets.push(floor.name); } else { diff --git a/src/dialogs/voice-assistant-setup/voice-assistant-setup-step-pipeline.ts b/src/dialogs/voice-assistant-setup/voice-assistant-setup-step-pipeline.ts index 0f69ce002a4d..c98910235f3f 100644 --- a/src/dialogs/voice-assistant-setup/voice-assistant-setup-step-pipeline.ts +++ b/src/dialogs/voice-assistant-setup/voice-assistant-setup-step-pipeline.ts @@ -144,7 +144,7 @@ export class HaVoiceAssistantSetupStepPipeline extends LitElement { { option: "preferred" }, { entity_id: this.assistConfiguration?.pipeline_entity_id } ); - this._nextStep(STEP.SUCCESS); + fireEvent(this, "next-step", { step: STEP.SUCCESS, noPrevious: true }); return; } } @@ -210,15 +210,15 @@ export class HaVoiceAssistantSetupStepPipeline extends LitElement { { option: cloudPipeline.name }, { entity_id: this.assistConfiguration?.pipeline_entity_id } ); - this._nextStep(STEP.SUCCESS); + fireEvent(this, "next-step", { step: STEP.SUCCESS, noPrevious: true }); } private async _setupCloud() { - fireEvent(this, "next-step", { step: STEP.CLOUD }); + this._nextStep(STEP.CLOUD); } private async _thisSystem() { - fireEvent(this, "next-step", { step: STEP.ADDONS }); + this._nextStep(STEP.ADDONS); } private _skip() { diff --git a/src/dialogs/voice-assistant-setup/voice-assistant-setup-step-success.ts b/src/dialogs/voice-assistant-setup/voice-assistant-setup-step-success.ts index 1e2d264f6712..d4336e4cb804 100644 --- a/src/dialogs/voice-assistant-setup/voice-assistant-setup-step-success.ts +++ b/src/dialogs/voice-assistant-setup/voice-assistant-setup-step-success.ts @@ -14,6 +14,7 @@ import { import { assistSatelliteAnnounce, AssistSatelliteConfiguration, + setWakeWords, } from "../../data/assist_satellite"; import { fetchCloudStatus } from "../../data/cloud"; 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 { AssistantSetupStyles } from "./styles"; 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") export class HaVoiceAssistantSetupStepSuccess extends LitElement { @@ -58,7 +61,9 @@ export class HaVoiceAssistantSetupStepSuccess extends LitElement { protected override render() { const pipelineEntity = this.assistConfiguration - ? this.hass.states[this.assistConfiguration.pipeline_entity_id] + ? (this.hass.states[ + this.assistConfiguration.pipeline_entity_id + ] as InputSelectEntity) : undefined; return html`
@@ -69,46 +74,53 @@ export class HaVoiceAssistantSetupStepSuccess extends LitElement { settings, you can change that below.

-
- - ${this.assistConfiguration?.available_wake_words.map( - (wakeword) => - html` - ${wakeword.wake_word} - ` - )} - - - - Test - -
-
- - ${pipelineEntity?.attributes.options.map( - (pipeline) => - html` - ${this.hass.formatEntityState(pipelineEntity, pipeline)} - ` - )} - - - - Edit - -
+ ${this.assistConfiguration && + this.assistConfiguration.available_wake_words.length > 1 + ? html`
+ + ${this.assistConfiguration.available_wake_words.map( + (wakeword) => + html` + ${wakeword.wake_word} + ` + )} + + + + Test + +
` + : nothing} + ${pipelineEntity + ? html`
+ + ${pipelineEntity?.attributes.options.map( + (pipeline) => + html` + ${this.hass.formatEntityState(pipelineEntity, pipeline)} + ` + )} + + + + Edit + +
` + : nothing} ${this._ttsSettings ? html`
= { const entityConfigStruct = object({ type: optional(string()), entity: string(), + name: optional(string()), icon: optional(string()), state_content: optional(union([string(), array(string())])), show_state: optional(boolean()), @@ -86,6 +87,12 @@ export class HuiHeadingEntityEditor name: "", type: "grid", schema: [ + { + name: "name", + selector: { + text: {}, + }, + }, { name: "icon", selector: { icon: {} }, @@ -128,7 +135,7 @@ export class HuiHeadingEntityEditor }, { name: "state_content", - selector: { ui_state_content: {} }, + selector: { ui_state_content: { allow_name: true } }, context: { filter_entity: "entity" }, }, ], @@ -269,6 +276,10 @@ export class HuiHeadingEntityEditor return this.hass!.localize( `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: return undefined; } diff --git a/src/panels/lovelace/heading-badges/hui-entity-heading-badge.ts b/src/panels/lovelace/heading-badges/hui-entity-heading-badge.ts index b6084a846dc8..e427d104d9da 100644 --- a/src/panels/lovelace/heading-badges/hui-entity-heading-badge.ts +++ b/src/panels/lovelace/heading-badges/hui-entity-heading-badge.ts @@ -125,12 +125,15 @@ export class HuiEntityHeadingBadge "--icon-color": color, }; + const name = config.name || stateObj.attributes.friendly_name; + return html` ${config.show_icon ? html` @@ -148,6 +151,8 @@ export class HuiEntityHeadingBadge .hass=${this.hass} .stateObj=${stateObj} .content=${config.state_content} + .name=${config.name} + dash-unavailable > ` : nothing} diff --git a/src/panels/lovelace/heading-badges/types.ts b/src/panels/lovelace/heading-badges/types.ts index ac9a4a10cd62..e87ccb1d64f4 100644 --- a/src/panels/lovelace/heading-badges/types.ts +++ b/src/panels/lovelace/heading-badges/types.ts @@ -16,6 +16,7 @@ export interface ErrorBadgeConfig extends LovelaceHeadingBadgeConfig { export interface EntityHeadingBadgeConfig extends LovelaceHeadingBadgeConfig { type?: "entity"; entity: string; + name?: string; state_content?: string | string[]; icon?: string; show_state?: boolean; diff --git a/src/state-display/state-display.ts b/src/state-display/state-display.ts index 26bfdbb5cdfb..a6f12693dd26 100644 --- a/src/state-display/state-display.ts +++ b/src/state-display/state-display.ts @@ -57,6 +57,9 @@ class StateDisplay extends LitElement { @property({ attribute: false }) public name?: string; + @property({ type: Boolean, attribute: "dash-unavailable" }) + public dashUnavailable?: boolean; + protected createRenderRoot() { return this; } @@ -73,6 +76,9 @@ class StateDisplay extends LitElement { const domain = computeStateDomain(stateObj); if (content === "state") { + if (this.dashUnavailable && isUnavailableState(stateObj.state)) { + return "—"; + } if ( (stateObj.attributes.device_class === SENSOR_DEVICE_CLASS_TIMESTAMP || TIMESTAMP_STATE_DOMAINS.includes(domain)) && diff --git a/src/translations/en.json b/src/translations/en.json index 005c8ef5526b..f3a2a622b764 100644 --- a/src/translations/en.json +++ b/src/translations/en.json @@ -6026,6 +6026,8 @@ "entity_config": { "color": "[%key:ui::panel::lovelace::editor::card::tile::color%]", "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_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", diff --git a/src/translations/translationMetadata.json b/src/translations/translationMetadata.json index 33a261a2993a..2fd2e286ebbd 100644 --- a/src/translations/translationMetadata.json +++ b/src/translations/translationMetadata.json @@ -67,6 +67,9 @@ "fr": { "nativeName": "Français" }, + "ga": { + "nativeName": "Gaeilge" + }, "gl": { "nativeName": "Galego" }, diff --git a/yarn.lock b/yarn.lock index e38cfcf1f630..d3be06e91c1e 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1511,14 +1511,14 @@ __metadata: languageName: node 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": - version: 6.33.0 - resolution: "@codemirror/view@npm:6.33.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.34.0 + resolution: "@codemirror/view@npm:6.34.0" dependencies: "@codemirror/state": "npm:^6.4.0" style-mod: "npm:^4.1.0" w3c-keyname: "npm:^2.2.4" - checksum: 10/240f1b5ed6ddbc928b220e241e7c67d2f8aaa04af337729cd80ea435c84fca02fe4136d2d4750a978d39c20e56f5ce332e6af2620c2e72d7bede35eebbf9e8ee + checksum: 10/df790659d229b2bd5867d8d424c7d911bf4800e893cf71cf1caf03797a70a1af561a05ce81a03f2e326320eb0a16db078a5ba4af2f89d790b578de94ea83f6ea languageName: node linkType: hard @@ -8908,7 +8908,7 @@ __metadata: "@codemirror/legacy-modes": "npm:6.4.1" "@codemirror/search": "npm:6.5.6" "@codemirror/state": "npm:6.4.1" - "@codemirror/view": "npm:6.33.0" + "@codemirror/view": "npm:6.34.0" "@egjs/hammerjs": "npm:2.0.17" "@formatjs/intl-datetimeformat": "npm:6.12.5" "@formatjs/intl-displaynames": "npm:6.6.8" @@ -9074,7 +9074,7 @@ __metadata: qr-scanner: "npm:1.4.2" qrcode: "npm:1.5.4" 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-terser: "npm:7.0.2" rollup-plugin-visualizer: "npm:5.12.0" @@ -9099,7 +9099,7 @@ __metadata: vis-network: "npm:9.1.9" vue: "npm:2.7.16" vue2-daterange-picker: "npm:0.6.8" - webpack: "npm:5.94.0" + webpack: "npm:5.95.0" webpack-cli: "npm:5.1.4" webpack-dev-server: "npm:5.1.0" webpack-manifest-plugin: "npm:5.0.0" @@ -12750,9 +12750,9 @@ __metadata: languageName: node linkType: hard -"rollup@npm:2.79.1, rollup@npm:^2.43.1, rollup@npm:^2.67.0": - version: 2.79.1 - resolution: "rollup@npm:2.79.1" +"rollup@npm:2.79.2, rollup@npm:^2.43.1, rollup@npm:^2.67.0": + version: 2.79.2 + resolution: "rollup@npm:2.79.2" dependencies: fsevents: "npm:~2.3.2" dependenciesMeta: @@ -12760,7 +12760,7 @@ __metadata: optional: true bin: rollup: dist/bin/rollup - checksum: 10/df087b701304432f30922bbee5f534ab189aa6938bd383b5686c03147e0d00cd1789ea10a462361326ce6b6ebe448ce272ad3f3cc40b82eeb3157df12f33663c + checksum: 10/095ba0a82811b1866a76d826987743278db0a87c45092656986bfff490326b66187d5f9ff0c24cf8d5682bc470aa00c36654e0044d6b6335ac0c1201b8280880 languageName: node linkType: hard @@ -14902,9 +14902,9 @@ __metadata: languageName: node linkType: hard -"webpack@npm:5.94.0": - version: 5.94.0 - resolution: "webpack@npm:5.94.0" +"webpack@npm:5.95.0": + version: 5.95.0 + resolution: "webpack@npm:5.95.0" dependencies: "@types/estree": "npm:^1.0.5" "@webassemblyjs/ast": "npm:^1.12.1" @@ -14934,7 +14934,7 @@ __metadata: optional: true bin: webpack: bin/webpack.js - checksum: 10/648449c5fbbb0839814116e3b2b044ac6c75a7ba272435155ddeb1e64dfaa2f8079be3adfbb691f648b69900756ce0f6fb73beab0ced3cf5e0fd46868b4593a6 + checksum: 10/0377ad3a550b041f26237c96fb55754625b0ce6bae83c1c2447e3262ad056b0b0ad770dcbb92b59f188e9a2bd56155ce910add17dcf023cfbe78bdec774380c1 languageName: node linkType: hard