feat(20-02): wire SSE subscription hooks into dashboard, detail, and inbox pages
Add useSubscription hooks to all three UI pages that invalidate React
Query caches on domain events:
- Dashboard: onTaskUpdate invalidates listInitiatives + listPhases
- Detail: onTaskUpdate invalidates phases/tasks/plans, onAgentUpdate
invalidates listAgents
- Inbox: onAgentUpdate invalidates listWaitingAgents + listMessages
Subscription failures are silent (onError: () => {}) so pages degrade
gracefully to manual refresh when the backend is not running.
This commit is contained in:
@@ -13,6 +13,16 @@ export const Route = createFileRoute("/inbox")({
|
||||
function InboxPage() {
|
||||
const [selectedAgentId, setSelectedAgentId] = useState<string | null>(null);
|
||||
|
||||
// Live updates: invalidate inbox queries on agent events
|
||||
const utils = trpc.useUtils();
|
||||
trpc.onAgentUpdate.useSubscription(undefined, {
|
||||
onData: () => {
|
||||
void utils.listWaitingAgents.invalidate();
|
||||
void utils.listMessages.invalidate();
|
||||
},
|
||||
onError: () => {},
|
||||
});
|
||||
|
||||
// Data fetching
|
||||
const agentsQuery = trpc.listWaitingAgents.useQuery();
|
||||
const messagesQuery = trpc.listMessages.useQuery({});
|
||||
@@ -22,8 +32,6 @@ function InboxPage() {
|
||||
);
|
||||
|
||||
// Mutations
|
||||
const utils = trpc.useUtils();
|
||||
|
||||
const resumeAgentMutation = trpc.resumeAgent.useMutation({
|
||||
onSuccess: () => {
|
||||
void utils.listWaitingAgents.invalidate();
|
||||
|
||||
@@ -209,6 +209,23 @@ function InitiativeDetailPage() {
|
||||
const { id } = Route.useParams();
|
||||
const navigate = useNavigate();
|
||||
|
||||
// Live updates: invalidate detail queries on task/phase and agent events
|
||||
const utils = trpc.useUtils();
|
||||
trpc.onTaskUpdate.useSubscription(undefined, {
|
||||
onData: () => {
|
||||
void utils.listPhases.invalidate();
|
||||
void utils.listTasks.invalidate();
|
||||
void utils.listPlans.invalidate();
|
||||
},
|
||||
onError: () => {},
|
||||
});
|
||||
trpc.onAgentUpdate.useSubscription(undefined, {
|
||||
onData: () => {
|
||||
void utils.listAgents.invalidate();
|
||||
},
|
||||
onError: () => {},
|
||||
});
|
||||
|
||||
// State
|
||||
const [selectedTaskId, setSelectedTaskId] = useState<string | null>(null);
|
||||
const [taskCountsByPhase, setTaskCountsByPhase] = useState<
|
||||
|
||||
@@ -2,6 +2,7 @@ import { useState } from "react";
|
||||
import { createFileRoute, useNavigate } from "@tanstack/react-router";
|
||||
import { Plus } from "lucide-react";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { trpc } from "@/lib/trpc";
|
||||
import { InitiativeList } from "@/components/InitiativeList";
|
||||
import { CreateInitiativeDialog } from "@/components/CreateInitiativeDialog";
|
||||
|
||||
@@ -23,6 +24,16 @@ function DashboardPage() {
|
||||
const [statusFilter, setStatusFilter] = useState<StatusFilter>("all");
|
||||
const [createDialogOpen, setCreateDialogOpen] = useState(false);
|
||||
|
||||
// Live updates: invalidate dashboard queries on task/phase events
|
||||
const utils = trpc.useUtils();
|
||||
trpc.onTaskUpdate.useSubscription(undefined, {
|
||||
onData: () => {
|
||||
void utils.listInitiatives.invalidate();
|
||||
void utils.listPhases.invalidate();
|
||||
},
|
||||
onError: () => {},
|
||||
});
|
||||
|
||||
return (
|
||||
<div className="space-y-6">
|
||||
{/* Page header */}
|
||||
|
||||
Reference in New Issue
Block a user