Pre-launch — Gluecron is in final validation. Public signups and git hosting for non-owner users open after launch review.
CodeIssuesPull RequestsActionsSecurityInsightsSettings
✨ AI
More
Blame · Line-by-line history

useGates.ts

Each line is annotated with the commit that last touched it. Click any SHA to jump to that commit and see the surrounding change.

useGates.tsBlame87 lines · 1 contributor
9989d86Claude1import { useCallback, useEffect, useState } from 'react';
2import { listGateRuns, triggerGateRun } from '../api/gates';
3import type { GateRun } from '../api/gates';
4
5export interface UseGatesReturn {
6 runs: GateRun[];
7 isLoading: boolean;
8 error: string | null;
9 isTriggering: boolean;
10 triggerRun: () => Promise<void>;
11 loadMore: () => void;
12 hasMore: boolean;
13 refresh: () => void;
14}
15
16/**
17 * Fetches gate runs for a repository with pagination and a manual trigger action.
18 */
19export function useGates(owner: string, repoName: string): UseGatesReturn {
20 const [runs, setRuns] = useState<GateRun[]>([]);
21 const [page, setPage] = useState(1);
22 const [isLoading, setIsLoading] = useState(true);
23 const [error, setError] = useState<string | null>(null);
24 const [hasMore, setHasMore] = useState(true);
25 const [isTriggering, setIsTriggering] = useState(false);
26 const [tick, setTick] = useState(0);
27
28 useEffect(() => {
29 if (!owner || !repoName) return;
30 let cancelled = false;
31
32 setIsLoading(true);
33 setError(null);
34
35 listGateRuns(owner, repoName, page)
36 .then((data) => {
37 if (!cancelled) {
38 if (page === 1) {
39 setRuns(data);
40 } else {
41 setRuns((prev) => [...prev, ...data]);
42 }
43 // Assume pages of 30
44 setHasMore(data.length === 30);
45 }
46 })
47 .catch((err) => {
48 if (!cancelled) {
49 setError(err instanceof Error ? err.message : 'Failed to load gate runs');
50 }
51 })
52 .finally(() => {
53 if (!cancelled) setIsLoading(false);
54 });
55
56 return () => {
57 cancelled = true;
58 };
59 }, [owner, repoName, page, tick]);
60
61 const loadMore = useCallback(() => {
62 if (!isLoading && hasMore) {
63 setPage((p) => p + 1);
64 }
65 }, [isLoading, hasMore]);
66
67 const refresh = useCallback(() => {
68 setPage(1);
69 setTick((t) => t + 1);
70 }, []);
71
72 const triggerRun = useCallback(async () => {
73 if (isTriggering) return;
74 setIsTriggering(true);
75 setError(null);
76 try {
77 const newRun = await triggerGateRun(owner, repoName);
78 setRuns((prev) => [newRun, ...prev]);
79 } catch (err) {
80 setError(err instanceof Error ? err.message : 'Failed to trigger gate run');
81 } finally {
82 setIsTriggering(false);
83 }
84 }, [owner, repoName, isTriggering]);
85
86 return { runs, isLoading, error, isTriggering, triggerRun, loadMore, hasMore, refresh };
87}