1
0
mirror of https://github.com/home-assistant/frontend.git synced 2026-02-15 07:25:54 +00:00

Show also not installable updates on update overview page (#28717)

* add "show not installable option" to update page

* split updates by install feature and show always

* fix

* fix "no update" panel

* use `nothing` instead of empty string

* re-add `outlined` to ha-card

* keep title, use different for not-installable updates
This commit is contained in:
Michael
2026-01-12 12:18:53 +01:00
committed by GitHub
parent 56d71c8e54
commit e0a9f5a08a
5 changed files with 94 additions and 36 deletions

View File

@@ -44,14 +44,27 @@ export const updateUsesProgress = (entity: UpdateEntity): boolean =>
supportsFeature(entity, UpdateEntityFeature.PROGRESS) &&
entity.attributes.update_percentage !== null;
export const updateAvailable = (
entity: UpdateEntity,
showSkipped = false
): boolean =>
entity.state === BINARY_STATE_ON ||
(showSkipped && Boolean(entity.attributes.skipped_version));
export const updateCanInstall = (
entity: UpdateEntity,
showSkipped = false
): boolean =>
(entity.state === BINARY_STATE_ON ||
(showSkipped && Boolean(entity.attributes.skipped_version))) &&
updateAvailable(entity, showSkipped) &&
supportsFeature(entity, UpdateEntityFeature.INSTALL);
export const updateCanNotInstall = (
entity: UpdateEntity,
showSkipped = false
): boolean =>
updateAvailable(entity, showSkipped) &&
!supportsFeature(entity, UpdateEntityFeature.INSTALL);
export const latestVersionIsSkipped = (entity: UpdateEntity): boolean =>
!!(
entity.attributes.latest_version &&
@@ -108,13 +121,17 @@ export const filterUpdateEntities = (
);
});
export const filterUpdateEntitiesWithInstall = (
export const filterUpdateEntitiesParameterized = (
entities: HassEntities,
showSkipped = false
showSkipped = false,
showNotInstallable = false
) =>
filterUpdateEntities(entities).filter((entity) =>
updateCanInstall(entity, showSkipped)
);
filterUpdateEntities(entities).filter((entity) => {
if (showNotInstallable) {
return updateCanNotInstall(entity, showSkipped);
}
return updateCanInstall(entity, showSkipped);
});
export const checkForEntityUpdates = async (
element: HTMLElement,

View File

@@ -2,7 +2,7 @@ import type { RequestSelectedDetail } from "@material/mwc-list/mwc-list-item";
import { mdiDotsVertical, mdiRefresh } from "@mdi/js";
import type { HassEntities } from "home-assistant-js-websocket";
import type { TemplateResult } from "lit";
import { LitElement, css, html } from "lit";
import { LitElement, css, html, nothing } from "lit";
import { customElement, property, state } from "lit/decorators";
import memoizeOne from "memoize-one";
import { isComponentLoaded } from "../../../common/config/is_component_loaded";
@@ -26,7 +26,7 @@ import {
} from "../../../data/hassio/supervisor";
import {
checkForEntityUpdates,
filterUpdateEntitiesWithInstall,
filterUpdateEntitiesParameterized,
} from "../../../data/update";
import { showAlertDialog } from "../../../dialogs/generic/show-dialog-box";
import "../../../layouts/hass-subpage";
@@ -53,7 +53,11 @@ class HaConfigSectionUpdates extends LitElement {
}
protected render(): TemplateResult {
const canInstallUpdates = this._filterUpdateEntitiesWithInstall(
const canInstallUpdates = this._filterInstallableUpdateEntities(
this.hass.states,
this._showSkipped
);
const notInstallableUpdates = this._filterNotInstallableUpdateEntities(
this.hass.states,
this._showSkipped
);
@@ -100,30 +104,49 @@ class HaConfigSectionUpdates extends LitElement {
)}
</ha-list-item>
`
: ""}
: nothing}
</ha-button-menu>
</div>
<div class="content">
<ha-card outlined>
<div class="card-content">
${canInstallUpdates.length
? html`
${canInstallUpdates.length
? html`
<ha-card outlined>
<div class="card-content">
<ha-config-updates
.hass=${this.hass}
.narrow=${this.narrow}
.updateEntities=${canInstallUpdates}
.isInstallable=${true}
showAll
></ha-config-updates>
`
: html`
<div class="no-updates">
${this.hass.localize(
"ui.panel.config.updates.no_updates"
)}
</div>
`}
</div>
</ha-card>
</div>
</ha-card>
`
: nothing}
${notInstallableUpdates.length
? html`
<ha-card outlined>
<div class="card-content">
<ha-config-updates
.hass=${this.hass}
.narrow=${this.narrow}
.updateEntities=${notInstallableUpdates}
.isInstallable=${false}
showAll
></ha-config-updates>
</div>
</ha-card>
`
: nothing}
${canInstallUpdates.length + notInstallableUpdates.length
? nothing
: html`
<ha-card outlined>
<div class="no-updates">
${this.hass.localize("ui.panel.config.updates.no_updates")}
</div>
</ha-card>
`}
</div>
</hass-subpage>
`;
@@ -177,9 +200,14 @@ class HaConfigSectionUpdates extends LitElement {
checkForEntityUpdates(this, this.hass);
}
private _filterUpdateEntitiesWithInstall = memoizeOne(
private _filterInstallableUpdateEntities = memoizeOne(
(entities: HassEntities, showSkipped: boolean) =>
filterUpdateEntitiesWithInstall(entities, showSkipped)
filterUpdateEntitiesParameterized(entities, showSkipped, false)
);
private _filterNotInstallableUpdateEntities = memoizeOne(
(entities: HassEntities, showSkipped: boolean) =>
filterUpdateEntitiesParameterized(entities, showSkipped, true)
);
static styles = css`

View File

@@ -31,7 +31,7 @@ import {
import type { UpdateEntity } from "../../../data/update";
import {
checkForEntityUpdates,
filterUpdateEntitiesWithInstall,
filterUpdateEntitiesParameterized,
} from "../../../data/update";
import {
QuickBarMode,
@@ -206,7 +206,7 @@ class HaConfigDashboard extends SubscribeMixin(LitElement) {
protected render(): TemplateResult {
const { updates: canInstallUpdates, total: totalUpdates } =
this._filterUpdateEntitiesWithInstall(
this._filterUpdateEntitiesParameterized(
this.hass.states,
this.hass.entities
);
@@ -291,6 +291,7 @@ class HaConfigDashboard extends SubscribeMixin(LitElement) {
.narrow=${this.narrow}
.total=${totalUpdates}
.updateEntities=${canInstallUpdates}
.isInstallable=${true}
></ha-config-updates>
${totalUpdates > canInstallUpdates.length
? html`
@@ -348,14 +349,16 @@ class HaConfigDashboard extends SubscribeMixin(LitElement) {
showShortcutsDialog(this);
}
private _filterUpdateEntitiesWithInstall = memoizeOne(
private _filterUpdateEntitiesParameterized = memoizeOne(
(
entities: HomeAssistant["states"],
entityRegistry: HomeAssistant["entities"]
): { updates: UpdateEntity[]; total: number } => {
const updates = filterUpdateEntitiesWithInstall(entities).filter(
(entity) => !entityRegistry[entity.entity_id]?.hidden
);
const updates = filterUpdateEntitiesParameterized(
entities,
false,
false
).filter((entity) => !entityRegistry[entity.entity_id]?.hidden);
return {
updates: updates.slice(0, updates.length === 3 ? updates.length : 2),

View File

@@ -32,6 +32,8 @@ class HaConfigUpdates extends SubscribeMixin(LitElement) {
@property({ type: Number }) public total?: number;
@property({ attribute: false }) public isInstallable = true;
@state() private _devices?: DeviceRegistryEntry[];
@state() private _entities?: EntityRegistryEntry[];
@@ -89,9 +91,16 @@ class HaConfigUpdates extends SubscribeMixin(LitElement) {
return html`
<div class="title" role="heading" aria-level="2">
${this.hass.localize("ui.panel.config.updates.title", {
count: this.total || this.updateEntities.length,
})}
${this.isInstallable
? this.hass.localize("ui.panel.config.updates.title", {
count: this.total || this.updateEntities.length,
})
: this.hass.localize(
"ui.panel.config.updates.title_not_installable",
{
count: this.total || this.updateEntities.length,
}
)}
</div>
<ha-md-list>
${updates.map((entity) => {

View File

@@ -2383,6 +2383,7 @@
"updates_refreshed": "State of {count} {count, plural,\n one {update}\n other {updates}\n} refreshed",
"checking_updates": "Checking for updates...",
"title": "{count} {count, plural,\n one {update}\n other {updates}\n}",
"title_not_installable": "{count} not installable {count, plural,\n one {update}\n other {updates}\n}",
"unable_to_fetch": "Unable to load updates",
"more_updates": "Show all updates",
"show": "show",