feat(FN-1850): aggregate projects across connected nodes

- Add /api/projects/across-nodes to merge local projects with online remote node project lists
- Expose fetchProjectsAcrossNodes and ProjectInfoWithSource, and switch useProjects to consume cross-node data
- Update ProjectOverview and ProjectCard with node badges, node count stats, and a node filter dropdown plus responsive styles
- Add server and dashboard test coverage for cross-node aggregation, filtering, and hook behavior changes
- Include a changeset for @gsxdsm/fusion minor release and preserve stale-channel SSE reconnect guards during merge
This commit is contained in:
Fusion
2026-04-18 03:08:00 -07:00
committed by gsxdsm
parent 76123c9538
commit 53babb3524
14 changed files with 1674 additions and 55 deletions

View File

@@ -170,6 +170,9 @@ export function useTasks(options?: UseTasksOptions) {
// (e.g., sseEnabled flipped to false during a pending reconnect timer in sse-bus).
let active = true;
// Guard against stale callbacks: when sseEnabled flips false or the
// effect unmounts, these handlers must not fire refreshTasks into a
// missions-only view where the SSE should be inactive.
const handleCreated = (e: MessageEvent) => {
if (isStale()) return;
const task = normalizeTask(JSON.parse(e.data) as Task);
@@ -267,6 +270,8 @@ export function useTasks(options?: UseTasksOptions) {
"task:deleted": handleDeleted,
"task:merged": handleMerged,
},
// Guard onReconnect against stale SSE callbacks: do not call refreshTasks
// if the SSE was disabled or the effect unmounted while reconnect was pending.
onReconnect: () => {
if (!active) return;
if (isStale()) return;