Skip to content

Fix archived tasks visibility and real-time updates #1130

Merged
arnestrickmann merged 6 commits intogeneralaction:mainfrom
thisisharsh7:fix/project-main-view-ui
Feb 27, 2026
Merged

Fix archived tasks visibility and real-time updates #1130
arnestrickmann merged 6 commits intogeneralaction:mainfrom
thisisharsh7:fix/project-main-view-ui

Conversation

@thisisharsh7
Copy link
Contributor

@thisisharsh7 thisisharsh7 commented Feb 26, 2026

  1. Archiving all the task shows nothing on main task UI ( Fixed controls not appearing when all tasks are archived )

before :
Screenshot 2026-02-27 at 6 17 03 AM

after:
Screenshot 2026-02-27 at 6 20 29 AM

  1. When I am archiving the task and I select the all all task filter when archiving it should just archive it shouldn't get hide since I am using the filter all task

before:

Screen.Recording.2026-02-27.at.6.24.47.AM.mov

after:

Screen.Recording.2026-02-27.at.6.28.44.AM.mov
  1. When I am deleting the archived task and I select the all task filter when deleting it, it doesn't remove from the ui until refresh

Before:

Screen.Recording.2026-02-27.at.6.33.22.AM.mov

After:

Screen.Recording.2026-02-27.at.6.31.41.AM.mov

@vercel
Copy link

vercel bot commented Feb 26, 2026

@thisisharsh7 is attempting to deploy a commit to the General Action Team on Vercel.

A member of the Team first needs to authorize it.

@greptile-apps
Copy link

greptile-apps bot commented Feb 26, 2026

Greptile Summary

This PR refactors how archived tasks are fetched and displayed in the UI. The changes introduce hasAnyTasks to control when search/filter controls are shown, add conditional rendering for the "Select" button, and create a helpful empty state message when all tasks are archived.

Key changes:

  • Refactored archived tasks fetching from conditional (only when showFilter === 'all') to always-on with activeTasksLength dependency
  • Added hasAnyTasks variable to show controls when any tasks exist (active or archived)
  • Added empty state UI when filteredTasks.length === 0 with contextual messages
  • Wrapped onDeleteTask in handleDeleteTask to refetch archived tasks when archived tasks are deleted

Issues found:

  • Race condition: refetchArchivedTasks uses setTimeout without cancellation mechanism, which could cause stale updates or updates on unmounted components
  • Performance: Archived tasks are now fetched even when viewing only active tasks (wasteful API calls)
  • Double fetching: Explicit refetchArchivedTasks() calls after archive/delete operations trigger alongside the useEffect dependency on activeTasksLength

Confidence Score: 3/5

  • This PR has functional improvements but contains a race condition bug and performance inefficiencies that should be addressed
  • The changes successfully improve UI behavior for archived tasks visibility, but the refactored refetchArchivedTasks function has a race condition due to missing cancellation mechanism in setTimeout. Additionally, archived tasks are now fetched unnecessarily when viewing only active tasks, and double-fetching occurs after archive/delete operations. While these issues don't break core functionality, they should be fixed to prevent potential bugs and optimize performance.
  • Pay close attention to src/renderer/components/ProjectMainView.tsx lines 339-354 for the race condition and inefficient fetching logic

Important Files Changed

Filename Overview
src/renderer/components/ProjectMainView.tsx Refactored archived tasks fetching logic and improved UI visibility controls, but introduced race condition and performance inefficiencies

Last reviewed commit: cf07fcc

Copy link

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1 file reviewed, 4 comments

Edit Code Review Agent Settings | Greptile

Comment on lines 339 to 350
const refetchArchivedTasks = useCallback(() => {
setTimeout(async () => {
try {
const result = await window.electronAPI.getArchivedTasks(project.id);
if (!cancelled && Array.isArray(result)) {
if (Array.isArray(result)) {
setArchivedTasks(result);
}
} catch {
// silently ignore
}
}
void fetchArchived();
return () => {
cancelled = true;
};
}, [showFilter, project.id]);
}, 100);
}, [project.id]);
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

missing cancellation mechanism in setTimeout can cause race conditions

The previous implementation had a cancelled flag to prevent stale updates. Without it:

  • If the component unmounts during the 100ms delay, setArchivedTasks will be called on an unmounted component
  • If multiple rapid refetch calls occur, race conditions could cause stale data to override newer data
Suggested change
const refetchArchivedTasks = useCallback(() => {
setTimeout(async () => {
try {
const result = await window.electronAPI.getArchivedTasks(project.id);
if (!cancelled && Array.isArray(result)) {
if (Array.isArray(result)) {
setArchivedTasks(result);
}
} catch {
// silently ignore
}
}
void fetchArchived();
return () => {
cancelled = true;
};
}, [showFilter, project.id]);
}, 100);
}, [project.id]);
const refetchArchivedTasks = useCallback(() => {
const timeoutId = setTimeout(async () => {
try {
const result = await window.electronAPI.getArchivedTasks(project.id);
if (Array.isArray(result)) {
setArchivedTasks(result);
}
} catch {
// silently ignore
}
}, 100);
return () => clearTimeout(timeoutId);
}, [project.id]);

Then handle cleanup in the useEffect.

Comment on lines 352 to 354
useEffect(() => {
refetchArchivedTasks();
}, [project.id, activeTasksLength, refetchArchivedTasks]);
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

archived tasks are fetched even when showFilter === 'active', wasting resources

The previous implementation only fetched archived tasks when needed (showFilter === 'all'). Now they're always fetched whenever activeTasksLength changes, even when the user is only viewing active tasks.

Consider adding showFilter to the dependency array and only fetching when needed:

Suggested change
useEffect(() => {
refetchArchivedTasks();
}, [project.id, activeTasksLength, refetchArchivedTasks]);
useEffect(() => {
if (showFilter === 'all') {
refetchArchivedTasks();
} else {
setArchivedTasks([]);
}
}, [project.id, activeTasksLength, showFilter, refetchArchivedTasks]);

exitSelectMode();

if (deletedNames.length > 0) {
refetchArchivedTasks();
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

double refetch - both explicit call here and useEffect (line 352) will trigger when activeTasksLength changes after deletion

exitSelectMode();

if (archivedNames.length > 0) {
refetchArchivedTasks();
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

double refetch - both explicit call here and useEffect (line 352) will trigger when activeTasksLength changes after archiving

@arnestrickmann
Copy link
Contributor

Hi @thisisharsh7,
Thanks for opening this PR.

From the description it is quite hard to understand what this PR does and what is being fixed.

Would love another description.

@yashdev9274
Copy link

hey, this PR needs a few fixes before merging:

  1. refetchArchivedTasks lacks cleanup - can cause state updates on unmounted components
  2. Double refetch after delete/archive (explicit call + useEffect both trigger)
  3. Archived tasks fetched even when filter is 'active'

i've added a review for reference

@arnestrickmann
Copy link
Contributor

@yashdev9274 thank you!

@arnestrickmann
Copy link
Contributor

Thanks for the quick turnaround! @thisisharsh7

@arnestrickmann
Copy link
Contributor

very good catch! @thisisharsh7

@arnestrickmann arnestrickmann merged commit a56a393 into generalaction:main Feb 27, 2026
2 of 3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants