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() {
|
async function loadCalendarData(widgets: Widget[]) {
|
||||||
setDashboardError(null);
|
|
||||||
|
|
||||||
try {
|
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", {
|
const allSourcesResponse = await fetch("/api/calendar/source", {
|
||||||
cache: "no-store"
|
cache: "no-store"
|
||||||
});
|
});
|
||||||
const allSourcesData = await parseJsonResponse<{ sources: CalendarSource[] }>(allSourcesResponse);
|
const allSourcesData = await parseJsonResponse<{ sources: CalendarSource[] }>(allSourcesResponse);
|
||||||
|
setCalendarSources(allSourcesData.sources);
|
||||||
|
|
||||||
const calendarWidgets = widgetsData.widgets.filter((widget) => widget.type === "calendar");
|
const calendarWidgets = widgets.filter((widget) => widget.type === "calendar");
|
||||||
const calendarLoads = await Promise.all(
|
|
||||||
|
if (calendarWidgets.length === 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const calendarLoads = await Promise.allSettled(
|
||||||
calendarWidgets.map(async (widget) => {
|
calendarWidgets.map(async (widget) => {
|
||||||
const [configResponse, eventsResponse] = await Promise.all([
|
const [configResponse, eventsResponse] = await Promise.all([
|
||||||
fetch(`/api/calendar/source?widgetId=${encodeURIComponent(widget.id)}`, {
|
fetch(`/api/calendar/source?widgetId=${encodeURIComponent(widget.id)}`, {
|
||||||
@@ -439,21 +427,49 @@ export default function DashboardPage() {
|
|||||||
const nextSelectionsByWidget: Record<string, string[]> = {};
|
const nextSelectionsByWidget: Record<string, string[]> = {};
|
||||||
const nextEventsCountByWidget: Record<string, number> = {};
|
const nextEventsCountByWidget: Record<string, number> = {};
|
||||||
|
|
||||||
calendarLoads.forEach((calendarLoad) => {
|
calendarLoads.forEach((result) => {
|
||||||
nextEventsByWidget[calendarLoad.widgetId] = calendarLoad.events;
|
if (result.status === "fulfilled") {
|
||||||
nextErrorsByWidget[calendarLoad.widgetId] = calendarLoad.error;
|
nextEventsByWidget[result.value.widgetId] = result.value.events;
|
||||||
nextSelectionsByWidget[calendarLoad.widgetId] = calendarLoad.selectedSourceIds;
|
nextErrorsByWidget[result.value.widgetId] = result.value.error;
|
||||||
nextEventsCountByWidget[calendarLoad.widgetId] = calendarLoad.nextEventsCount;
|
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);
|
setSettings(settingsData.settings);
|
||||||
setWidgets(widgetsData.widgets);
|
setWidgets(widgetsData.widgets);
|
||||||
setNotes(notesData.notes);
|
setNotes(notesData.notes);
|
||||||
setCalendarEventsByWidget(nextEventsByWidget);
|
|
||||||
setCalendarErrorsByWidget(nextErrorsByWidget);
|
void loadCalendarData(widgetsData.widgets);
|
||||||
setCalendarSources(allSourcesData.sources);
|
|
||||||
setCalendarSelectionsByWidget(nextSelectionsByWidget);
|
|
||||||
setCalendarNextEventsCountByWidget(nextEventsCountByWidget);
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
setDashboardError(error instanceof Error ? error.message : "Dashboard konnte nicht geladen werden.");
|
setDashboardError(error instanceof Error ? error.message : "Dashboard konnte nicht geladen werden.");
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user