Skip to content

starting new tasks should refresh#83

Merged
Kitenite merged 2 commits intomainfrom
starting-new-tasks-should-refresh-86cf
Nov 15, 2025
Merged

starting new tasks should refresh#83
Kitenite merged 2 commits intomainfrom
starting-new-tasks-should-refresh-86cf

Conversation

@Kitenite
Copy link
Copy Markdown
Collaborator

@Kitenite Kitenite commented Nov 15, 2025

Summary by CodeRabbit

  • Refactor
    • Enhanced internal state management for workspace and worktree operations to safely handle concurrent updates and prevent stale closures in React components.
    • Refined the worktree creation workflow for more reliable state synchronization across application components.
    • Optimized async operation handling to reduce unnecessary external system calls and improve application efficiency.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Nov 15, 2025

Caution

Review failed

The pull request is closed.

Walkthrough

The PR refactors worktree creation handling by introducing a return value from handleWorktreeCreated to pass the refreshed workspace, replacing direct state mutations with functional updates in useTabs, and updating type signatures across three hooks to reflect these changes.

Changes

Cohort / File(s) Summary
Task management wiring
apps/desktop/src/renderer/screens/main/MainScreen.tsx
Added handleWorktreeCreatedWithResult alias from useWorktrees hook and wired it into useTasks to pass the refreshed workspace; kept original handleWorktreeCreated binding for external SidebarOverlay and MainContentArea props.
Functional state updates
apps/desktop/src/renderer/screens/main/hooks/useTabs.ts
Replaced direct state mutations with functional state updates (setCurrentWorkspace((prev) => {...})) in handleTabCreated, handleTabSelect, and handleTabFocus; updated setCurrentWorkspace type from concrete callback to React.Dispatch<React.SetStateAction<Workspace | null>>.
Worktree creation return value
apps/desktop/src/renderer/screens/main/hooks/useTasks.ts
Changed handleWorktreeCreated signature to return Promise<{ id: string; worktrees?: Worktree[] } | null>; updated task creation flow to capture and use returned refreshedWorkspace instead of re-fetching via IPC, with a short delay for state propagation.
Hook signature and wrapper logic
apps/desktop/src/renderer/screens/main/hooks/useWorktrees.ts
Updated setCurrentWorkspace type to React.Dispatch<React.SetStateAction<Workspace | null>>; modified handleWorktreeCreated to return Promise<Workspace | null> with refreshed workspace; introduced internal handleWorktreeCreatedVoid wrapper; exposed new public alias handleWorktreeCreatedWithResult.

Sequence Diagram

sequenceDiagram
    participant MainScreen
    participant useTasks
    participant useWorktrees
    participant API as IPC/Backend

    rect rgb(200, 220, 240)
    Note over MainScreen,API: Before: handleWorktreeCreated returns void
    MainScreen->>useTasks: handleWorktreeCreated (Promise<void>)
    useTasks->>useWorktrees: handleWorktreeCreated()
    useWorktrees->>API: Create worktree
    API-->>useWorktrees: Success
    useWorktrees->>useWorktrees: Update state
    useWorktrees-->>useTasks: void
    useTasks->>API: Re-fetch latestWorkspace (redundant)
    API-->>useTasks: Workspace
    useTasks-->>MainScreen: void
    end

    rect rgb(220, 240, 200)
    Note over MainScreen,API: After: handleWorktreeCreated returns refreshed workspace
    MainScreen->>useTasks: handleWorktreeCreatedWithResult()
    useTasks->>useWorktrees: handleWorktreeCreated()
    useWorktrees->>API: Create worktree
    API-->>useWorktrees: Success
    useWorktrees->>useWorktrees: Update state
    useWorktrees-->>useTasks: Workspace | null (refreshedWorkspace)
    useTasks->>useTasks: Wait for state propagation
    useTasks-->>MainScreen: refreshedWorkspace
    end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Areas requiring extra attention:

  • Functional state update pattern in useTabs.ts: Verify that all setCurrentWorkspace((prev) => {...}) patterns correctly handle null states and preserve prior state atomically
  • Return value handling in useTasks.ts and useWorktrees.ts: Ensure refreshed workspace is reliably captured and the short delay for state propagation doesn't introduce race conditions
  • Wrapper and alias logic in useWorktrees.ts: Confirm handleWorktreeCreatedVoid and handleWorktreeCreatedWithResult are correctly wired in the hook return object
  • Type signature consistency: Verify all callers of updated signatures (setCurrentWorkspace, handleWorktreeCreated) are compatible with new types and no casting is needed

