fix(#298): Fix async response handling in dashboard
Some checks failed
ci/woodpecker/push/woodpecker Pipeline failed
Some checks failed
ci/woodpecker/push/woodpecker Pipeline failed
Replaced setTimeout hacks with proper polling mechanism: - Added pollForQueryResponse() function with configurable polling interval - Polls every 500ms with 30s timeout - Properly handles DELIVERED and FAILED message states - Throws errors for failures and timeouts Updated dashboard to use polling instead of arbitrary delays: - Removed setTimeout(resolve, 1000) hacks - Added proper async/await for query responses - Improved response data parsing for new query format - Better error handling via polling exceptions This fixes race conditions and unreliable data loading. Fixes #298 Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -13,7 +13,7 @@ import {
|
||||
FederationConnectionStatus,
|
||||
type ConnectionDetails,
|
||||
} from "@/lib/api/federation";
|
||||
import { sendFederatedQuery } from "@/lib/api/federation-queries";
|
||||
import { sendFederatedQuery, pollForQueryResponse } from "@/lib/api/federation-queries";
|
||||
import type { Task, Event } from "@mosaic/shared";
|
||||
|
||||
export default function AggregatedDashboardPage(): React.JSX.Element {
|
||||
@@ -50,18 +50,19 @@ export default function AggregatedDashboardPage(): React.JSX.Element {
|
||||
try {
|
||||
// Query tasks
|
||||
if (connection.remoteCapabilities.supportsQuery) {
|
||||
const taskResponse = await sendFederatedQuery(connection.id, "tasks.list", {
|
||||
const taskQueryMessage = await sendFederatedQuery(connection.id, "get tasks", {
|
||||
limit: 10,
|
||||
});
|
||||
|
||||
// Wait a bit for the query to be processed and response received
|
||||
// In production, this would use WebSocket or polling
|
||||
await new Promise((resolve) => setTimeout(resolve, 1000));
|
||||
// Poll for the response instead of using setTimeout
|
||||
const taskResponse = await pollForQueryResponse(taskQueryMessage.id, {
|
||||
pollInterval: 500,
|
||||
timeout: 30000,
|
||||
});
|
||||
|
||||
// For MVP, we'll use mock data since query processing is async
|
||||
// In production, we'd poll for the response or use WebSocket
|
||||
if (taskResponse.response) {
|
||||
const responseTasks = (taskResponse.response as { data?: Task[] }).data ?? [];
|
||||
const responseData = taskResponse.response as { type?: string; data?: Task[] };
|
||||
const responseTasks = responseData.data ?? [];
|
||||
const federatedTasks = responseTasks.map((task) => ({
|
||||
task,
|
||||
provenance: {
|
||||
@@ -76,14 +77,19 @@ export default function AggregatedDashboardPage(): React.JSX.Element {
|
||||
}
|
||||
|
||||
// Query events
|
||||
const eventResponse = await sendFederatedQuery(connection.id, "events.list", {
|
||||
const eventQueryMessage = await sendFederatedQuery(connection.id, "get events", {
|
||||
limit: 10,
|
||||
});
|
||||
|
||||
await new Promise((resolve) => setTimeout(resolve, 1000));
|
||||
// Poll for the response
|
||||
const eventResponse = await pollForQueryResponse(eventQueryMessage.id, {
|
||||
pollInterval: 500,
|
||||
timeout: 30000,
|
||||
});
|
||||
|
||||
if (eventResponse.response) {
|
||||
const responseEvents = (eventResponse.response as { data?: Event[] }).data ?? [];
|
||||
const responseData = eventResponse.response as { type?: string; data?: Event[] };
|
||||
const responseEvents = responseData.data ?? [];
|
||||
const federatedEvents = responseEvents.map((event) => ({
|
||||
event,
|
||||
provenance: {
|
||||
|
||||
Reference in New Issue
Block a user