feat(FN-4801): merge fusion/fn-4801
This commit is contained in:
5
.changeset/FN-4801-top-progress-revalidation.md
Normal file
5
.changeset/FN-4801-top-progress-revalidation.md
Normal file
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"@runfusion/fusion": patch
|
||||
---
|
||||
|
||||
Dashboard top progress bar now also reflects task list revalidation, not just project loading.
|
||||
@@ -382,7 +382,7 @@ function AppInner() {
|
||||
// Tasks hook with project context and search query
|
||||
// SSE is only enabled for board/list views to free connection slots for mission detail fetches
|
||||
const taskSseEnabled = taskView === "board" || taskView === "list";
|
||||
const { tasks, createTask, moveTask, pauseTask, unpauseTask, deleteTask, mergeTask, retryTask, resetTask, updateTask, duplicateTask, archiveTask, unarchiveTask, archiveAllDone, loadArchivedTasks, refreshTasks, ingestCreatedTasks, lastFetchTimeMs } = useTasks(
|
||||
const { tasks, isStale, createTask, moveTask, pauseTask, unpauseTask, deleteTask, mergeTask, retryTask, resetTask, updateTask, duplicateTask, archiveTask, unarchiveTask, archiveAllDone, loadArchivedTasks, refreshTasks, ingestCreatedTasks, lastFetchTimeMs } = useTasks(
|
||||
{
|
||||
...(currentProject ? { projectId: currentProject.id } : {}),
|
||||
searchQuery: searchQuery || undefined,
|
||||
@@ -1643,6 +1643,10 @@ function AppInner() {
|
||||
isOnboardingCompleted() &&
|
||||
!isPostOnboardingDismissed();
|
||||
|
||||
// Top progress bar reflects any in-flight revalidation: projects, current-project, or tasks.
|
||||
// Add new sources here, not inside TopProgressBar.
|
||||
const isRevalidating = projectsLoading || currentProjectLoading || isStale;
|
||||
|
||||
return (
|
||||
<NavigationHistoryProvider value={{ pushNav, replaceCurrent }}>
|
||||
<FileBrowserProvider openFile={openFileInBrowser}>
|
||||
@@ -1654,7 +1658,7 @@ function AppInner() {
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<TopProgressBar visible={projectsLoading || currentProjectLoading} />
|
||||
<TopProgressBar visible={isRevalidating} />
|
||||
<Header
|
||||
shellHost={shellHost.host}
|
||||
onOpenSettings={openSettingsWithNav}
|
||||
|
||||
@@ -603,6 +603,7 @@ beforeEach(() => {
|
||||
mockUseTasks.mockReset();
|
||||
mockUseTasks.mockImplementation(() => ({
|
||||
tasks: [],
|
||||
isStale: false,
|
||||
createTask: mockCreateTask,
|
||||
moveTask: vi.fn(),
|
||||
pauseTask: vi.fn(),
|
||||
@@ -706,6 +707,84 @@ describe("FN-4250 FileBrowserProvider coverage", () => {
|
||||
expect(screen.queryByTestId("fb-probe-loader")).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("FN-4801: keeps top progress bar visible while tasks are stale", () => {
|
||||
mockProjectsState.loading = false;
|
||||
mockProjectsState.projects = [
|
||||
{ id: DEFAULT_PROJECT_ID, name: "Test Project", path: "/test", status: "active", isolationMode: "in-process", createdAt: "", updatedAt: "" },
|
||||
];
|
||||
mockCurrentProjectState.loading = false;
|
||||
mockUseTasks.mockImplementation(() => ({
|
||||
tasks: [],
|
||||
isStale: true,
|
||||
createTask: mockCreateTask,
|
||||
moveTask: vi.fn(),
|
||||
pauseTask: vi.fn(),
|
||||
unpauseTask: vi.fn(),
|
||||
deleteTask: vi.fn(),
|
||||
mergeTask: vi.fn(),
|
||||
retryTask: vi.fn(),
|
||||
resetTask: vi.fn(),
|
||||
updateTask: vi.fn(),
|
||||
duplicateTask: vi.fn(),
|
||||
archiveTask: vi.fn(),
|
||||
unarchiveTask: vi.fn(),
|
||||
archiveAllDone: vi.fn(),
|
||||
loadArchivedTasks: vi.fn(),
|
||||
refreshTasks: vi.fn(),
|
||||
ingestCreatedTasks: vi.fn(),
|
||||
lastFetchTimeMs: Date.now(),
|
||||
}));
|
||||
|
||||
render(<App />);
|
||||
|
||||
const progressBar = screen.getByRole("progressbar", { name: "Loading" });
|
||||
expect(progressBar).toHaveAttribute("aria-busy", "true");
|
||||
expect(progressBar).toHaveAttribute("data-visible", "true");
|
||||
});
|
||||
|
||||
it("FN-4801: hides top progress bar on next render when tasks are fresh", () => {
|
||||
mockProjectsState.loading = false;
|
||||
mockProjectsState.projects = [
|
||||
{ id: DEFAULT_PROJECT_ID, name: "Test Project", path: "/test", status: "active", isolationMode: "in-process", createdAt: "", updatedAt: "" },
|
||||
];
|
||||
mockCurrentProjectState.loading = false;
|
||||
|
||||
const taskHookState = { isStale: true };
|
||||
mockUseTasks.mockImplementation(() => ({
|
||||
tasks: [],
|
||||
isStale: taskHookState.isStale,
|
||||
createTask: mockCreateTask,
|
||||
moveTask: vi.fn(),
|
||||
pauseTask: vi.fn(),
|
||||
unpauseTask: vi.fn(),
|
||||
deleteTask: vi.fn(),
|
||||
mergeTask: vi.fn(),
|
||||
retryTask: vi.fn(),
|
||||
resetTask: vi.fn(),
|
||||
updateTask: vi.fn(),
|
||||
duplicateTask: vi.fn(),
|
||||
archiveTask: vi.fn(),
|
||||
unarchiveTask: vi.fn(),
|
||||
archiveAllDone: vi.fn(),
|
||||
loadArchivedTasks: vi.fn(),
|
||||
refreshTasks: vi.fn(),
|
||||
ingestCreatedTasks: vi.fn(),
|
||||
lastFetchTimeMs: Date.now(),
|
||||
}));
|
||||
|
||||
const { rerender } = render(<App />);
|
||||
|
||||
const progressBar = screen.getByRole("progressbar", { name: "Loading" });
|
||||
expect(progressBar).toHaveAttribute("aria-busy", "true");
|
||||
expect(progressBar).toHaveAttribute("data-visible", "true");
|
||||
|
||||
taskHookState.isStale = false;
|
||||
rerender(<App />);
|
||||
|
||||
expect(progressBar).toHaveAttribute("aria-busy", "false");
|
||||
expect(progressBar).toHaveAttribute("data-visible", "false");
|
||||
});
|
||||
|
||||
it("FN-4250: ChatView branch is inside FileBrowserProvider", async () => {
|
||||
localStorage.setItem(taskViewStorageKey(), "chat");
|
||||
|
||||
|
||||
@@ -18,4 +18,17 @@ describe("TopProgressBar", () => {
|
||||
expect(progressBar).toHaveAttribute("aria-busy", "false");
|
||||
expect(progressBar).toHaveAttribute("data-visible", "false");
|
||||
});
|
||||
|
||||
it("derives visibility only from the visible prop across rerenders", () => {
|
||||
const { rerender } = render(<TopProgressBar visible={true} />);
|
||||
|
||||
const progressBar = screen.getByRole("progressbar", { name: "Loading" });
|
||||
expect(progressBar).toHaveAttribute("aria-busy", "true");
|
||||
expect(progressBar).toHaveAttribute("data-visible", "true");
|
||||
|
||||
rerender(<TopProgressBar visible={false} />);
|
||||
|
||||
expect(progressBar).toHaveAttribute("aria-busy", "false");
|
||||
expect(progressBar).toHaveAttribute("data-visible", "false");
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user