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