Possibly related PRs

  • workspace #71: Modifies the same files and symbols (MainScreen.tsx, useWorktrees, useTasks, useTabs) and changes the handleWorktreeCreated signature and task management wiring.
  • Tabs creation and management #78: Updates the main screen hooks (useWorktrees and useTasks) and the public hook API around worktree handling.
  • start tasks and top bar #81: Modifies the task creation flow in useTasks.ts to handle worktree creation with the same handleWorktreeCreated return value and state propagation logic.

Poem

🐰 A hop through state with care so keen,
Functional updates keep closures clean,
Now worktrees whisper what they've seen,
Returning wisdom, not just void—serene!
Through hooks we dance, each promise keeping true.

Pre-merge checks and finishing touches

❌ Failed checks (2 warnings)
Check name Status Explanation Resolution
Description check ⚠️ Warning The PR description is largely incomplete, missing required sections like a detailed description, related issues, type of change classification, testing details, and additional context. Fill in the required template sections: provide a clear description of the changes, link related issues, select the type of change, describe testing performed, and add any relevant context.
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (1 passed)
Check name Status Explanation
Title check ✅ Passed The title 'starting new tasks should refresh 86cf' is directly related to the main change: implementing functionality where creating a new worktree/task triggers a workspace refresh with the updated data.

📜 Recent review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between fd1d64e and c8ea632.

📒 Files selected for processing (1)
  • apps/desktop/src/renderer/screens/main/MainScreen.tsx (2 hunks)

Comment @coderabbitai help to get the list of available commands and usage tips.

@Kitenite Kitenite changed the title starting new tasks should refresh 86cf starting new tasks should refresh Nov 15, 2025
@Kitenite Kitenite merged commit faeb587 into main Nov 15, 2025
1 of 4 checks passed
@Kitenite Kitenite deleted the starting-new-tasks-should-refresh-86cf branch November 15, 2025 01:04
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (4)
apps/desktop/src/renderer/screens/main/hooks/useTabs.ts (1)

37-61: Functional updater in handleTabCreated looks correct; outer null check is redundant

The functional setCurrentWorkspace here correctly appends the tab and updates activeWorktreeId/activeTabId without risking stale closures. The outer if (!currentWorkspace) return; is now redundant since the updater already guards on prev; you can simplify if you want slightly clearer logic.

- const handleTabCreated = (worktreeId: string, tab: Tab) => {
-   if (!currentWorkspace) return;
-
-   // Use functional setState to avoid stale closures
-   setCurrentWorkspace((prev) => {
-     if (!prev) return prev;
+ const handleTabCreated = (worktreeId: string, tab: Tab) => {
+   // Use functional setState to avoid stale closures
+   setCurrentWorkspace((prev) => {
+     if (!prev) return prev;
@@
-   });
- };
+   });
+ };
apps/desktop/src/renderer/screens/main/hooks/useTasks.ts (2)

7-15: Prop types for currentWorkspace/handleWorktreeCreated are sound but could reuse shared workspace typing

The narrowed shapes for currentWorkspace and handleWorktreeCreated’s return type are sufficient for this hook and remain structurally compatible with Workspace. If you want to keep these in sync with the shared model, consider expressing them via a Pick<Workspace, "id" | "worktrees"> alias instead of duplicating the inline object shape.

