mirror of
https://github.com/AutoMaker-Org/automaker.git
synced 2026-02-01 20:23:36 +00:00
fix(ui): add missing cache invalidation for React Query
- Add cache invalidation to useBoardPersistence after create/update/delete - Add useAutoModeQueryInvalidation to board-view for WebSocket events - Add cache invalidation to github-issues-view after converting issue to task - Add cache invalidation to analysis-view after generating features - Fix UI not updating when features are added, updated, or completed Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -1,7 +1,9 @@
|
||||
import { useCallback, useState } from 'react';
|
||||
import { createLogger } from '@automaker/utils/logger';
|
||||
import { useQueryClient } from '@tanstack/react-query';
|
||||
import { useAppStore, FileTreeNode, ProjectAnalysis } from '@/store/app-store';
|
||||
import { getElectronAPI } from '@/lib/electron';
|
||||
import { queryKeys } from '@/lib/query-keys';
|
||||
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import {
|
||||
@@ -72,6 +74,7 @@ export function AnalysisView() {
|
||||
const [isGeneratingFeatureList, setIsGeneratingFeatureList] = useState(false);
|
||||
const [featureListGenerated, setFeatureListGenerated] = useState(false);
|
||||
const [featureListError, setFeatureListError] = useState<string | null>(null);
|
||||
const queryClient = useQueryClient();
|
||||
|
||||
// Recursively scan directory
|
||||
const scanDirectory = useCallback(
|
||||
@@ -647,6 +650,11 @@ ${Object.entries(projectAnalysis.filesByExtension)
|
||||
} as any);
|
||||
}
|
||||
|
||||
// Invalidate React Query cache to sync UI
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: queryKeys.features.all(currentProject.path),
|
||||
});
|
||||
|
||||
setFeatureListGenerated(true);
|
||||
} catch (error) {
|
||||
logger.error('Failed to generate feature list:', error);
|
||||
@@ -656,7 +664,7 @@ ${Object.entries(projectAnalysis.filesByExtension)
|
||||
} finally {
|
||||
setIsGeneratingFeatureList(false);
|
||||
}
|
||||
}, [currentProject, projectAnalysis]);
|
||||
}, [currentProject, projectAnalysis, queryClient]);
|
||||
|
||||
// Toggle folder expansion
|
||||
const toggleFolder = (path: string) => {
|
||||
|
||||
@@ -82,6 +82,7 @@ import { useInitScriptEvents } from '@/hooks/use-init-script-events';
|
||||
import { usePipelineConfig } from '@/hooks/queries';
|
||||
import { useQueryClient } from '@tanstack/react-query';
|
||||
import { queryKeys } from '@/lib/query-keys';
|
||||
import { useAutoModeQueryInvalidation } from '@/hooks/use-query-invalidation';
|
||||
|
||||
// Stable empty array to avoid infinite loop in selector
|
||||
const EMPTY_WORKTREES: ReturnType<ReturnType<typeof useAppStore.getState>['getWorktrees']> = [];
|
||||
@@ -115,6 +116,9 @@ export function BoardView() {
|
||||
// Fetch pipeline config via React Query
|
||||
const { data: pipelineConfig } = usePipelineConfig(currentProject?.path);
|
||||
const queryClient = useQueryClient();
|
||||
|
||||
// Subscribe to auto mode events for React Query cache invalidation
|
||||
useAutoModeQueryInvalidation(currentProject?.path);
|
||||
// Subscribe to worktreePanelVisibleByProject to trigger re-renders when it changes
|
||||
const worktreePanelVisibleByProject = useAppStore((state) => state.worktreePanelVisibleByProject);
|
||||
// Subscribe to showInitScriptIndicatorByProject to trigger re-renders when it changes
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
import { useCallback } from 'react';
|
||||
import { useQueryClient } from '@tanstack/react-query';
|
||||
import { Feature } from '@/store/app-store';
|
||||
import { getElectronAPI } from '@/lib/electron';
|
||||
import { useAppStore } from '@/store/app-store';
|
||||
import { createLogger } from '@automaker/utils/logger';
|
||||
import { queryKeys } from '@/lib/query-keys';
|
||||
|
||||
const logger = createLogger('BoardPersistence');
|
||||
|
||||
@@ -12,6 +14,7 @@ interface UseBoardPersistenceProps {
|
||||
|
||||
export function useBoardPersistence({ currentProject }: UseBoardPersistenceProps) {
|
||||
const { updateFeature } = useAppStore();
|
||||
const queryClient = useQueryClient();
|
||||
|
||||
// Persist feature update to API (replaces saveFeatures)
|
||||
const persistFeatureUpdate = useCallback(
|
||||
@@ -41,12 +44,16 @@ export function useBoardPersistence({ currentProject }: UseBoardPersistenceProps
|
||||
);
|
||||
if (result.success && result.feature) {
|
||||
updateFeature(result.feature.id, result.feature);
|
||||
// Invalidate React Query cache to sync UI
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: queryKeys.features.all(currentProject.path),
|
||||
});
|
||||
}
|
||||
} catch (error) {
|
||||
logger.error('Failed to persist feature update:', error);
|
||||
}
|
||||
},
|
||||
[currentProject, updateFeature]
|
||||
[currentProject, updateFeature, queryClient]
|
||||
);
|
||||
|
||||
// Persist feature creation to API
|
||||
@@ -64,12 +71,16 @@ export function useBoardPersistence({ currentProject }: UseBoardPersistenceProps
|
||||
const result = await api.features.create(currentProject.path, feature);
|
||||
if (result.success && result.feature) {
|
||||
updateFeature(result.feature.id, result.feature);
|
||||
// Invalidate React Query cache to sync UI
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: queryKeys.features.all(currentProject.path),
|
||||
});
|
||||
}
|
||||
} catch (error) {
|
||||
logger.error('Failed to persist feature creation:', error);
|
||||
}
|
||||
},
|
||||
[currentProject, updateFeature]
|
||||
[currentProject, updateFeature, queryClient]
|
||||
);
|
||||
|
||||
// Persist feature deletion to API
|
||||
@@ -85,11 +96,15 @@ export function useBoardPersistence({ currentProject }: UseBoardPersistenceProps
|
||||
}
|
||||
|
||||
await api.features.delete(currentProject.path, featureId);
|
||||
// Invalidate React Query cache to sync UI
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: queryKeys.features.all(currentProject.path),
|
||||
});
|
||||
} catch (error) {
|
||||
logger.error('Failed to persist feature deletion:', error);
|
||||
}
|
||||
},
|
||||
[currentProject]
|
||||
[currentProject, queryClient]
|
||||
);
|
||||
|
||||
return {
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
import { useState, useCallback, useMemo } from 'react';
|
||||
import { createLogger } from '@automaker/utils/logger';
|
||||
import { CircleDot, RefreshCw } from 'lucide-react';
|
||||
import { useQueryClient } from '@tanstack/react-query';
|
||||
import { getElectronAPI, GitHubIssue, IssueValidationResult } from '@/lib/electron';
|
||||
import { useAppStore } from '@/store/app-store';
|
||||
import { ConfirmDialog } from '@/components/ui/confirm-dialog';
|
||||
@@ -9,6 +10,7 @@ import { LoadingState } from '@/components/ui/loading-state';
|
||||
import { ErrorState } from '@/components/ui/error-state';
|
||||
import { cn, pathsEqual } from '@/lib/utils';
|
||||
import { toast } from 'sonner';
|
||||
import { queryKeys } from '@/lib/query-keys';
|
||||
import { useGithubIssues, useIssueValidation } from './github-issues-view/hooks';
|
||||
import { IssueRow, IssueDetailPanel, IssuesListHeader } from './github-issues-view/components';
|
||||
import { ValidationDialog } from './github-issues-view/dialogs';
|
||||
@@ -27,6 +29,7 @@ export function GitHubIssuesView() {
|
||||
useState<ValidateIssueOptions | null>(null);
|
||||
|
||||
const { currentProject, getCurrentWorktree, worktreesByProject } = useAppStore();
|
||||
const queryClient = useQueryClient();
|
||||
|
||||
// Model override for validation
|
||||
const validationModelOverride = useModelOverride({ phase: 'validationModel' });
|
||||
@@ -109,6 +112,10 @@ export function GitHubIssuesView() {
|
||||
|
||||
const result = await api.features.create(currentProject.path, feature);
|
||||
if (result.success) {
|
||||
// Invalidate React Query cache to sync UI
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: queryKeys.features.all(currentProject.path),
|
||||
});
|
||||
toast.success(`Created task: ${issue.title}`);
|
||||
} else {
|
||||
toast.error(result.error || 'Failed to create task');
|
||||
@@ -119,7 +126,7 @@ export function GitHubIssuesView() {
|
||||
toast.error(err instanceof Error ? err.message : 'Failed to create task');
|
||||
}
|
||||
},
|
||||
[currentProject?.path, currentBranch]
|
||||
[currentProject?.path, currentBranch, queryClient]
|
||||
);
|
||||
|
||||
if (loading) {
|
||||
|
||||
Reference in New Issue
Block a user