refactor(ui): migrate board view to React Query

- Replace manual fetching in use-board-features with useFeatures query
- Migrate use-board-actions to use mutation hooks
- Update kanban-card and agent-info-panel to use query hooks
- Migrate agent-output-modal to useAgentOutput query
- Migrate create-pr-dialog to useCreatePR mutation
- Remove manual loading/error state management
- Add proper cache invalidation on mutations

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
Shirone
2026-01-15 16:21:23 +01:00
parent d08ef472a3
commit 3411256366
7 changed files with 160 additions and 402 deletions

View File

@@ -1,4 +1,4 @@
import { useState, useEffect, useRef, useCallback } from 'react';
import { useState, useEffect, useRef, useCallback, useMemo } from 'react';
import {
Dialog,
DialogContent,
@@ -16,6 +16,7 @@ import { BranchAutocomplete } from '@/components/ui/branch-autocomplete';
import { GitPullRequest, Loader2, ExternalLink } from 'lucide-react';
import { getElectronAPI } from '@/lib/electron';
import { toast } from 'sonner';
import { useWorktreeBranches } from '@/hooks/queries';
interface WorktreeInfo {
path: string;
@@ -53,12 +54,21 @@ export function CreatePRDialog({
const [prUrl, setPrUrl] = useState<string | null>(null);
const [browserUrl, setBrowserUrl] = useState<string | null>(null);
const [showBrowserFallback, setShowBrowserFallback] = useState(false);
// Branch fetching state
const [branches, setBranches] = useState<string[]>([]);
const [isLoadingBranches, setIsLoadingBranches] = useState(false);
// Track whether an operation completed that warrants a refresh
const operationCompletedRef = useRef(false);
// Use React Query for branch fetching - only enabled when dialog is open
const { data: branchesData, isLoading: isLoadingBranches } = useWorktreeBranches(
open ? worktree?.path : undefined,
true // Include remote branches for PR base branch selection
);
// Filter out current worktree branch from the list
const branches = useMemo(() => {
if (!branchesData?.branches) return [];
return branchesData.branches.map((b) => b.name).filter((name) => name !== worktree?.branch);
}, [branchesData?.branches, worktree?.branch]);
// Common state reset function to avoid duplication
const resetState = useCallback(() => {
setTitle('');
@@ -71,44 +81,13 @@ export function CreatePRDialog({
setBrowserUrl(null);
setShowBrowserFallback(false);
operationCompletedRef.current = false;
setBranches([]);
}, [defaultBaseBranch]);
// Fetch branches for autocomplete
const fetchBranches = useCallback(async () => {
if (!worktree?.path) return;
setIsLoadingBranches(true);
try {
const api = getElectronAPI();
if (!api?.worktree?.listBranches) {
return;
}
// Fetch both local and remote branches for PR base branch selection
const result = await api.worktree.listBranches(worktree.path, true);
if (result.success && result.result) {
// Extract branch names, filtering out the current worktree branch
const branchNames = result.result.branches
.map((b) => b.name)
.filter((name) => name !== worktree.branch);
setBranches(branchNames);
}
} catch {
// Silently fail - branches will default to main only
} finally {
setIsLoadingBranches(false);
}
}, [worktree?.path, worktree?.branch]);
// Reset state when dialog opens or worktree changes
useEffect(() => {
// Reset all state on both open and close
resetState();
if (open) {
// Fetch fresh branches when dialog opens
fetchBranches();
}
}, [open, worktree?.path, resetState, fetchBranches]);
}, [open, worktree?.path, resetState]);
const handleCreate = async () => {
if (!worktree) return;