diff --git a/dashboard.go b/dashboard.go index 4698d35..1b863a6 100644 --- a/dashboard.go +++ b/dashboard.go @@ -1226,6 +1226,7 @@ func (c *Crawler) handleAPIFilter(w http.ResponseWriter, r *http.Request) { domainStatus := r.URL.Query().Get("domainStatus") languages := r.URL.Query().Get("languages") // comma-separated list show := r.URL.Query().Get("show") // "feeds" or "domains" + sort := r.URL.Query().Get("sort") // "alpha" or "feeds" limit := 100 offset := 0 @@ -1262,11 +1263,11 @@ func (c *Crawler) handleAPIFilter(w http.ResponseWriter, r *http.Request) { if show == "feeds" { c.filterFeeds(w, tld, domain, feedStatus, langList, limit, offset) } else { - c.filterDomains(w, tld, domainStatus, limit, offset) + c.filterDomains(w, tld, domainStatus, sort, limit, offset) } } -func (c *Crawler) filterDomains(w http.ResponseWriter, tld, status string, limit, offset int) { +func (c *Crawler) filterDomains(w http.ResponseWriter, tld, status, sort string, limit, offset int) { var args []interface{} argNum := 1 query := ` @@ -1290,7 +1291,12 @@ func (c *Crawler) filterDomains(w http.ResponseWriter, tld, status string, limit argNum++ } - query += fmt.Sprintf(" ORDER BY d.host ASC LIMIT $%d OFFSET $%d", argNum, argNum+1) + // Sort by feed count descending or alphabetically + if sort == "feeds" { + query += fmt.Sprintf(" ORDER BY feed_count DESC, d.host ASC LIMIT $%d OFFSET $%d", argNum, argNum+1) + } else { + query += fmt.Sprintf(" ORDER BY d.host ASC LIMIT $%d OFFSET $%d", argNum, argNum+1) + } args = append(args, limit, offset) rows, err := c.db.Query( query, args...) diff --git a/static/dashboard.js b/static/dashboard.js index 5889118..26c25cb 100644 --- a/static/dashboard.js +++ b/static/dashboard.js @@ -16,6 +16,7 @@ function initDashboard() { let isLoadingMore = false; let availableLanguages = []; let selectedLanguages = new Set(); + let sortBy = 'alpha'; // 'alpha' or 'feeds' // Update command input to reflect current filters function updateCommandInput() { @@ -81,7 +82,20 @@ function initDashboard() { parts.push('lang:' + escapeHtml(Array.from(selectedLanguages).join(',')) + ' ✕'); } - breadcrumb.innerHTML = parts.join(' / '); + // Add sort toggle on the right if viewing domains + let sortToggle = ''; + if (currentFilters.tld && !currentFilters.domain && !currentFilters.feedStatus) { + const alphaStyle = sortBy === 'alpha' ? 'color: #0f0;' : 'color: #666;'; + const feedsStyle = sortBy === 'feeds' ? 'color: #0f0;' : 'color: #666;'; + sortToggle = '' + + 'A-Z' + + ' | ' + + '#feeds' + + ''; + } + + breadcrumb.innerHTML = '