mirror of
https://tangled.org/evan.jarrett.net/at-container-registry
synced 2026-09-01 15:56:58 +00:00
162 lines
6.7 KiB
HTML
162 lines
6.7 KiB
HTML
{{define "partials/gc_preview.html"}}
|
|
<div class="space-y-6">
|
|
<!-- Summary cards -->
|
|
<div class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-4">
|
|
<div class="stats shadow bg-base-100">
|
|
<div class="stat">
|
|
<div class="stat-title">Orphaned Records</div>
|
|
<div class="stat-value {{if .Preview.OrphanedRecords}}text-error{{end}}">{{len .Preview.OrphanedRecords}}</div>
|
|
<div class="stat-desc">Layer records with no manifest</div>
|
|
</div>
|
|
</div>
|
|
<div class="stats shadow bg-base-100">
|
|
<div class="stat">
|
|
<div class="stat-title">Orphaned Blobs</div>
|
|
<div class="stat-value {{if .Preview.OrphanedBlobs}}text-error{{end}}">{{len .Preview.OrphanedBlobs}}</div>
|
|
<div class="stat-desc">S3 blobs with no layer record</div>
|
|
</div>
|
|
</div>
|
|
<div class="stats shadow bg-base-100">
|
|
<div class="stat">
|
|
<div class="stat-title">Missing Records</div>
|
|
<div class="stat-value {{if .Preview.MissingRecords}}text-warning{{end}}">{{len .Preview.MissingRecords}}</div>
|
|
<div class="stat-desc">Would be reconciled</div>
|
|
</div>
|
|
</div>
|
|
<div class="stats shadow bg-base-100">
|
|
<div class="stat">
|
|
<div class="stat-title">Referenced Blobs</div>
|
|
<div class="stat-value text-success">{{.Preview.ReferencedBlobs}}</div>
|
|
<div class="stat-desc">{{formatDuration .Preview.Duration}}</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Meta info -->
|
|
<p class="text-sm text-base-content/50">
|
|
Checked {{.Preview.UsersChecked}} users, {{.Preview.ManifestsChecked}} manifests, {{.Preview.TotalLayerRecords}} layer records, {{.Preview.TotalBlobs}} S3 blobs.
|
|
</p>
|
|
|
|
<!-- Orphaned Records table -->
|
|
{{if .Preview.OrphanedRecords}}
|
|
<div class="collapse collapse-arrow bg-base-100 shadow-sm">
|
|
<input type="checkbox" />
|
|
<div class="collapse-title font-medium">
|
|
{{ icon "file-x" "size-4 inline" }} Orphaned Layer Records ({{len .Preview.OrphanedRecords}})
|
|
</div>
|
|
<div class="collapse-content">
|
|
<div class="overflow-x-auto">
|
|
<table class="table table-sm">
|
|
<thead>
|
|
<tr>
|
|
<th>RKey</th>
|
|
<th>Digest</th>
|
|
<th>Manifest</th>
|
|
<th>Size</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
{{range .Preview.OrphanedRecords}}
|
|
<tr>
|
|
<td><code class="text-xs font-mono">{{.Rkey}}</code></td>
|
|
<td><code class="text-xs font-mono">{{truncate .Digest 24}}</code></td>
|
|
<td><code class="text-xs font-mono break-all">{{truncate .ManifestURI 50}}</code></td>
|
|
<td class="whitespace-nowrap">{{formatBytes .Size}}</td>
|
|
</tr>
|
|
{{end}}
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
{{end}}
|
|
|
|
<!-- Orphaned Blobs table -->
|
|
{{if .Preview.OrphanedBlobs}}
|
|
<div class="collapse collapse-arrow bg-base-100 shadow-sm">
|
|
<input type="checkbox" />
|
|
<div class="collapse-title font-medium">
|
|
{{ icon "trash-2" "size-4 inline" }} Orphaned Blobs ({{len .Preview.OrphanedBlobs}})
|
|
</div>
|
|
<div class="collapse-content">
|
|
<div class="overflow-x-auto">
|
|
<table class="table table-sm">
|
|
<thead>
|
|
<tr>
|
|
<th>Digest</th>
|
|
<th>Size</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
{{range .Preview.OrphanedBlobs}}
|
|
<tr>
|
|
<td><code class="text-xs font-mono">{{truncate .Digest 30}}</code></td>
|
|
<td class="whitespace-nowrap">{{formatBytes .Size}}</td>
|
|
</tr>
|
|
{{end}}
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
{{end}}
|
|
|
|
<!-- Missing Records table (reconcile mode only) -->
|
|
{{if .Preview.MissingRecords}}
|
|
<div class="collapse collapse-arrow bg-base-100 shadow-sm">
|
|
<input type="checkbox" />
|
|
<div class="collapse-title font-medium">
|
|
{{ icon "file-plus" "size-4 inline" }} Missing Layer Records ({{len .Preview.MissingRecords}})
|
|
</div>
|
|
<div class="collapse-content">
|
|
<div class="overflow-x-auto">
|
|
<table class="table table-sm">
|
|
<thead>
|
|
<tr>
|
|
<th>Digest</th>
|
|
<th>Manifest</th>
|
|
<th>User</th>
|
|
<th>Size</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
{{range .Preview.MissingRecords}}
|
|
<tr>
|
|
<td><code class="text-xs font-mono">{{truncate .Digest 24}}</code></td>
|
|
<td><code class="text-xs font-mono break-all">{{truncate .ManifestURI 50}}</code></td>
|
|
<td><code class="text-xs font-mono">{{truncate .UserDID 24}}</code></td>
|
|
<td class="whitespace-nowrap">{{formatBytes .Size}}</td>
|
|
</tr>
|
|
{{end}}
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
{{end}}
|
|
|
|
<!-- Run GC button (only if there are actions to take) -->
|
|
{{if or .Preview.OrphanedRecords .Preview.OrphanedBlobs .Preview.MissingRecords}}
|
|
<div class="flex items-center gap-3 mt-6">
|
|
<button class="btn btn-error gap-2"
|
|
hx-post="/admin/api/gc/run"
|
|
hx-target="#gc-results"
|
|
hx-swap="innerHTML"
|
|
hx-confirm="Are you sure you want to run garbage collection?"
|
|
hx-indicator="#gc-loading">
|
|
{{ icon "zap" "size-4" }}
|
|
Run GC
|
|
</button>
|
|
</div>
|
|
{{end}}
|
|
|
|
<!-- Nothing to clean -->
|
|
{{if and (not .Preview.OrphanedRecords) (not .Preview.OrphanedBlobs) (not .Preview.MissingRecords)}}
|
|
<div class="alert alert-success">
|
|
{{ icon "check-circle" "size-5" }}
|
|
<span>Storage is clean. No orphaned data found.</span>
|
|
</div>
|
|
{{end}}
|
|
</div>
|
|
{{end}}
|