-import type { Worktree } from "shared/types";
+import type { Worktree, Workspace } from "shared/types";
@@
-interface UseTasksProps {
-  currentWorkspace: {
-    id: string;
-    worktrees?: Worktree[];
-  } | null;
+interface UseTasksProps {
+  currentWorkspace: Pick<Workspace, "id" | "worktrees"> | null;
@@
-  handleWorktreeCreated: () => Promise<{ id: string; worktrees?: Worktree[] } | null>;
+  handleWorktreeCreated: () => Promise<Pick<Workspace, "id" | "worktrees"> | null>;

173-193: Avoid the extra 50ms timeout after handleWorktreeCreated; it’s unnecessary and brittle

Awaiting handleWorktreeCreated() already guarantees its setCurrentWorkspace update is enqueued before you call setSelectedWorktreeId / handleTabSelect. The additional setTimeout(…, 50) only adds latency and couples correctness to timing, while the functional state updates in useTabs are designed to compose without this delay.

You can rely on the awaited call plus the returned refreshedWorkspace and drop the timeout.

-            // handleWorktreeCreated returns the refreshed workspace directly
-            const refreshedWorkspace = await handleWorktreeCreated();
-
-            // Wait for React to process the state update from handleWorktreeCreated
-            // This ensures handleTabSelect sees the updated workspace in its functional setState
-            await new Promise((resolve) => setTimeout(resolve, 50));
+            // handleWorktreeCreated returns the refreshed workspace directly
+            const refreshedWorkspace = await handleWorktreeCreated();
@@
-                    // Use the refreshed workspace returned by handleWorktreeCreated
-                    if (result.worktree && refreshedWorkspace) {
+                    // Use the refreshed workspace returned by handleWorktreeCreated
+                    if (result.worktree && refreshedWorkspace) {
                         // Find the worktree by branch name to get the correct ID
                         const newWorktree = refreshedWorkspace.worktrees?.find(
                             (wt) => wt.branch === result.worktree?.branch,
                         );
apps/desktop/src/renderer/screens/main/MainScreen.tsx (1)

116-127: Consider memoizing WorkspaceOperationsProvider value to avoid unnecessary context recalculations

Wrapping the tree in WorkspaceOperationsProvider is a good way to centralize workspace/worktree operations. Right now the value object is recreated on every MainScreen render, which will force all useWorkspaceOperations consumers to re-render even when the underlying handlers/state haven’t changed.

Not urgent, but you can optionally wrap the value in useMemo to stabilize it.

-import { useState } from "react";
+import { useMemo, useState } from "react";
@@
-  const {
-    handleWorktreeCreated,
-    handleWorktreeCreatedWithResult,
-    handleUpdateWorktree,
-    handleCreatePR,
-    handleMergePR,
-    handleDeleteWorktree,
-  } = useWorktrees({
+  const {
+    handleWorktreeCreated,
+    handleWorktreeCreatedWithResult,
+    handleUpdateWorktree,
+    handleCreatePR,
+    handleMergePR,
+    handleDeleteWorktree,
+  } = useWorktrees({
@@
-  const {
+  const {
@@
-  } = useTasks({
+  } = useTasks({
@@
-  return (
-    <WorkspaceOperationsProvider
-      value={{
-        handleWorktreeCreated,
-        handleUpdateWorktree,
-        handleCreatePR,
-        handleMergePR,
-        handleDeleteWorktree,
-        currentWorkspace,
-        workspaces,
-        handleWorkspaceSelect,
-        loadAllWorkspaces,
-      }}
-    >
+  const workspaceOperationsValue = useMemo(
+    () => ({
+      handleWorktreeCreated,
+      handleUpdateWorktree,
+      handleCreatePR,
+      handleMergePR,
+      handleDeleteWorktree,
+      currentWorkspace,
+      workspaces,
+      handleWorkspaceSelect,
+      loadAllWorkspaces,
+    }),
+    [
+      handleWorktreeCreated,
+      handleUpdateWorktree,
+      handleCreatePR,
+      handleMergePR,
+      handleDeleteWorktree,
+      currentWorkspace,
+      workspaces,
+      handleWorkspaceSelect,
+      loadAllWorkspaces,
+    ],
+  );
+
+  return (
+    <WorkspaceOperationsProvider value={workspaceOperationsValue}>
@@
-      {workspaces && (
+      {workspaces && (
@@
-      )}
-    </WorkspaceOperationsProvider>
+      )}
+    </WorkspaceOperationsProvider>
   );

Also applies to: 243-243

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 9fd128c and fd1d64e.

📒 Files selected for processing (5)
  • apps/desktop/src/renderer/screens/main/MainScreen.tsx (4 hunks)
  • apps/desktop/src/renderer/screens/main/contexts/WorkspaceOperationsContext.tsx (1 hunks)
  • apps/desktop/src/renderer/screens/main/hooks/useTabs.ts (4 hunks)
  • apps/desktop/src/renderer/screens/main/hooks/useTasks.ts (2 hunks)
  • apps/desktop/src/renderer/screens/main/hooks/useWorktrees.ts (4 hunks)
🧰 Additional context used
🧬 Code graph analysis (5)
apps/desktop/src/renderer/screens/main/hooks/useTabs.ts (1)
apps/desktop/src/shared/types.ts (1)
  • Workspace (70-82)
apps/desktop/src/renderer/screens/main/contexts/WorkspaceOperationsContext.tsx (1)
apps/desktop/src/shared/types.ts (2)
  • Worktree (58-68)
  • Workspace (70-82)
apps/desktop/src/renderer/screens/main/hooks/useTasks.ts (1)
apps/desktop/src/shared/types.ts (1)
  • Worktree (58-68)
apps/desktop/src/renderer/screens/main/MainScreen.tsx (1)
apps/desktop/src/renderer/screens/main/contexts/WorkspaceOperationsContext.tsx (1)
  • WorkspaceOperationsProvider (37-43)
apps/desktop/src/renderer/screens/main/hooks/useWorktrees.ts (1)
apps/desktop/src/shared/types.ts (1)
  • Workspace (70-82)
🔇 Additional comments (7)
apps/desktop/src/renderer/screens/main/hooks/useTabs.ts (2)

1-8: setCurrentWorkspace typed as React.Dispatch is aligned with React state usage

Typing setCurrentWorkspace as React.Dispatch<React.SetStateAction<Workspace | null>> is a good change and matches how you’re now using functional updates throughout this hook. No issues from a typing or usage perspective.


65-85: Selection/focus handlers now compose correctly with concurrent workspace updates

Using functional setCurrentWorkspace in both handleTabSelect and handleTabFocus ensures that active worktree/tab updates compose safely with other callers (like workspace refresh) without clobbering concurrent changes. The IPC call still only depends on the workspace id, so this refactor is behavior‑preserving.

Also applies to: 89-107

apps/desktop/src/renderer/screens/main/MainScreen.tsx (1)

75-83: Clean separation of void vs resultful worktree-creation handlers

Using handleWorktreeCreated for the Promise surface and handleWorktreeCreatedWithResult for callers that need the refreshed workspace (useTasks) is a clear separation that keeps the context API simple while still enabling richer flows in hooks. The mapping handleWorktreeCreated: handleWorktreeCreatedWithResult in useTasks matches the updated hook signatures.

Also applies to: 108-113

apps/desktop/src/renderer/screens/main/hooks/useWorktrees.ts (3)

4-7: setCurrentWorkspace typing matches new functional update usage

Updating setCurrentWorkspace to React.Dispatch<React.SetStateAction<Workspace | null>> is consistent with the functional updates you’re now doing in handleWorktreeCreated and keeps this hook aligned with useWorkspace/useTabs. No issues here.


24-59: handleWorktreeCreated’s refreshed-workspace return and guarded functional update look solid

The new handleWorktreeCreated implementation:

  • Safely bails out when there’s no currentWorkspace.
  • Uses a workspaceId snapshot plus a functional setCurrentWorkspace to avoid races when the current workspace changes.
  • Clones the worktrees array to ensure React notices the structural change.
  • Returns the refreshedWorkspace (or null on failure), which matches how useTasks consumes it.

This is a good balance between correctness and ergonomics; no changes needed.


210-218: Wrapper/alias split between void and resultful handlers is clean

handleWorktreeCreatedVoid is a simple wrapper that preserves the existing Promise contract for components/context, while exposing handleWorktreeCreatedWithResult for callers that need the refreshed workspace. This keeps public APIs stable without duplicating logic.

apps/desktop/src/renderer/screens/main/contexts/WorkspaceOperationsContext.tsx (1)

5-43: WorkspaceOperationsContext surface and hook/provider pattern look correct

The WorkspaceOperationsContextValue interface matches what MainScreen provides, and useWorkspaceOperations correctly throws if used outside WorkspaceOperationsProvider. The provider itself is a straightforward wrapper around createContext and useContext, which should make workspace operations easy to consume across the tree.

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.

1 participant