v52: simplify feed row: status, count, path, title inline
This commit is contained in:
+7
-2
@@ -137,6 +137,7 @@ func (c *Crawler) handleAPIDomains(w http.ResponseWriter, r *http.Request) {
|
||||
Status string `json:"status,omitempty"`
|
||||
PublishStatus string `json:"publish_status,omitempty"`
|
||||
Language string `json:"language,omitempty"`
|
||||
ItemCount int `json:"item_count,omitempty"`
|
||||
}
|
||||
|
||||
type DomainInfo struct {
|
||||
@@ -165,7 +166,7 @@ func (c *Crawler) handleAPIDomains(w http.ResponseWriter, r *http.Request) {
|
||||
// Now get feeds for these domains
|
||||
if len(hosts) > 0 {
|
||||
feedRows, err := c.db.Query(`
|
||||
SELECT source_host, url, title, type, status, publish_status, language
|
||||
SELECT source_host, url, title, type, status, publish_status, language, item_count
|
||||
FROM feeds
|
||||
WHERE source_host = ANY($1)
|
||||
ORDER BY source_host, url
|
||||
@@ -177,7 +178,8 @@ func (c *Crawler) handleAPIDomains(w http.ResponseWriter, r *http.Request) {
|
||||
var host string
|
||||
var f FeedInfo
|
||||
var title, feedType, status, publishStatus, language *string
|
||||
if err := feedRows.Scan(&host, &f.URL, &title, &feedType, &status, &publishStatus, &language); err != nil {
|
||||
var itemCount *int
|
||||
if err := feedRows.Scan(&host, &f.URL, &title, &feedType, &status, &publishStatus, &language, &itemCount); err != nil {
|
||||
continue
|
||||
}
|
||||
f.Title = StringValue(title)
|
||||
@@ -185,6 +187,9 @@ func (c *Crawler) handleAPIDomains(w http.ResponseWriter, r *http.Request) {
|
||||
f.Status = StringValue(status)
|
||||
f.PublishStatus = StringValue(publishStatus)
|
||||
f.Language = StringValue(language)
|
||||
if itemCount != nil {
|
||||
f.ItemCount = *itemCount
|
||||
}
|
||||
feedsByHost[host] = append(feedsByHost[host], f)
|
||||
}
|
||||
// Attach feeds to domains
|
||||
|
||||
+20
-14
@@ -132,43 +132,49 @@ function initDashboard() {
|
||||
|
||||
html += '</div>';
|
||||
|
||||
// Feeds under this domain (hidden by default, toggled by clicking domain name)
|
||||
// Feeds under this domain (hidden by default, toggled by clicking spacer)
|
||||
if (d.feeds && d.feeds.length > 0) {
|
||||
html += '<div class="domain-feeds" style="display: none; margin-left: 20px; border-left: 2px solid #333; padding-left: 10px;">';
|
||||
d.feeds.forEach(f => {
|
||||
const feedStatus = f.publish_status || 'hold';
|
||||
const feedHasError = f.status === 'error' || f.status === 'dead';
|
||||
|
||||
html += `<div class="inline-feed-block" data-url="${escapeHtml(f.url)}" data-status="${feedStatus}">`;
|
||||
|
||||
html += `<div class="feed-row" style="display: flex; align-items: center; padding: 4px 0; font-size: 12px;">`;
|
||||
|
||||
// Language indicator (fixed width)
|
||||
const lang = f.language || '';
|
||||
html += `<span style="display: inline-block; width: 32px; margin-right: 6px; color: #666; font-size: 10px; font-family: monospace; text-align: center;">${escapeHtml(lang)}</span>`;
|
||||
|
||||
// Feed status buttons
|
||||
// Feed publish status buttons (pass/hold/skip)
|
||||
html += renderStatusBtns(feedStatus, 'feed', f.url, f.status);
|
||||
|
||||
// Feed path + title
|
||||
// Feed crawl status (active/error/dead)
|
||||
const statusColor = f.status === 'active' ? '#484' : f.status === 'error' ? '#a66' : '#666';
|
||||
html += `<span style="color: ${statusColor}; font-size: 10px; font-family: monospace; width: 40px; margin-right: 6px;">${escapeHtml(f.status || 'active')}</span>`;
|
||||
|
||||
// Item count if > 0
|
||||
if (f.item_count > 0) {
|
||||
html += `<span style="color: #888; font-size: 10px; font-family: monospace; width: 50px; margin-right: 6px; text-align: right;">${commaFormat(f.item_count)}</span>`;
|
||||
} else {
|
||||
html += `<span style="width: 50px; margin-right: 6px;"></span>`;
|
||||
}
|
||||
|
||||
// Feed path (URL without domain)
|
||||
let feedPath = f.url;
|
||||
try {
|
||||
const urlObj = new URL(f.url.startsWith('http') ? f.url : 'https://' + f.url);
|
||||
feedPath = urlObj.pathname + urlObj.search;
|
||||
} catch (e) {}
|
||||
const displayText = f.title ? `${feedPath} - ${f.title}` : feedPath;
|
||||
html += `<span class="feed-title" style="color: #fff; cursor: pointer; flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;" title="${escapeHtml(f.url)}">${escapeHtml(displayText)}</span>`;
|
||||
html += `<span style="color: #0af; font-size: 11px; margin-right: 8px; white-space: nowrap;" title="${escapeHtml(f.url)}">${escapeHtml(feedPath)}</span>`;
|
||||
|
||||
// Feed type
|
||||
if (f.type) {
|
||||
html += `<span style="color: #555; margin-left: 8px; font-size: 10px;">${escapeHtml(f.type)}</span>`;
|
||||
// Feed title
|
||||
if (f.title) {
|
||||
html += `<span style="color: #fff; flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;">${escapeHtml(f.title)}</span>`;
|
||||
} else {
|
||||
html += '<span style="flex: 1;"></span>';
|
||||
}
|
||||
|
||||
html += '</div>';
|
||||
|
||||
// Collapsible detail section
|
||||
html += '<div class="feed-detail" style="display: none; padding: 8px 0 8px 10px; border-left: 2px solid #444; margin-left: 10px; background: #0a0a0a;"></div>';
|
||||
|
||||
html += '</div>';
|
||||
});
|
||||
html += '</div>';
|
||||
|
||||
+1
-1
@@ -534,7 +534,7 @@ const dashboardHTML = `<!DOCTYPE html>
|
||||
<div id="output"></div>
|
||||
</div>
|
||||
|
||||
<div style="color: #333; font-size: 11px; margin-top: 10px;">v51</div>
|
||||
<div style="color: #333; font-size: 11px; margin-top: 10px;">v52</div>
|
||||
|
||||
<div class="updated" id="updatedAt">Last updated: {{.UpdatedAt.Format "2006-01-02 15:04:05"}}</div>
|
||||
</body>
|
||||
|
||||
Reference in New Issue
Block a user