mirror of
https://github.com/AutoMaker-Org/automaker.git
synced 2026-01-31 06:42:03 +00:00
- Use GraphQL variables instead of string interpolation for safety - Add cursor validation to prevent potential GraphQL injection - Add 30s timeout for spawned gh process to prevent hanging - Export ValidationComment and ValidationLinkedPR from validation-schema - Remove duplicate interface definitions from validate-issue.ts - Use ISO date format instead of locale-dependent toLocaleDateString() - Reset error state when issue is deselected in useIssueComments hook 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
135 lines
3.7 KiB
TypeScript
135 lines
3.7 KiB
TypeScript
import { useState, useEffect, useCallback, useRef } from 'react';
|
|
import { getElectronAPI, GitHubComment } from '@/lib/electron';
|
|
import { useAppStore } from '@/store/app-store';
|
|
|
|
interface UseIssueCommentsResult {
|
|
comments: GitHubComment[];
|
|
totalCount: number;
|
|
loading: boolean;
|
|
loadingMore: boolean;
|
|
hasNextPage: boolean;
|
|
error: string | null;
|
|
loadMore: () => void;
|
|
refresh: () => void;
|
|
}
|
|
|
|
export function useIssueComments(issueNumber: number | null): UseIssueCommentsResult {
|
|
const { currentProject } = useAppStore();
|
|
const [comments, setComments] = useState<GitHubComment[]>([]);
|
|
const [totalCount, setTotalCount] = useState(0);
|
|
const [loading, setLoading] = useState(false);
|
|
const [loadingMore, setLoadingMore] = useState(false);
|
|
const [hasNextPage, setHasNextPage] = useState(false);
|
|
const [endCursor, setEndCursor] = useState<string | undefined>(undefined);
|
|
const [error, setError] = useState<string | null>(null);
|
|
const isMountedRef = useRef(true);
|
|
|
|
const fetchComments = useCallback(
|
|
async (cursor?: string) => {
|
|
if (!currentProject?.path || !issueNumber) {
|
|
return;
|
|
}
|
|
|
|
const isLoadingMore = !!cursor;
|
|
|
|
try {
|
|
if (isMountedRef.current) {
|
|
setError(null);
|
|
if (isLoadingMore) {
|
|
setLoadingMore(true);
|
|
} else {
|
|
setLoading(true);
|
|
}
|
|
}
|
|
|
|
const api = getElectronAPI();
|
|
if (api.github) {
|
|
const result = await api.github.getIssueComments(
|
|
currentProject.path,
|
|
issueNumber,
|
|
cursor
|
|
);
|
|
|
|
if (isMountedRef.current) {
|
|
if (result.success) {
|
|
if (isLoadingMore) {
|
|
// Append new comments
|
|
setComments((prev) => [...prev, ...(result.comments || [])]);
|
|
} else {
|
|
// Replace all comments
|
|
setComments(result.comments || []);
|
|
}
|
|
setTotalCount(result.totalCount || 0);
|
|
setHasNextPage(result.hasNextPage || false);
|
|
setEndCursor(result.endCursor);
|
|
} else {
|
|
setError(result.error || 'Failed to fetch comments');
|
|
}
|
|
}
|
|
}
|
|
} catch (err) {
|
|
if (isMountedRef.current) {
|
|
console.error('[useIssueComments] Error fetching comments:', err);
|
|
setError(err instanceof Error ? err.message : 'Failed to fetch comments');
|
|
}
|
|
} finally {
|
|
if (isMountedRef.current) {
|
|
setLoading(false);
|
|
setLoadingMore(false);
|
|
}
|
|
}
|
|
},
|
|
[currentProject?.path, issueNumber]
|
|
);
|
|
|
|
// Reset and fetch when issue changes
|
|
useEffect(() => {
|
|
isMountedRef.current = true;
|
|
|
|
if (issueNumber) {
|
|
// Reset state when issue changes
|
|
setComments([]);
|
|
setTotalCount(0);
|
|
setHasNextPage(false);
|
|
setEndCursor(undefined);
|
|
setError(null);
|
|
fetchComments();
|
|
} else {
|
|
// Clear comments when no issue is selected
|
|
setComments([]);
|
|
setTotalCount(0);
|
|
setHasNextPage(false);
|
|
setEndCursor(undefined);
|
|
setLoading(false);
|
|
setError(null);
|
|
}
|
|
|
|
return () => {
|
|
isMountedRef.current = false;
|
|
};
|
|
}, [issueNumber, fetchComments]);
|
|
|
|
const loadMore = useCallback(() => {
|
|
if (hasNextPage && endCursor && !loadingMore) {
|
|
fetchComments(endCursor);
|
|
}
|
|
}, [hasNextPage, endCursor, loadingMore, fetchComments]);
|
|
|
|
const refresh = useCallback(() => {
|
|
setComments([]);
|
|
setEndCursor(undefined);
|
|
fetchComments();
|
|
}, [fetchComments]);
|
|
|
|
return {
|
|
comments,
|
|
totalCount,
|
|
loading,
|
|
loadingMore,
|
|
hasNextPage,
|
|
error,
|
|
loadMore,
|
|
refresh,
|
|
};
|
|
}
|