Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ import { useQuery } from "@tanstack/react-query";
import { FOCUSABLE_SELECTOR } from "@utils/overlay";
import { LayoutGroup, motion } from "framer-motion";
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
import { useInitialDirectoryFromFolderId } from "../hooks/useInitialDirectoryFromFolderId";
import { usePreviewConfig } from "../hooks/usePreviewConfig";
import { useTaskCreation } from "../hooks/useTaskCreation";
import { CloudGithubMissingNotice } from "./CloudGithubMissingNotice";
Expand Down Expand Up @@ -401,14 +402,7 @@ export function TaskInput({
setLastUsedCloudRepository,
]);

useEffect(() => {
if (view.folderId) {
const folder = folders.find((f) => f.id === view.folderId);
if (folder) {
setSelectedDirectory(folder.path);
}
}
}, [view.folderId, folders]);
useInitialDirectoryFromFolderId(view.folderId, folders, setSelectedDirectory);

useEffect(() => {
setCloudBranchSearchQuery("");
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
import type { RegisteredFolder } from "@main/services/folders/schemas";
import { renderHook } from "@testing-library/react";
import { describe, expect, it, vi } from "vitest";
import { useInitialDirectoryFromFolderId } from "./useInitialDirectoryFromFolderId";

const folder = (id: string, path: string): RegisteredFolder => ({
id,
path,
name: id,
remoteUrl: null,
lastAccessed: "2026-05-21T00:00:00Z",
createdAt: "2026-05-21T00:00:00Z",
});

describe("useInitialDirectoryFromFolderId", () => {
it("syncs the directory to the folder matching folderId on first render", () => {
const setSelectedDirectory = vi.fn();
renderHook(() =>
useInitialDirectoryFromFolderId(
"a",
[folder("a", "/repos/a")],
setSelectedDirectory,
),
);
expect(setSelectedDirectory).toHaveBeenCalledExactlyOnceWith("/repos/a");
});

it("waits for folders to load before syncing", () => {
const setSelectedDirectory = vi.fn();
const { rerender } = renderHook(
({ folders }: { folders: RegisteredFolder[] }) =>
useInitialDirectoryFromFolderId("a", folders, setSelectedDirectory),
{ initialProps: { folders: [] as RegisteredFolder[] } },
);
expect(setSelectedDirectory).not.toHaveBeenCalled();

rerender({ folders: [folder("a", "/repos/a")] });
expect(setSelectedDirectory).toHaveBeenCalledExactlyOnceWith("/repos/a");
});

it("does not re-sync when folders changes but folderId stays the same", () => {
const setSelectedDirectory = vi.fn();
const { rerender } = renderHook(
({ folders }: { folders: RegisteredFolder[] }) =>
useInitialDirectoryFromFolderId("a", folders, setSelectedDirectory),
{ initialProps: { folders: [folder("a", "/repos/a")] } },
);
expect(setSelectedDirectory).toHaveBeenCalledExactlyOnceWith("/repos/a");

// Simulate adding a folder (e.g. after the user picks one via "Open
// folder..."). The folders list changes but the user's pick must not be
// clobbered by re-syncing from the original folderId.
rerender({
folders: [folder("a", "/repos/a"), folder("b", "/repos/picked")],
});
expect(setSelectedDirectory).toHaveBeenCalledTimes(1);
});

it("re-syncs when folderId changes", () => {
const setSelectedDirectory = vi.fn();
const folders = [folder("a", "/repos/a"), folder("b", "/repos/b")];
const { rerender } = renderHook(
({ folderId }: { folderId: string }) =>
useInitialDirectoryFromFolderId(
folderId,
folders,
setSelectedDirectory,
),
{ initialProps: { folderId: "a" } },
);
expect(setSelectedDirectory).toHaveBeenLastCalledWith("/repos/a");

rerender({ folderId: "b" });
expect(setSelectedDirectory).toHaveBeenLastCalledWith("/repos/b");
expect(setSelectedDirectory).toHaveBeenCalledTimes(2);
});

it("does nothing when folderId is undefined", () => {
const setSelectedDirectory = vi.fn();
renderHook(() =>
useInitialDirectoryFromFolderId(
undefined,
[folder("a", "/repos/a")],
setSelectedDirectory,
),
);
expect(setSelectedDirectory).not.toHaveBeenCalled();
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import type { RegisteredFolder } from "@main/services/folders/schemas";
import { useEffect, useRef } from "react";

/**
* Syncs `selectedDirectory` to the path of `folders[view.folderId]` once per
* folderId. The dependency on `folders` is required so the sync still fires
* when the folder list hasn't loaded yet on initial mount, but we must not
* re-sync on later `folders` refetches (e.g. after `addFolder`) — that would
* clobber a folder the user just picked via the file dialog.
*/
export function useInitialDirectoryFromFolderId(
folderId: string | undefined,
folders: RegisteredFolder[],
setSelectedDirectory: (path: string) => void,
) {
const lastInitializedRef = useRef<string | undefined>(undefined);
useEffect(() => {
if (!folderId) {
lastInitializedRef.current = undefined;
return;
}
if (lastInitializedRef.current === folderId) return;
const folder = folders.find((f) => f.id === folderId);
if (folder) {
setSelectedDirectory(folder.path);
lastInitializedRef.current = folderId;
}
}, [folderId, folders, setSelectedDirectory]);
}
Loading