Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ All notable changes to this project will be documented in this file.

**Fixed:**
- Templates in the row's own `tap_action` / `hold_action` / `double_tap_action` (e.g. a templated `navigation_path`) were passed raw to Home Assistant when tapping the row's icon or name, so navigation went to the literal Jinja. Only the main state value and additional entities resolved them (#460)
- `hide_unavailable` with an `attribute` now also hides when the attribute is `null`, the way integrations report "not set" - it showed as Unknown (or blank with a timestamp `format`) instead of hiding (#452)

## 4.12.0

Expand Down
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -247,6 +247,8 @@ For example, only show the alarm exit-state sensor while the alarm is armed:

`hide_if` and `hide_unavailable` at the top level hide the main entity's state value (the row itself stays visible); `default` is shown in its place when set.

With an `attribute` set, `hide_unavailable` also hides when that attribute is missing or `null` (which HA shows as Unknown); an empty list or string still shows.

### Templating

Display options accept Jinja **templates**, rendered by Home Assistant server-side and updated live whenever the entities they reference change. Any supported option whose value contains `{{ }}` or `{% %}` is treated as a template: `name`, `icon`, `icon_color`, `color`, `secondary_info` text, `hide_if`, a `template` option that replaces the displayed value entirely, any `styles` value, and any value inside `tap_action`/`hold_action`/`double_tap_action`. The `entity` variable holds the owning entity's id, and `vars` lets you name values reused across a row.
Expand Down
17 changes: 17 additions & 0 deletions src/index.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -898,6 +898,23 @@ describe('multiple-entity-row', () => {
expect(row.config.secondary_info).toBeUndefined();
});

// The #452 follow-up: a null attribute rendered "Open: Unknown" instead of hiding.
it('hides an object-form secondary_info whose attribute is null', async () => {
el.setConfig({
entity: 'binary_sensor.windows',
secondary_info: { attribute: 'open_windows', name: 'Open:', hide_unavailable: true },
});
el.hass = buildHass({
'binary_sensor.windows': {
entity_id: 'binary_sensor.windows',
state: 'off',
attributes: { open_windows: null },
},
});
await flushRender(el);
expect(el.shadowRoot.querySelector('hui-generic-entity-row').secondaryText).toBeFalsy();
});

// Generic keywords are the one secondary_info HA renders natively - those must keep
// passing through, with no secondaryText override.
it('passes a generic secondary_info keyword through to the row config', async () => {
Expand Down
4 changes: 3 additions & 1 deletion src/util.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,14 @@ export const fireEvent = (node, type, detail) => {

export const isUnavailable = (stateObj) => !stateObj || UNAVAILABLE_STATES.includes(stateObj.state);

// A null attribute counts as missing: integrations report "not set" that way, and HA displays it
// as Unknown (#452). An empty list or string is a real value and stays visible.
export const hideUnavailable = (stateObj, config) =>
config.hide_unavailable &&
(isUnavailable(stateObj) ||
(config.attribute &&
![LAST_CHANGED, LAST_UPDATED].includes(config.attribute) &&
stateObj.attributes[config.attribute] === undefined));
stateObj.attributes[config.attribute] == null));

export const hideIf = (stateObj, config, hass) => {
if (hideUnavailable(stateObj, config)) {
Expand Down
11 changes: 11 additions & 0 deletions src/util.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,17 @@ describe('hideUnavailable', () => {
const stateObj = { state: 'on', attributes: { brightness: 100 } };
expect(hideUnavailable(stateObj, { hide_unavailable: true, attribute: 'brightness' })).toBe(false);
});

// #452: integrations report an unset attribute as null, which HA displays as Unknown.
it('is true when the configured attribute is null', () => {
const stateObj = { state: 'off', attributes: { open_windows: null } };
expect(hideUnavailable(stateObj, { hide_unavailable: true, attribute: 'open_windows' })).toBe(true);
});

it.each([[[]], [''], [0], [false]])('is false for the present but empty-ish attribute %j', (value) => {
const stateObj = { state: 'off', attributes: { open_windows: value } };
expect(hideUnavailable(stateObj, { hide_unavailable: true, attribute: 'open_windows' })).toBe(false);
});
});

describe('hideIf', () => {
Expand Down
Loading