Feature: Snapshot-Tab gruppiert nach Dataset wie Cockpit-Plugin
Snapshots werden nach Dataset gruppiert angezeigt (tank: 94, tank/share: 94) mit aufklappbaren Zeilen statt flacher Liste. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -501,7 +501,16 @@ export default function DatasetsPage() {
|
||||
<div className="text-center py-6 text-muted-foreground text-xs">Loading…</div>
|
||||
) : snaps.length === 0 ? (
|
||||
<div className="text-center py-6 text-muted-foreground text-xs">No snapshots</div>
|
||||
) : (
|
||||
) : (() => {
|
||||
// Group snapshots by dataset
|
||||
const groups = new Map<string, Snapshot[]>()
|
||||
snaps.forEach((s) => {
|
||||
const ds = s.dataset || s.name.split("@")[0]
|
||||
if (!groups.has(ds)) groups.set(ds, [])
|
||||
groups.get(ds)!.push(s)
|
||||
})
|
||||
const expandKey = `snapgroup-${pool.name}`
|
||||
return (
|
||||
<div className="overflow-x-auto">
|
||||
<table className="w-full text-xs">
|
||||
<thead className="bg-muted">
|
||||
@@ -515,34 +524,56 @@ export default function DatasetsPage() {
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{snaps.map((snap) => (
|
||||
<tr key={snap.name} className="border-b border-border/50 hover:bg-muted/30">
|
||||
<td className="px-3 py-2 font-mono">
|
||||
<span className="text-muted-foreground">{snap.dataset}@</span>{snap.name.split("@")[1]}
|
||||
{Array.from(groups.entries()).map(([ds, dsSnaps]) => {
|
||||
const isGroupExpanded = expandedDatasets.has(`${expandKey}-${ds}`)
|
||||
return [
|
||||
// Group header row
|
||||
<tr
|
||||
key={`group-${ds}`}
|
||||
className="border-b border-border bg-muted/20 hover:bg-muted/40 cursor-pointer select-none"
|
||||
onClick={() => {
|
||||
const next = new Set(expandedDatasets)
|
||||
if (isGroupExpanded) next.delete(`${expandKey}-${ds}`)
|
||||
else next.add(`${expandKey}-${ds}`)
|
||||
setExpandedDatasets(next)
|
||||
}}
|
||||
>
|
||||
<td className="px-3 py-2 font-mono font-medium" colSpan={5}>
|
||||
<div className="flex items-center gap-2">
|
||||
{isGroupExpanded ? <ChevronDown className="w-3 h-3" /> : <ChevronRight className="w-3 h-3" />}
|
||||
<span>{ds}</span>
|
||||
<span className="text-muted-foreground font-normal">{dsSnaps.length}</span>
|
||||
</div>
|
||||
</td>
|
||||
<td className="px-3 py-2 text-muted-foreground">
|
||||
<td />
|
||||
</tr>,
|
||||
// Snapshot rows (expanded)
|
||||
...(isGroupExpanded ? dsSnaps.map((snap) => (
|
||||
<tr key={snap.name} className="border-b border-border/40 hover:bg-muted/30">
|
||||
<td className="px-3 py-1.5 font-mono pl-8">{snap.name.split("@")[1]}</td>
|
||||
<td className="px-3 py-1.5 text-muted-foreground">
|
||||
{snap.creation_datetime ? new Date(snap.creation_datetime).toLocaleString() : "—"}
|
||||
</td>
|
||||
<td className="px-3 py-2">{formatBytes(snap.used)}</td>
|
||||
<td className="px-3 py-2">{formatBytes(snap.referenced)}</td>
|
||||
<td className="px-3 py-2 text-muted-foreground">—</td>
|
||||
<td className="px-3 py-2 text-right">
|
||||
<td className="px-3 py-1.5">{formatBytes(snap.used)}</td>
|
||||
<td className="px-3 py-1.5">{formatBytes(snap.referenced)}</td>
|
||||
<td className="px-3 py-1.5 text-muted-foreground">—</td>
|
||||
<td className="px-3 py-1.5 text-right">
|
||||
<button
|
||||
className="p-1 rounded hover:bg-muted"
|
||||
onClick={(e) => {
|
||||
e.stopPropagation()
|
||||
setSnapContextMenu({ snap, x: e.clientX, y: e.clientY })
|
||||
}}
|
||||
onClick={(e) => { e.stopPropagation(); setSnapContextMenu({ snap, x: e.clientX, y: e.clientY }) }}
|
||||
>
|
||||
<MoreVertical className="w-3 h-3" />
|
||||
</button>
|
||||
</td>
|
||||
</tr>
|
||||
))}
|
||||
)) : [])
|
||||
]
|
||||
})}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
)}
|
||||
)
|
||||
})()}
|
||||
</div>
|
||||
)
|
||||
})()}
|
||||
|
||||
Reference in New Issue
Block a user