web/lib/use-canopy-events.tsblame
View source
5bcd5db1"use client";
5bcd5db2
5bcd5db3import { useEffect, useRef } from "react";
5bcd5db4
5bcd5db5export type CanopyEventType =
5bcd5db6 | "run:created"
5bcd5db7 | "run:started"
5bcd5db8 | "run:completed"
5bcd5db9 | "run:cancelled"
5bcd5db10 | "step:started"
5bcd5db11 | "step:completed"
5bcd5db12 | "step:skipped"
5bcd5db13 | "log:append";
5bcd5db14
5bcd5db15export interface CanopyEvent {
5bcd5db16 type: CanopyEventType;
5bcd5db17 runId: number;
5bcd5db18 repoId: number;
5bcd5db19 stepId?: number;
5bcd5db20 stepIndex?: number;
5bcd5db21 status?: string;
5bcd5db22 run?: Record<string, unknown>;
5bcd5db23 step?: Record<string, unknown>;
5bcd5db24 log?: { stream: string; content: string; created_at: string };
5bcd5db25 ts: string;
5bcd5db26}
5bcd5db27
5bcd5db28interface UseCanopyEventsOptions {
5bcd5db29 scope: "run" | "repo" | "global";
5bcd5db30 runId?: number;
5bcd5db31 owner?: string;
5bcd5db32 repo?: string;
5bcd5db33 onEvent: (event: CanopyEvent) => void;
5bcd5db34 enabled?: boolean;
5bcd5db35}
5bcd5db36
5bcd5db37export function useCanopyEvents({
5bcd5db38 scope,
5bcd5db39 runId,
5bcd5db40 owner,
5bcd5db41 repo,
5bcd5db42 onEvent,
5bcd5db43 enabled = true,
5bcd5db44}: UseCanopyEventsOptions) {
5bcd5db45 const handlerRef = useRef(onEvent);
5bcd5db46 handlerRef.current = onEvent;
5bcd5db47
5bcd5db48 useEffect(() => {
5bcd5db49 if (!enabled) return;
5bcd5db50
5bcd5db51 const params = new URLSearchParams({ scope });
5bcd5db52 if (runId != null) params.set("runId", String(runId));
5bcd5db53 if (owner) params.set("owner", owner);
5bcd5db54 if (repo) params.set("repo", repo);
5bcd5db55
5bcd5db56 const es = new EventSource(`/api/canopy/events?${params}`);
5bcd5db57
5bcd5db58 const eventTypes: CanopyEventType[] = [
5bcd5db59 "run:created",
5bcd5db60 "run:started",
5bcd5db61 "run:completed",
5bcd5db62 "run:cancelled",
5bcd5db63 "step:started",
5bcd5db64 "step:completed",
5bcd5db65 "step:skipped",
5bcd5db66 "log:append",
5bcd5db67 ];
5bcd5db68
5bcd5db69 for (const type of eventTypes) {
5bcd5db70 es.addEventListener(type, (e: MessageEvent) => {
5bcd5db71 try {
5bcd5db72 const data = JSON.parse(e.data) as CanopyEvent;
5bcd5db73 handlerRef.current(data);
5bcd5db74 } catch {}
5bcd5db75 });
5bcd5db76 }
5bcd5db77
5bcd5db78 return () => es.close();
5bcd5db79 }, [scope, runId, owner, repo, enabled]);
5bcd5db80}