feat(resources): managed/unmanaged resource separation across Resources Hub

- Classify all Docker images, volumes, and networks as managed (Sencho
  stack), external (other Compose project), or unused/system via a new
  getClassifiedResources() method and GET /api/system/resources endpoint
- Add pruneManagedOnly() + getDiskUsageClassified() to DockerController
- Prune buttons now default to Sencho-managed scope; "All Docker" is
  hidden in a ⋮ dropdown with a distinct destructive confirm dialog
- Replace Reclaimable Space donut with interactive Docker Disk Footprint
  widget (stacked bar with clickable segments that filter resource tabs)
- Add managed/external filter toggles and classification badges per tab
- GET /api/stats now returns managed + unmanaged container counts; Home
  Dashboard Active Containers card subtitle shows "N managed · N external"
- Rename "Ghost Containers" tab/copy to "Unmanaged Containers" throughout
This commit is contained in:
SaelixCode
2026-03-22 03:17:54 -04:00
parent 740796b869
commit 5191737d53
5 changed files with 879 additions and 256 deletions
+6 -3
View File
@@ -13,9 +13,10 @@ import { Label } from './ui/label';
interface Stats {
active: number;
managed: number;
unmanaged: number;
exited: number;
total: number;
inactive: number;
}
interface MetricPoint {
@@ -66,7 +67,7 @@ export default function HomeDashboard() {
const [convertedYaml, setConvertedYaml] = useState('');
const [createDialogOpen, setCreateDialogOpen] = useState(false);
const [newStackName, setNewStackName] = useState('');
const [stats, setStats] = useState<Stats>({ active: 0, exited: 0, total: 0, inactive: 0 });
const [stats, setStats] = useState<Stats>({ active: 0, managed: 0, unmanaged: 0, exited: 0, total: 0 });
const [systemStats, setSystemStats] = useState<SystemStats | null>(null);
const [metrics, setMetrics] = useState<MetricPoint[]>([]);
@@ -221,7 +222,9 @@ export default function HomeDashboard() {
</CardHeader>
<CardContent>
<div className="text-3xl font-bold text-green-500">{stats.active}</div>
<p className="text-xs text-muted-foreground mt-1">Currently running</p>
<p className="text-xs text-muted-foreground mt-1">
{stats.managed} managed · {stats.unmanaged} external
</p>
</CardContent>
</Card>
File diff suppressed because it is too large Load Diff