Load calendar data async so slow/failing sources don't block page load
Split loadDashboardData into two phases: core data (settings, widgets, notes) renders immediately, then calendar events load in the background. Uses Promise.allSettled so individual calendar source failures don't affect other sources or the dashboard. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
+47
-31
@@ -381,33 +381,21 @@ export default function DashboardPage() {
|
||||
}
|
||||
}
|
||||
|
||||
async function loadDashboardData() {
|
||||
setDashboardError(null);
|
||||
|
||||
async function loadCalendarData(widgets: Widget[]) {
|
||||
try {
|
||||
const [settingsResponse, widgetsResponse, notesResponse] = await Promise.all([
|
||||
fetch("/api/settings", {
|
||||
cache: "no-store"
|
||||
}),
|
||||
fetch("/api/widgets", {
|
||||
cache: "no-store"
|
||||
}),
|
||||
fetch("/api/notes", {
|
||||
cache: "no-store"
|
||||
})
|
||||
]);
|
||||
|
||||
const settingsData = await parseJsonResponse<{ settings: Settings }>(settingsResponse);
|
||||
const widgetsData = await parseJsonResponse<{ widgets: Widget[] }>(widgetsResponse);
|
||||
const notesData = await parseJsonResponse<{ notes: NoteBoardItem[] }>(notesResponse);
|
||||
|
||||
const allSourcesResponse = await fetch("/api/calendar/source", {
|
||||
cache: "no-store"
|
||||
});
|
||||
const allSourcesData = await parseJsonResponse<{ sources: CalendarSource[] }>(allSourcesResponse);
|
||||
setCalendarSources(allSourcesData.sources);
|
||||
|
||||
const calendarWidgets = widgetsData.widgets.filter((widget) => widget.type === "calendar");
|
||||
const calendarLoads = await Promise.all(
|
||||
const calendarWidgets = widgets.filter((widget) => widget.type === "calendar");
|
||||
|
||||
if (calendarWidgets.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
const calendarLoads = await Promise.allSettled(
|
||||
calendarWidgets.map(async (widget) => {
|
||||
const [configResponse, eventsResponse] = await Promise.all([
|
||||
fetch(`/api/calendar/source?widgetId=${encodeURIComponent(widget.id)}`, {
|
||||
@@ -439,21 +427,49 @@ export default function DashboardPage() {
|
||||
const nextSelectionsByWidget: Record<string, string[]> = {};
|
||||
const nextEventsCountByWidget: Record<string, number> = {};
|
||||
|
||||
calendarLoads.forEach((calendarLoad) => {
|
||||
nextEventsByWidget[calendarLoad.widgetId] = calendarLoad.events;
|
||||
nextErrorsByWidget[calendarLoad.widgetId] = calendarLoad.error;
|
||||
nextSelectionsByWidget[calendarLoad.widgetId] = calendarLoad.selectedSourceIds;
|
||||
nextEventsCountByWidget[calendarLoad.widgetId] = calendarLoad.nextEventsCount;
|
||||
calendarLoads.forEach((result) => {
|
||||
if (result.status === "fulfilled") {
|
||||
nextEventsByWidget[result.value.widgetId] = result.value.events;
|
||||
nextErrorsByWidget[result.value.widgetId] = result.value.error;
|
||||
nextSelectionsByWidget[result.value.widgetId] = result.value.selectedSourceIds;
|
||||
nextEventsCountByWidget[result.value.widgetId] = result.value.nextEventsCount;
|
||||
}
|
||||
});
|
||||
|
||||
setCalendarEventsByWidget(nextEventsByWidget);
|
||||
setCalendarErrorsByWidget(nextErrorsByWidget);
|
||||
setCalendarSelectionsByWidget(nextSelectionsByWidget);
|
||||
setCalendarNextEventsCountByWidget(nextEventsCountByWidget);
|
||||
} catch {
|
||||
// calendar load failure must not block dashboard
|
||||
}
|
||||
}
|
||||
|
||||
async function loadDashboardData() {
|
||||
setDashboardError(null);
|
||||
|
||||
try {
|
||||
const [settingsResponse, widgetsResponse, notesResponse] = await Promise.all([
|
||||
fetch("/api/settings", {
|
||||
cache: "no-store"
|
||||
}),
|
||||
fetch("/api/widgets", {
|
||||
cache: "no-store"
|
||||
}),
|
||||
fetch("/api/notes", {
|
||||
cache: "no-store"
|
||||
})
|
||||
]);
|
||||
|
||||
const settingsData = await parseJsonResponse<{ settings: Settings }>(settingsResponse);
|
||||
const widgetsData = await parseJsonResponse<{ widgets: Widget[] }>(widgetsResponse);
|
||||
const notesData = await parseJsonResponse<{ notes: NoteBoardItem[] }>(notesResponse);
|
||||
|
||||
setSettings(settingsData.settings);
|
||||
setWidgets(widgetsData.widgets);
|
||||
setNotes(notesData.notes);
|
||||
setCalendarEventsByWidget(nextEventsByWidget);
|
||||
setCalendarErrorsByWidget(nextErrorsByWidget);
|
||||
setCalendarSources(allSourcesData.sources);
|
||||
setCalendarSelectionsByWidget(nextSelectionsByWidget);
|
||||
setCalendarNextEventsCountByWidget(nextEventsCountByWidget);
|
||||
|
||||
void loadCalendarData(widgetsData.widgets);
|
||||
} catch (error) {
|
||||
setDashboardError(error instanceof Error ? error.message : "Dashboard konnte nicht geladen werden.");
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user