Reduce API calls on FE (#258)

* remove unnecessary /branches call

* remove unnecessary dependency on active tab and user selected tab

* remove duplicate fetch attempt data and execution state
This commit is contained in:
Anastasiia Solop
2025-07-19 16:02:03 +02:00
committed by GitHub
parent 975fc901e1
commit 0e91ecd016
4 changed files with 9 additions and 69 deletions

View File

@@ -38,19 +38,13 @@ const TaskDetailsProvider: FC<{
task: TaskWithAttemptStatus;
projectId: string;
children: ReactNode;
activeTab: 'logs' | 'diffs' | 'related';
setActiveTab: Dispatch<SetStateAction<'logs' | 'diffs' | 'related'>>;
setShowEditorDialog: Dispatch<SetStateAction<boolean>>;
userSelectedTab: boolean;
projectHasDevScript?: boolean;
}> = ({
task,
projectId,
children,
activeTab,
setActiveTab,
setShowEditorDialog,
userSelectedTab,
projectHasDevScript,
}) => {
const [loading, setLoading] = useState(false);
@@ -84,7 +78,6 @@ const TaskDetailsProvider: FC<{
allLogs: [], // new field for all logs
});
const diffLoadingRef = useRef(false);
const relatedTasksLoadingRef = useRef(false);
const fetchRelatedTasks = useCallback(async () => {
@@ -127,12 +120,6 @@ const TaskDetailsProvider: FC<{
return;
}
// Prevent multiple concurrent requests
if (diffLoadingRef.current) {
return;
}
diffLoadingRef.current = true;
if (isBackgroundRefresh) {
setIsBackgroundRefreshing(true);
} else {
@@ -154,7 +141,6 @@ const TaskDetailsProvider: FC<{
console.error('Failed to load diff:', err);
setDiffError('Failed to load diff');
} finally {
diffLoadingRef.current = false;
if (isBackgroundRefresh) {
setIsBackgroundRefreshing(false);
} else {
@@ -165,10 +151,6 @@ const TaskDetailsProvider: FC<{
[projectId, selectedAttempt?.id, selectedAttempt?.task_id]
);
useEffect(() => {
fetchDiff();
}, [fetchDiff]);
useEffect(() => {
if (selectedAttempt && task) {
fetchRelatedTasks();
@@ -318,7 +300,7 @@ const TaskDetailsProvider: FC<{
fetchAttemptData(selectedAttempt.id, selectedAttempt.task_id);
fetchExecutionState(selectedAttempt.id, selectedAttempt.task_id);
}
}, 2000);
}, 5000);
return () => clearInterval(interval);
}, [
@@ -355,32 +337,12 @@ const TaskDetailsProvider: FC<{
useEffect(() => {
if (!executionState?.execution_state || !selectedAttempt) return;
const isCodingAgentComplete =
executionState.execution_state === 'CodingAgentComplete';
const isCodingAgentFailed =
executionState.execution_state === 'CodingAgentFailed';
const isComplete = executionState.execution_state === 'Complete';
const hasChanges = executionState.has_changes;
// Fetch diff when coding agent completes, fails, or task is complete and has changes
if (
(isCodingAgentComplete || isCodingAgentFailed || isComplete) &&
hasChanges
) {
fetchDiff();
// Auto-switch to diffs tab when changes are detected, but only if user hasn't manually selected a tab
if (activeTab === 'logs' && !userSelectedTab) {
setActiveTab('diffs');
}
}
fetchDiff();
}, [
executionState?.execution_state,
executionState?.has_changes,
selectedAttempt,
fetchDiff,
activeTab,
userSelectedTab,
setActiveTab,
]);
const value = useMemo(

View File

@@ -8,10 +8,9 @@ import {
type Props = {
activeTab: 'logs' | 'diffs' | 'related';
setActiveTab: (tab: 'logs' | 'diffs' | 'related') => void;
setUserSelectedTab: (tab: boolean) => void;
};
function TabNavigation({ activeTab, setActiveTab, setUserSelectedTab }: Props) {
function TabNavigation({ activeTab, setActiveTab }: Props) {
const { diff } = useContext(TaskDiffContext);
const { totalRelatedCount } = useContext(TaskRelatedTasksContext);
return (
@@ -19,9 +18,7 @@ function TabNavigation({ activeTab, setActiveTab, setUserSelectedTab }: Props) {
<div className="flex px-4">
<button
onClick={() => {
console.log('Logs tab clicked - setting activeTab to logs');
setActiveTab('logs');
setUserSelectedTab(true);
}}
className={`flex items-center px-4 py-2 text-sm font-medium border-b-2 transition-colors ${
activeTab === 'logs'
@@ -34,9 +31,7 @@ function TabNavigation({ activeTab, setActiveTab, setUserSelectedTab }: Props) {
</button>
<button
onClick={() => {
console.log('Diffs tab clicked - setting activeTab to diffs');
setActiveTab('diffs');
setUserSelectedTab(true);
}}
className={`flex items-center px-4 py-2 text-sm font-medium border-b-2 transition-colors ${
activeTab === 'diffs'
@@ -54,11 +49,7 @@ function TabNavigation({ activeTab, setActiveTab, setUserSelectedTab }: Props) {
</button>
<button
onClick={() => {
console.log(
'Related Tasks tab clicked - setting activeTab to related'
);
setActiveTab('related');
setUserSelectedTab(true);
}}
className={`flex items-center px-4 py-2 text-sm font-medium border-b-2 transition-colors ${
activeTab === 'related'

View File

@@ -40,13 +40,11 @@ export function TaskDetailsPanel({
const [activeTab, setActiveTab] = useState<'logs' | 'diffs' | 'related'>(
'logs'
);
const [userSelectedTab, setUserSelectedTab] = useState<boolean>(false);
// Reset to logs tab when task changes
useEffect(() => {
if (task?.id) {
setActiveTab('logs');
setUserSelectedTab(true); // Treat this as a user selection to prevent auto-switching
}
}, [task?.id]);
@@ -74,9 +72,6 @@ export function TaskDetailsPanel({
task={task}
projectId={projectId}
setShowEditorDialog={setShowEditorDialog}
activeTab={activeTab}
setActiveTab={setActiveTab}
userSelectedTab={userSelectedTab}
projectHasDevScript={projectHasDevScript}
>
{/* Backdrop - only on smaller screens (overlay mode) */}
@@ -96,7 +91,6 @@ export function TaskDetailsPanel({
<TabNavigation
activeTab={activeTab}
setActiveTab={setActiveTab}
setUserSelectedTab={setUserSelectedTab}
/>
{/* Tab Content */}

View File

@@ -5,13 +5,12 @@ import { Button } from '@/components/ui/button';
import { useConfig } from '@/components/config-provider';
import { attemptsApi, projectsApi } from '@/lib/api';
import type { GitBranch, TaskAttempt } from 'shared/types';
import { EXECUTOR_TYPES, EXECUTOR_LABELS } from 'shared/types';
import { EXECUTOR_LABELS, EXECUTOR_TYPES } from 'shared/types';
import {
TaskAttemptDataContext,
TaskAttemptLoadingContext,
TaskAttemptStoppingContext,
TaskDetailsContext,
TaskExecutionStateContext,
TaskSelectedAttemptContext,
} from '@/components/context/taskDetailsContext.ts';
import CreatePRDialog from '@/components/tasks/Toolbar/CreatePRDialog.tsx';
@@ -31,10 +30,9 @@ function TaskDetailsToolbar() {
);
const { isStopping } = useContext(TaskAttemptStoppingContext);
const { fetchAttemptData, setAttemptData, isAttemptRunning } = useContext(
const { setAttemptData, isAttemptRunning } = useContext(
TaskAttemptDataContext
);
const { fetchExecutionState } = useContext(TaskExecutionStateContext);
const [taskAttempts, setTaskAttempts] = useState<TaskAttempt[]>([]);
const location = useLocation();
@@ -67,10 +65,10 @@ function TaskDetailsToolbar() {
setBranches(result);
// Set current branch as default
const currentBranch = result.find((b) => b.is_current);
if (currentBranch && !selectedBranch) {
setSelectedBranch(currentBranch.name);
if (currentBranch) {
setSelectedBranch((prev) => (!prev ? currentBranch.name : prev));
}
}, [projectId, selectedBranch]);
}, [projectId]);
useEffect(() => {
fetchProjectBranches();
@@ -163,11 +161,6 @@ function TaskDetailsToolbar() {
return prev;
return selectedAttemptToUse;
});
fetchAttemptData(selectedAttemptToUse.id, selectedAttemptToUse.task_id);
fetchExecutionState(
selectedAttemptToUse.id,
selectedAttemptToUse.task_id
);
} else {
setSelectedAttempt(null);
setAttemptData({
@@ -181,7 +174,7 @@ function TaskDetailsToolbar() {
} finally {
setLoading(false);
}
}, [task, projectId, fetchAttemptData, fetchExecutionState, location.search]);
}, [task, projectId, location.search]);
useEffect(() => {
fetchTaskAttempts();