- {/* Stacked bar */}
-
- {segments.map((seg, i) =>
- seg.bytes > 0 ? (
-
seg.filter && onFilter(seg.filter)}
- />
- ) : null
- )}
-
-
- {/* Legend */}
-
- {segments.map((seg, i) =>
- seg.bytes > 0 ? (
-
- ) : null
- )}
-
-
- );
-}
-
// ── Filter Toggle - Segmented Control ─────────────────────────────────────────
interface FilterToggleProps {
@@ -700,6 +630,42 @@ export default function ResourcesView() {
setVolumeFilter(filter);
};
+ const treemapFilterToResourceFilter = (filter: 'managed' | 'unmanaged' | 'reclaimable'): ResourceFilter => {
+ if (filter === 'managed') return 'managed';
+ if (filter === 'unmanaged') return 'unmanaged';
+ return 'unmanaged';
+ };
+
+ const totalReclaimableBytes = (usage?.reclaimableImages ?? 0)
+ + (usage?.reclaimableContainers ?? 0)
+ + (usage?.reclaimableVolumes ?? 0);
+
+ const handleReviewAndPrune = () => {
+ setConfirmPrune({ target: 'images', scope: 'all' });
+ };
+
+ const volumeLandings = useMemo(() => {
+ const largest: TabLandingEntry[] = [...volumes]
+ .sort((a, b) => b.Size - a.Size)
+ .slice(0, 5)
+ .map(vol => ({
+ key: vol.Name,
+ primary: vol.Name,
+ secondary: vol.Size > 0 ? formatBytes(vol.Size) : '-',
+ }));
+ const now = Date.now();
+ const recent: TabLandingEntry[] = volumes
+ .filter(v => !!v.CreatedAt && now - new Date(v.CreatedAt).getTime() <= RECENT_WINDOW_MS)
+ .sort((a, b) => new Date(b.CreatedAt ?? 0).getTime() - new Date(a.CreatedAt ?? 0).getTime())
+ .slice(0, 5)
+ .map(vol => ({
+ key: vol.Name,
+ primary: vol.Name,
+ secondary: vol.CreatedAt ? ageLabel(new Date(vol.CreatedAt).getTime()) : '-',
+ }));
+ return { largest, recent };
+ }, [volumes]);
+
return (
@@ -708,7 +674,7 @@ export default function ResourcesView() {
Resources Hub
{activeNode?.type === 'remote' && (
-
- {activeNode.name}
+
· {activeNode.name}
)}
{trivy.available && isPaid && (