-
-
- ${this.hass.localize(
- "ui.panel.config.storage.detailed_description",
- {
- used: `${this._hostInfo?.disk_used} GB`,
- total: `${this._hostInfo?.disk_total} GB`,
- free_space: `${this._hostInfo.disk_free} GB`,
- }
- )}
-
+ ${this._renderStorageMetrics(
+ this._hostInfo,
+ this._storageInfo
+ )}
${this._hostInfo.disk_life_time !== null
? // prettier-ignore
html`
@@ -247,7 +237,100 @@ class HaConfigSectionStorage extends LitElement {
`;
}
+ private _renderStorageMetrics = memoizeOne(
+ (hostInfo?: HassioHostInfo, storageInfo?: HostDisksUsage | null) => {
+ if (!hostInfo) {
+ return nothing;
+ }
+ const computedStyles = getComputedStyle(this);
+ let totalSpaceGB = hostInfo.disk_total;
+ let usedSpaceGB = hostInfo.disk_used;
+ // hostInfo.disk_free is sometimes 0, so we may need to calculate it
+ let freeSpaceGB =
+ hostInfo.disk_free || hostInfo.disk_total - hostInfo.disk_used;
+ const segments: Segment[] = [];
+ if (storageInfo) {
+ const totalSpace =
+ storageInfo.total_bytes ?? this._gbToBytes(hostInfo.disk_total);
+ totalSpaceGB = this._bytesToGB(totalSpace);
+ usedSpaceGB = this._bytesToGB(storageInfo.used_bytes);
+ freeSpaceGB = this._bytesToGB(totalSpace - storageInfo.used_bytes);
+ storageInfo.children?.forEach((child, index) => {
+ if (child.used_bytes > 0) {
+ const space = this._bytesToGB(child.used_bytes);
+ segments.push({
+ value: space,
+ color: getGraphColorByIndex(index, computedStyles),
+ label: html`${this.hass.localize(
+ `ui.panel.config.storage.segments.${child.id}`
+ ) ||
+ child.label ||
+ child.id}
+
${roundWithOneDecimal(space)} GB`,
+ });
+ }
+ });
+ } else {
+ segments.push({
+ value: usedSpaceGB,
+ color: "var(--primary-color)",
+ label: html`${this.hass.localize(
+ "ui.panel.config.storage.segments.used"
+ )}
+
${roundWithOneDecimal(usedSpaceGB)} GB`,
+ });
+ }
+ segments.push({
+ value: freeSpaceGB,
+ color:
+ "var(--ha-bar-background-color, var(--secondary-background-color))",
+ label: html`${this.hass.localize(
+ "ui.panel.config.storage.segments.free"
+ )}
+
${roundWithOneDecimal(freeSpaceGB)} GB`,
+ });
+ const chart = html`
+
+ `;
+ return storageInfo || storageInfo === null
+ ? chart
+ : html`
+
+ `;
+ }
+ );
+
+ private _bytesToGB(bytes: number) {
+ return bytes / 1024 / 1024 / 1024;
+ }
+
+ private _gbToBytes(GB: number) {
+ return GB * 1024 * 1024 * 1024;
+ }
+
private async _load() {
+ this._loadStorageInfo();
try {
this._hostInfo = await fetchHassioHostInfo(this.hass);
} catch (err: any) {
@@ -260,6 +343,15 @@ class HaConfigSectionStorage extends LitElement {
}
}
+ private async _loadStorageInfo() {
+ try {
+ this._storageInfo = await fetchHostDisksUsage(this.hass);
+ } catch (err: any) {
+ this._error = err.message || err;
+ this._storageInfo = null;
+ }
+ }
+
private _moveDatadisk(): void {
showMoveDatadiskDialog(this, {
hostInfo: this._hostInfo!,
@@ -311,9 +403,6 @@ class HaConfigSectionStorage extends LitElement {
}
}
- private _getUsedSpace = (used: number, total: number) =>
- roundWithOneDecimal(getValueInPercentage(used, 0, total));
-
static styles = css`
.content {
padding: 28px 20px 0;
@@ -337,10 +426,22 @@ class HaConfigSectionStorage extends LitElement {
flex-direction: column;
}
- .detailed-storage-info {
- font-size: var(--ha-font-size-s);
- color: var(--secondary-text-color);
+ .loading-container {
+ position: relative;
}
+
+ .loading-overlay {
+ position: absolute;
+ top: 0;
+ left: 0;
+ width: 100%;
+ height: 100%;
+ background-color: rgba(var(--rgb-card-background-color), 0.75);
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ }
+
.mount-state-failed {
color: var(--error-color);
}
diff --git a/src/translations/en.json b/src/translations/en.json
index 1c61467050..8346d740a6 100644
--- a/src/translations/en.json
+++ b/src/translations/en.json
@@ -6661,8 +6661,20 @@
"storage": {
"caption": "Storage",
"description": "{percent_used} used - {free_space} free",
- "used_space": "Used space",
- "detailed_description": "{used} used of {total} total, {free_space} remaining",
+ "used_space": "Storage",
+ "detailed_description": "{used} of {total} used",
+ "segments": {
+ "used": "Used space",
+ "free": "Free space",
+ "system": "System",
+ "addons_data": "Add-on data",
+ "addons_config": "Add-on configuration",
+ "media": "Media",
+ "share": "Share",
+ "backup": "Backups",
+ "homeassistant": "Home Assistant",
+ "ssl": "SSL"
+ },
"lifetime_used": "Lifetime used",
"lifetime_used_description": "The drive’s wear level is shown as a percentage, based on endurance indicators reported by the device via NVMe SMART or eMMC lifetime estimate fields.",
"disk_metrics": "Disk metrics",