From 822f82b7c9e2f738fe00b703ffaf3f392685f9ae Mon Sep 17 00:00:00 2001 From: Claude Date: Sun, 19 Jul 2026 09:15:14 +0000 Subject: [PATCH] feat: show layer age in prune table Dangling images can lose "fromContainer" attribution when a container updates more than once between prunes (rollback_points keeps only the most recent swap per container), showing as "Untracked source" even though they're safe to remove. Surfacing each layer's creation date (already returned by the dangling-images API, just unused) makes it visually obvious that an unattributed row is simply an older leftover from an earlier update of the same container. --- client/src/pages/SettingsPage.jsx | 19 +++++++++++++++++++ client/src/styles/app.css | 6 ++++++ 2 files changed, 25 insertions(+) diff --git a/client/src/pages/SettingsPage.jsx b/client/src/pages/SettingsPage.jsx index e8ddd27..1851fba 100644 --- a/client/src/pages/SettingsPage.jsx +++ b/client/src/pages/SettingsPage.jsx @@ -26,6 +26,23 @@ function formatBytes(n) { return `${value.toFixed(1)} ${units[i]}`; } +// Rough relative age for an image's creation time (Docker's `created` is Unix +// seconds). Helps explain why some dangling layers show "Untracked source" — +// e.g. an old layer from a container's earlier update, before its rollback +// point got overwritten by a more recent one. +function formatAge(createdSeconds) { + if (!Number.isFinite(createdSeconds)) return '—'; + const ms = Date.now() - createdSeconds * 1000; + const days = Math.floor(ms / 86400000); + if (days < 1) return 'today'; + if (days === 1) return '1 day ago'; + if (days < 30) return `${days} days ago`; + const months = Math.floor(days / 30); + if (months < 12) return `${months} month${months === 1 ? '' : 's'} ago`; + const years = Math.floor(days / 365); + return `${years} year${years === 1 ? '' : 's'} ago`; +} + // Per-target label/description/placeholder for the notification URL field. const NOTIFY_META = { discord: { @@ -520,6 +537,7 @@ export default function SettingsPage({ onPruneComplete } = {}) { Layer Size + Created @@ -533,6 +551,7 @@ export default function SettingsPage({ onPruneComplete } = {}) { {img.id} {formatBytes(img.size || 0)} + {formatAge(img.created)}