${this._error
? html`
diff --git a/src/panels/config/core/ha-config-section-storage.ts b/src/panels/config/core/ha-config-section-storage.ts
index 6e3a96f140..b40eaa4d44 100644
--- a/src/panels/config/core/ha-config-section-storage.ts
+++ b/src/panels/config/core/ha-config-section-storage.ts
@@ -1,7 +1,17 @@
-import { css, html, LitElement, TemplateResult } from "lit";
-import { customElement, property } from "lit/decorators";
+import { css, html, LitElement, PropertyValues, TemplateResult } from "lit";
+import { customElement, property, state } from "lit/decorators";
+import memoizeOne from "memoize-one";
+import { isComponentLoaded } from "../../../common/config/is_component_loaded";
+import "../../../components/ha-alert";
+import "../../../components/ha-bar";
+import "../../../components/ha-metric";
+import { fetchHassioHostInfo, HassioHostInfo } from "../../../data/hassio/host";
import "../../../layouts/hass-subpage";
import type { HomeAssistant, Route } from "../../../types";
+import {
+ getValueInPercentage,
+ roundWithOneDecimal,
+} from "../../../util/calculate";
import "./ha-config-analytics";
@customElement("ha-config-section-storage")
@@ -12,6 +22,17 @@ class HaConfigSectionStorage extends LitElement {
@property({ type: Boolean }) public narrow!: boolean;
+ @state() private _error?: { code: string; message: string };
+
+ @state() private _storageData?: HassioHostInfo;
+
+ protected firstUpdated(changedProps: PropertyValues) {
+ super.firstUpdated(changedProps);
+ if (isComponentLoaded(this.hass, "hassio")) {
+ this._load();
+ }
+ }
+
protected render(): TemplateResult {
return html`
-
+
+ ${this._error
+ ? html`
+ ${this._error.message || this._error.code}
+ `
+ : ""}
+ ${this._storageData
+ ? html`
+
+
+ ${this._storageData.disk_life_time !== "" &&
+ this._storageData.disk_life_time >= 10
+ ? html`
+
+ `
+ : ""}
+
+ `
+ : ""}
+
`;
}
+ private async _load() {
+ this._error = undefined;
+ try {
+ if (isComponentLoaded(this.hass, "hassio")) {
+ this._storageData = await fetchHassioHostInfo(this.hass);
+ }
+ } catch (err: any) {
+ this._error = err.message || err;
+ }
+ }
+
+ private _getUsedSpace = memoizeOne((used: number, total: number) =>
+ roundWithOneDecimal(getValueInPercentage(used, 0, total))
+ );
+
static styles = css`
.content {
padding: 28px 20px 0;
max-width: 1040px;
margin: 0 auto;
}
+ ha-card {
+ padding: 16px;
+ max-width: 500px;
+ margin: 0 auto;
+ height: 100%;
+ justify-content: space-between;
+ flex-direction: column;
+ display: flex;
+ }
+ .emmc {
+ --metric-bar-ok-color: #000;
+ }
`;
}
diff --git a/src/panels/config/core/ha-config-section-updates.ts b/src/panels/config/core/ha-config-section-updates.ts
new file mode 100644
index 0000000000..0853566da3
--- /dev/null
+++ b/src/panels/config/core/ha-config-section-updates.ts
@@ -0,0 +1,137 @@
+import { HassEntities } from "home-assistant-js-websocket";
+import { css, html, LitElement, PropertyValues, TemplateResult } from "lit";
+import { customElement, property } from "lit/decorators";
+import memoizeOne from "memoize-one";
+import { computeStateDomain } from "../../../common/entity/compute_state_domain";
+import { caseInsensitiveStringCompare } from "../../../common/string/compare";
+import "../../../components/ha-alert";
+import "../../../components/ha-bar";
+import "../../../components/ha-metric";
+import { updateCanInstall, UpdateEntity } from "../../../data/update";
+import "../../../layouts/hass-subpage";
+import type { HomeAssistant } from "../../../types";
+import { showToast } from "../../../util/toast";
+import "../dashboard/ha-config-updates";
+import "./ha-config-analytics";
+
+@customElement("ha-config-section-updates")
+class HaConfigSectionUpdates extends LitElement {
+ @property({ attribute: false }) public hass!: HomeAssistant;
+
+ @property({ type: Boolean }) public narrow!: boolean;
+
+ private _notifyUpdates = false;
+
+ protected render(): TemplateResult {
+ const canInstallUpdates = this._filterUpdateEntitiesWithInstall(
+ this.hass.states
+ );
+
+ return html`
+
+
+
+ ${canInstallUpdates.length
+ ? html`
+
+ `
+ : html`
+ ${this.hass.localize("ui.panel.config.updates.no_updates")}
+ `}
+
+
+
+ `;
+ }
+
+ protected override updated(changedProps: PropertyValues): void {
+ super.updated(changedProps);
+
+ if (!changedProps.has("hass") || !this._notifyUpdates) {
+ return;
+ }
+ this._notifyUpdates = false;
+ if (this._filterUpdateEntitiesWithInstall(this.hass.states).length) {
+ showToast(this, {
+ message: this.hass.localize(
+ "ui.panel.config.updates.updates_refreshed"
+ ),
+ });
+ } else {
+ showToast(this, {
+ message: this.hass.localize("ui.panel.config.updates.no_new_updates"),
+ });
+ }
+ }
+
+ private _filterUpdateEntities = memoizeOne((entities: HassEntities) =>
+ (
+ Object.values(entities).filter(
+ (entity) => computeStateDomain(entity) === "update"
+ ) as UpdateEntity[]
+ ).sort((a, b) => {
+ if (a.attributes.title === "Home Assistant Core") {
+ return -3;
+ }
+ if (b.attributes.title === "Home Assistant Core") {
+ return 3;
+ }
+ if (a.attributes.title === "Home Assistant Operating System") {
+ return -2;
+ }
+ if (b.attributes.title === "Home Assistant Operating System") {
+ return 2;
+ }
+ if (a.attributes.title === "Home Assistant Supervisor") {
+ return -1;
+ }
+ if (b.attributes.title === "Home Assistant Supervisor") {
+ return 1;
+ }
+ return caseInsensitiveStringCompare(
+ a.attributes.title || a.attributes.friendly_name || "",
+ b.attributes.title || b.attributes.friendly_name || ""
+ );
+ })
+ );
+
+ private _filterUpdateEntitiesWithInstall = memoizeOne(
+ (entities: HassEntities) =>
+ this._filterUpdateEntities(entities).filter((entity) =>
+ updateCanInstall(entity)
+ )
+ );
+
+ static styles = css`
+ .content {
+ padding: 28px 20px 0;
+ max-width: 1040px;
+ margin: 0 auto;
+ }
+ ha-card {
+ padding: 16px;
+ max-width: 500px;
+ margin: 0 auto;
+ height: 100%;
+ justify-content: space-between;
+ flex-direction: column;
+ display: flex;
+ }
+ `;
+}
+
+declare global {
+ interface HTMLElementTagNameMap {
+ "ha-config-section-updates": HaConfigSectionUpdates;
+ }
+}
diff --git a/src/panels/config/core/ha-config-system-navigation.ts b/src/panels/config/core/ha-config-system-navigation.ts
index 0db85573b0..8792ef009a 100644
--- a/src/panels/config/core/ha-config-system-navigation.ts
+++ b/src/panels/config/core/ha-config-system-navigation.ts
@@ -33,7 +33,7 @@ class HaConfigSystemNavigation extends LitElement {
return html`
${this.narrow
? html`
- ${this.hass.localize(
- "ui.panel.config.dashboard.system.title"
- )}
+ ${this.hass.localize("ui.panel.config.dashboard.system.main")}
`
: ""}
`
)}
- ${!this._showAll && this.updateEntities.length >= 4
+ ${!this.showAll && this.updateEntities.length >= 4
? html`
`}
+ >
+