pkg-proxy/internal/server/templates/pages/packages_list.html
2026-03-11 17:25:47 +00:00

115 lines
6.2 KiB
HTML

{{define "title"}}Cached Packages - git-pkgs proxy{{end}}
{{define "content"}}
<div class="mb-8">
<h1 class="text-3xl font-bold mb-2">Cached Packages</h1>
<p class="text-gray-600 dark:text-gray-400">
{{.Count}} packages{{if .Ecosystem}} in {{.Ecosystem}}{{end}}
</p>
</div>
<div class="mb-6 flex items-center gap-4">
<div class="flex-1">
<label for="ecosystem-filter" class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1">Filter by ecosystem</label>
<select id="ecosystem-filter" class="w-full max-w-xs px-4 py-2 text-sm bg-white dark:bg-gray-800 border border-gray-300 dark:border-gray-700 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500 dark:focus:ring-blue-400">
<option value="">All ecosystems</option>
{{range supportedEcosystems}}
<option value="{{.}}"{{if eq $.Ecosystem .}} selected{{end}}>{{ecosystemBadgeLabel .}}</option>
{{end}}
</select>
</div>
<div class="flex-1">
<label for="sort-by" class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1">Sort by</label>
<select id="sort-by" class="w-full max-w-xs px-4 py-2 text-sm bg-white dark:bg-gray-800 border border-gray-300 dark:border-gray-700 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500 dark:focus:ring-blue-400">
<option value="hits"{{if eq .SortBy "hits"}} selected{{end}}>Cache hits</option>
<option value="name"{{if eq .SortBy "name"}} selected{{end}}>Name</option>
<option value="size"{{if eq .SortBy "size"}} selected{{end}}>Size</option>
<option value="cached_at"{{if eq .SortBy "cached_at"}} selected{{end}}>Recently cached</option>
<option value="ecosystem"{{if eq .SortBy "ecosystem"}} selected{{end}}>Ecosystem</option>
<option value="vulns"{{if eq .SortBy "vulns"}} selected{{end}}>Vulnerabilities</option>
</select>
</div>
</div>
{{if .Results}}
<div class="bg-white dark:bg-gray-900 rounded-xl shadow-sm border border-gray-200 dark:border-gray-800">
<div class="divide-y divide-gray-200 dark:divide-gray-800">
{{range .Results}}
<div class="px-6 py-4 flex items-center justify-between">
<div class="min-w-0 flex-1">
<div class="flex items-center gap-2">
{{template "ecosystem_badge" .Ecosystem}}
<a href="/package/{{.Ecosystem}}/{{.Name}}" class="font-medium truncate hover:text-blue-600 dark:hover:text-blue-400">{{.Name}}</a>
{{if .LatestVersion}}
<span class="text-gray-500 dark:text-gray-400">@{{.LatestVersion}}</span>
{{end}}
</div>
<div class="flex items-center gap-2 mt-1">
{{if .License}}
<span class="inline-flex items-center px-2 py-0.5 rounded text-xs font-medium bg-{{if eq .LicenseCategory "permissive"}}green{{else if eq .LicenseCategory "copyleft"}}pink{{else}}gray{{end}}-100 text-{{if eq .LicenseCategory "permissive"}}green{{else if eq .LicenseCategory "copyleft"}}pink{{else}}gray{{end}}-700 dark:bg-{{if eq .LicenseCategory "permissive"}}green{{else if eq .LicenseCategory "copyleft"}}pink{{else}}gray{{end}}-900 dark:text-{{if eq .LicenseCategory "permissive"}}green{{else if eq .LicenseCategory "copyleft"}}pink{{else}}gray{{end}}-300">{{.License}}</span>
{{end}}
{{if gt .VulnCount 0}}
<span class="inline-flex items-center px-2 py-0.5 rounded text-xs font-medium bg-red-100 text-red-700 dark:bg-red-900 dark:text-red-300">{{.VulnCount}} vulns</span>
{{end}}
</div>
</div>
<div class="flex items-center gap-4 text-sm text-gray-500 dark:text-gray-400">
<span>{{.Hits}} hits</span>
<span>{{.SizeFormatted}}</span>
{{if .CachedAt}}
<span>{{.CachedAt}}</span>
{{end}}
</div>
</div>
{{end}}
</div>
</div>
{{else}}
<div class="bg-white dark:bg-gray-900 rounded-xl shadow-sm border border-gray-200 dark:border-gray-800 p-12 text-center">
<p class="text-gray-500 dark:text-gray-400">No cached packages found{{if .Ecosystem}} in {{.Ecosystem}}{{end}}</p>
<a href="/" class="mt-4 inline-block text-sm text-blue-600 dark:text-blue-400 hover:underline">Return to dashboard</a>
</div>
{{end}}
{{if gt .TotalPages 1}}
<div class="mt-6 flex items-center justify-center gap-2">
{{if gt .Page 1}}
<a href="?{{if .Ecosystem}}ecosystem={{.Ecosystem}}&{{end}}{{if .SortBy}}sort={{.SortBy}}&{{end}}page={{sub .Page 1}}"
class="px-4 py-2 text-sm font-medium text-gray-700 dark:text-gray-300 bg-white dark:bg-gray-800 border border-gray-300 dark:border-gray-700 rounded-lg hover:bg-gray-50 dark:hover:bg-gray-700">
Previous
</a>
{{end}}
<span class="px-4 py-2 text-sm text-gray-600 dark:text-gray-400">
Page {{.Page}} of {{.TotalPages}}
</span>
{{if lt .Page .TotalPages}}
<a href="?{{if .Ecosystem}}ecosystem={{.Ecosystem}}&{{end}}{{if .SortBy}}sort={{.SortBy}}&{{end}}page={{add .Page 1}}"
class="px-4 py-2 text-sm font-medium text-gray-700 dark:text-gray-300 bg-white dark:bg-gray-800 border border-gray-300 dark:border-gray-700 rounded-lg hover:bg-gray-50 dark:hover:bg-gray-700">
Next
</a>
{{end}}
</div>
{{end}}
<script>
document.getElementById('ecosystem-filter').addEventListener('change', function(e) {
const ecosystem = e.target.value;
const sortBy = document.getElementById('sort-by').value;
const params = new URLSearchParams();
if (ecosystem) params.set('ecosystem', ecosystem);
if (sortBy) params.set('sort', sortBy);
window.location.href = '/packages?' + params.toString();
});
document.getElementById('sort-by').addEventListener('change', function(e) {
const sortBy = e.target.value;
const ecosystem = document.getElementById('ecosystem-filter').value;
const params = new URLSearchParams();
if (ecosystem) params.set('ecosystem', ecosystem);
if (sortBy) params.set('sort', sortBy);
window.location.href = '/packages?' + params.toString();
});
</script>
{{end}}