fix(news): use Promise.allSettled for resilience, deduplicate items, guard categories
Build & Deploy / build-and-deploy (push) Successful in 2m15s

This commit is contained in:
svemagie
2026-04-19 12:45:46 +02:00
parent 2e911fcc35
commit 72125da01e
+25 -7
View File
@@ -161,7 +161,7 @@ withSidebar: true
<span x-show="item.author || item.blog?.title" x-text="'by ' + (item.author || item.blog?.title)"></span> <span x-show="item.author || item.blog?.title" x-text="'by ' + (item.author || item.blog?.title)"></span>
<time class="font-mono text-sm" :datetime="item.published" x-text="formatDate(item.published)"></time> <time class="font-mono text-sm" :datetime="item.published" x-text="formatDate(item.published)"></time>
<span class="hidden sm:inline" x-show="item.categories?.length"> <span class="hidden sm:inline" x-show="item.categories?.length">
<template x-for="cat in item.categories.slice(0, 3)" :key="cat"> <template x-for="cat in (item.categories || []).slice(0, 3)" :key="cat">
<span class="text-accent-600 dark:text-accent-400" x-text="'#' + cat"></span> <span class="text-accent-600 dark:text-accent-400" x-text="'#' + cat"></span>
</template> </template>
</span> </span>
@@ -387,12 +387,25 @@ function newsApp() {
this.error = null; this.error = null;
try { try {
const [itemsRes, feedsRes, statusRes] = await Promise.all([ const [itemsResult, feedsResult, statusResult] = await Promise.allSettled([
fetch('/rssapi/api/items?limit=50').then(r => r.json()), fetch('/rssapi/api/items?limit=50').then(r => { if (!r.ok) throw new Error('HTTP ' + r.status); return r.json(); }),
fetch('/rssapi/api/feeds').then(r => r.json()), fetch('/rssapi/api/feeds').then(r => { if (!r.ok) throw new Error('HTTP ' + r.status); return r.json(); }),
fetch('/rssapi/api/status').then(r => r.json()) fetch('/rssapi/api/status').then(r => { if (!r.ok) throw new Error('HTTP ' + r.status); return r.json(); })
]); ]);
if (itemsResult.status === 'rejected') {
this.error = 'Failed to load news: ' + itemsResult.reason.message;
console.error('News items fetch error:', itemsResult.reason);
return;
}
const itemsRes = itemsResult.value;
const feedsRes = feedsResult.status === 'fulfilled' ? feedsResult.value : { feeds: [] };
const statusRes = statusResult.status === 'fulfilled' ? statusResult.value : null;
if (feedsResult.status === 'rejected') console.warn('News feeds fetch failed (non-critical):', feedsResult.reason);
if (statusResult.status === 'rejected') console.warn('News status fetch failed (non-critical):', statusResult.reason);
this.items = itemsRes.items || []; this.items = itemsRes.items || [];
this.pagination = itemsRes.pagination || null; this.pagination = itemsRes.pagination || null;
this.feeds = feedsRes.feeds || []; this.feeds = feedsRes.feeds || [];
@@ -429,8 +442,13 @@ function newsApp() {
}, },
get filteredItems() { get filteredItems() {
if (this.filterFeed === 'all') return this.items; const seen = new Set();
return this.items.filter(item => item.feedId === this.filterFeed); const base = this.filterFeed === 'all' ? this.items : this.items.filter(item => item.feedId === this.filterFeed);
return base.filter(item => {
if (seen.has(item.id)) return false;
seen.add(item.id);
return true;
});
}, },
getFeedUrl(feedId) { getFeedUrl(feedId) {