feat(FN-1529): implement search query propagation to remote node data
- Add search query propagation so remote nodes receive and use query filters - Update api-node.ts to accept and forward search query parameters - Add useRemoteNodeData query key dependency for proper re-fetching on filter changes - Add api-node.test.ts with tests for search query propagation - Add comprehensive tests for App component including remote data filtering - Document search query propagation pitfall in .fusion/memory.md
This commit is contained in:
@@ -59,17 +59,17 @@ function AppInner() {
|
||||
}
|
||||
}, [currentNodeId, nodes, clearCurrentNode]);
|
||||
|
||||
// Remote node data and events when in remote mode
|
||||
const remoteData = useRemoteNodeData(currentNodeId, { projectId: currentProject?.id });
|
||||
// Search query state - must be defined before useTasks
|
||||
const [searchQuery, setSearchQuery] = useState("");
|
||||
|
||||
// Remote node data and events when in remote mode (pass searchQuery for server-side filtering)
|
||||
const remoteData = useRemoteNodeData(currentNodeId, { projectId: currentProject?.id, searchQuery: searchQuery || undefined });
|
||||
const remoteEvents = useRemoteNodeEvents(currentNodeId);
|
||||
|
||||
// Use remote data when in remote mode, local data otherwise
|
||||
const effectiveProjects = isRemote && remoteData.projects.length > 0 ? remoteData.projects : projects;
|
||||
const effectiveTasks = isRemote && remoteData.tasks.length > 0 ? remoteData.tasks : [];
|
||||
|
||||
// Search query state - must be defined before useTasks
|
||||
const [searchQuery, setSearchQuery] = useState("");
|
||||
|
||||
// Tasks hook with project context and search query
|
||||
const { tasks, createTask, moveTask, deleteTask, mergeTask, retryTask, updateTask, duplicateTask, archiveTask, unarchiveTask, archiveAllDone } = useTasks(
|
||||
currentProject ? { projectId: currentProject.id, searchQuery: searchQuery || undefined } : { searchQuery: searchQuery || undefined }
|
||||
|
||||
@@ -113,6 +113,68 @@ describe("api-node", () => {
|
||||
{ nodeId: "node_abc" },
|
||||
);
|
||||
});
|
||||
|
||||
it("forwards search query parameter (q) when provided", async () => {
|
||||
const mockTasks = [
|
||||
{
|
||||
id: "FN-001",
|
||||
title: "Searchable Task",
|
||||
description: "Test description",
|
||||
column: "todo" as const,
|
||||
dependencies: [],
|
||||
steps: [],
|
||||
currentStep: 0,
|
||||
size: "M" as const,
|
||||
reviewLevel: 1,
|
||||
createdAt: "2026-01-01T00:00:00.000Z",
|
||||
updatedAt: "2026-01-01T00:00:00.000Z",
|
||||
columnMovedAt: "2026-01-01T00:00:00.000Z",
|
||||
},
|
||||
];
|
||||
mockProxyApi.mockResolvedValueOnce(mockTasks);
|
||||
|
||||
const result = await fetchRemoteNodeTasks("node_abc", "proj_001", "searchable");
|
||||
|
||||
expect(mockProxyApi).toHaveBeenCalledTimes(1);
|
||||
expect(mockProxyApi).toHaveBeenCalledWith(
|
||||
"/tasks?projectId=proj_001&q=searchable",
|
||||
{ nodeId: "node_abc" },
|
||||
);
|
||||
expect(result).toEqual(mockTasks);
|
||||
});
|
||||
|
||||
it("properly encodes search query with special characters", async () => {
|
||||
mockProxyApi.mockResolvedValueOnce([]);
|
||||
|
||||
await fetchRemoteNodeTasks("node_abc", "proj_001", "search+query&test");
|
||||
|
||||
expect(mockProxyApi).toHaveBeenCalledWith(
|
||||
"/tasks?projectId=proj_001&q=search%2Bquery%26test",
|
||||
{ nodeId: "node_abc" },
|
||||
);
|
||||
});
|
||||
|
||||
it("omits q parameter when searchQuery is undefined", async () => {
|
||||
mockProxyApi.mockResolvedValueOnce([]);
|
||||
|
||||
await fetchRemoteNodeTasks("node_abc", "proj_001");
|
||||
|
||||
expect(mockProxyApi).toHaveBeenCalledWith(
|
||||
"/tasks?projectId=proj_001",
|
||||
{ nodeId: "node_abc" },
|
||||
);
|
||||
});
|
||||
|
||||
it("omits q parameter when searchQuery is empty string", async () => {
|
||||
mockProxyApi.mockResolvedValueOnce([]);
|
||||
|
||||
await fetchRemoteNodeTasks("node_abc", "proj_001", "");
|
||||
|
||||
expect(mockProxyApi).toHaveBeenCalledWith(
|
||||
"/tasks?projectId=proj_001",
|
||||
{ nodeId: "node_abc" },
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe("fetchRemoteNodeProjectHealth", () => {
|
||||
|
||||
@@ -25,8 +25,16 @@ export async function fetchRemoteNodeProjects(nodeId: string): Promise<ProjectIn
|
||||
}
|
||||
|
||||
/** Fetch tasks from a specific project on a remote node */
|
||||
export async function fetchRemoteNodeTasks(nodeId: string, projectId: string): Promise<Task[]> {
|
||||
return proxyApi<Task[]>(`/tasks?projectId=${encodeURIComponent(projectId)}`, { nodeId });
|
||||
export async function fetchRemoteNodeTasks(
|
||||
nodeId: string,
|
||||
projectId: string,
|
||||
searchQuery?: string,
|
||||
): Promise<Task[]> {
|
||||
const params = new URLSearchParams({ projectId });
|
||||
if (searchQuery && searchQuery.trim()) {
|
||||
params.set("q", searchQuery.trim());
|
||||
}
|
||||
return proxyApi<Task[]>(`/tasks?${params.toString()}`, { nodeId });
|
||||
}
|
||||
|
||||
/** Fetch project health from a remote node */
|
||||
|
||||
@@ -166,6 +166,7 @@ vi.mock("../../hooks/useNodes", () => ({
|
||||
|
||||
import { App } from "../../App";
|
||||
import { fetchAuthStatus, fetchSettings, fetchGlobalSettings, fetchTaskDetail, updateSettings, runScript, fetchScripts } from "../../api";
|
||||
import * as apiNodeModule from "../../hooks/useRemoteNodeData";
|
||||
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks();
|
||||
@@ -1735,3 +1736,159 @@ describe("App node mode switching", () => {
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("App search query propagation to remote mode", () => {
|
||||
// Mock useRemoteNodeData to capture searchQuery parameter
|
||||
let capturedSearchQuery: string | undefined;
|
||||
|
||||
beforeEach(() => {
|
||||
capturedSearchQuery = undefined;
|
||||
|
||||
// Get the mocked useRemoteNodeData and capture the searchQuery
|
||||
vi.mocked(apiNodeModule.useRemoteNodeData).mockImplementation((nodeId, options) => {
|
||||
capturedSearchQuery = options?.searchQuery;
|
||||
return {
|
||||
projects: [],
|
||||
tasks: [],
|
||||
health: null,
|
||||
loading: false,
|
||||
error: null,
|
||||
refresh: vi.fn(),
|
||||
};
|
||||
});
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
vi.clearAllMocks();
|
||||
localStorage.removeItem("fusion-dashboard-current-node");
|
||||
});
|
||||
|
||||
it("passes searchQuery to useRemoteNodeData when in remote mode", async () => {
|
||||
// Set up mock with remote node
|
||||
const { useNodes } = await import("../../hooks/useNodes");
|
||||
vi.mocked(useNodes).mockReturnValue({
|
||||
nodes: [
|
||||
{
|
||||
id: "node_remote_1",
|
||||
name: "Remote Node 1",
|
||||
type: "remote" as const,
|
||||
url: "http://remote:4040",
|
||||
status: "online" as const,
|
||||
maxConcurrent: 2,
|
||||
createdAt: "",
|
||||
updatedAt: "",
|
||||
},
|
||||
],
|
||||
loading: false,
|
||||
error: null,
|
||||
refresh: vi.fn(),
|
||||
register: vi.fn(),
|
||||
update: vi.fn(),
|
||||
unregister: vi.fn(),
|
||||
healthCheck: vi.fn(),
|
||||
});
|
||||
|
||||
// Mock node context to return remote node
|
||||
mockNodeContextValue.currentNode = {
|
||||
id: "node_remote_1",
|
||||
name: "Remote Node 1",
|
||||
type: "remote",
|
||||
url: "http://remote:4040",
|
||||
status: "online",
|
||||
maxConcurrent: 2,
|
||||
createdAt: "",
|
||||
updatedAt: "",
|
||||
};
|
||||
mockNodeContextValue.currentNodeId = "node_remote_1";
|
||||
mockNodeContextValue.isRemote = true;
|
||||
|
||||
// Set project mode
|
||||
localStorage.setItem("kb-dashboard-view-mode", "project");
|
||||
|
||||
render(<App />);
|
||||
|
||||
await waitFor(() => {
|
||||
expect(fetchSettings).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
// Wait for initial load to complete
|
||||
await act(async () => {
|
||||
await new Promise((resolve) => setTimeout(resolve, 300));
|
||||
});
|
||||
|
||||
// At this point, searchQuery should be passed to useRemoteNodeData
|
||||
// capturedSearchQuery should be undefined (empty search initially)
|
||||
expect(capturedSearchQuery).toBeUndefined();
|
||||
});
|
||||
|
||||
it("updates searchQuery in useRemoteNodeData when header search changes", async () => {
|
||||
// Set up mock with remote node
|
||||
const { useNodes } = await import("../../hooks/useNodes");
|
||||
vi.mocked(useNodes).mockReturnValue({
|
||||
nodes: [
|
||||
{
|
||||
id: "node_remote_1",
|
||||
name: "Remote Node 1",
|
||||
type: "remote" as const,
|
||||
url: "http://remote:4040",
|
||||
status: "online" as const,
|
||||
maxConcurrent: 2,
|
||||
createdAt: "",
|
||||
updatedAt: "",
|
||||
},
|
||||
],
|
||||
loading: false,
|
||||
error: null,
|
||||
refresh: vi.fn(),
|
||||
register: vi.fn(),
|
||||
update: vi.fn(),
|
||||
unregister: vi.fn(),
|
||||
healthCheck: vi.fn(),
|
||||
});
|
||||
|
||||
// Mock node context to return remote node
|
||||
mockNodeContextValue.currentNode = {
|
||||
id: "node_remote_1",
|
||||
name: "Remote Node 1",
|
||||
type: "remote",
|
||||
url: "http://remote:4040",
|
||||
status: "online",
|
||||
maxConcurrent: 2,
|
||||
createdAt: "",
|
||||
updatedAt: "",
|
||||
};
|
||||
mockNodeContextValue.currentNodeId = "node_remote_1";
|
||||
mockNodeContextValue.isRemote = true;
|
||||
|
||||
// Set project mode
|
||||
localStorage.setItem("kb-dashboard-view-mode", "project");
|
||||
|
||||
render(<App />);
|
||||
|
||||
await waitFor(() => {
|
||||
expect(fetchSettings).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
// Wait for initial load to complete
|
||||
await act(async () => {
|
||||
await new Promise((resolve) => setTimeout(resolve, 300));
|
||||
});
|
||||
|
||||
// Click the search toggle button to open search
|
||||
const searchToggleBtn = screen.getByTestId("desktop-header-search-btn");
|
||||
expect(searchToggleBtn).toBeInTheDocument();
|
||||
fireEvent.click(searchToggleBtn);
|
||||
|
||||
// Now the search input should be visible
|
||||
const searchInput = await screen.findByPlaceholderText("Search tasks...");
|
||||
expect(searchInput).toBeInTheDocument();
|
||||
|
||||
// Type in the search input
|
||||
fireEvent.change(searchInput, { target: { value: "test search" } });
|
||||
|
||||
// Wait for the search query to propagate
|
||||
await waitFor(() => {
|
||||
expect(capturedSearchQuery).toBe("test search");
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -15,6 +15,260 @@ const mockFetchRemoteNodeProjects = vi.mocked(apiNodeModule.fetchRemoteNodeProje
|
||||
const mockFetchRemoteNodeTasks = vi.mocked(apiNodeModule.fetchRemoteNodeTasks);
|
||||
const mockFetchRemoteNodeProjectHealth = vi.mocked(apiNodeModule.fetchRemoteNodeProjectHealth);
|
||||
|
||||
describe("useRemoteNodeData search query propagation", () => {
|
||||
beforeEach(() => {
|
||||
mockFetchRemoteNodeHealth.mockReset();
|
||||
mockFetchRemoteNodeProjects.mockReset();
|
||||
mockFetchRemoteNodeTasks.mockReset();
|
||||
mockFetchRemoteNodeProjectHealth.mockReset();
|
||||
|
||||
// Default mock setup for successful fetch
|
||||
mockFetchRemoteNodeHealth.mockResolvedValueOnce({
|
||||
status: "online",
|
||||
version: "1.0.0",
|
||||
nodeId: "node_abc",
|
||||
});
|
||||
mockFetchRemoteNodeProjects.mockResolvedValueOnce([]);
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
vi.clearAllMocks();
|
||||
});
|
||||
|
||||
it("forwards searchQuery to fetchRemoteNodeTasks when provided", async () => {
|
||||
const mockTasks = [
|
||||
{
|
||||
id: "FN-001",
|
||||
title: "Test Task",
|
||||
description: "Test description",
|
||||
column: "todo" as const,
|
||||
dependencies: [],
|
||||
steps: [],
|
||||
currentStep: 0,
|
||||
size: "M" as const,
|
||||
reviewLevel: 1,
|
||||
createdAt: "2026-01-01T00:00:00.000Z",
|
||||
updatedAt: "2026-01-01T00:00:00.000Z",
|
||||
columnMovedAt: "2026-01-01T00:00:00.000Z",
|
||||
},
|
||||
];
|
||||
mockFetchRemoteNodeTasks.mockResolvedValueOnce(mockTasks);
|
||||
|
||||
const { result } = renderHook(() =>
|
||||
useRemoteNodeData("node_abc", { projectId: "proj_001", searchQuery: "test" }),
|
||||
);
|
||||
|
||||
await waitFor(() => {
|
||||
expect(result.current.loading).toBe(false);
|
||||
});
|
||||
|
||||
expect(mockFetchRemoteNodeTasks).toHaveBeenCalledTimes(1);
|
||||
expect(mockFetchRemoteNodeTasks).toHaveBeenCalledWith("node_abc", "proj_001", "test");
|
||||
expect(result.current.tasks).toEqual(mockTasks);
|
||||
});
|
||||
|
||||
it("does not forward searchQuery when undefined", async () => {
|
||||
mockFetchRemoteNodeTasks.mockResolvedValueOnce([]);
|
||||
|
||||
const { result } = renderHook(() =>
|
||||
useRemoteNodeData("node_abc", { projectId: "proj_001" }),
|
||||
);
|
||||
|
||||
await waitFor(() => {
|
||||
expect(result.current.loading).toBe(false);
|
||||
});
|
||||
|
||||
expect(mockFetchRemoteNodeTasks).toHaveBeenCalledTimes(1);
|
||||
expect(mockFetchRemoteNodeTasks).toHaveBeenCalledWith("node_abc", "proj_001", undefined);
|
||||
});
|
||||
|
||||
it("refetches tasks when searchQuery changes", async () => {
|
||||
const initialTasks = [
|
||||
{
|
||||
id: "FN-001",
|
||||
title: "Initial Task",
|
||||
description: "Initial description",
|
||||
column: "todo" as const,
|
||||
dependencies: [],
|
||||
steps: [],
|
||||
currentStep: 0,
|
||||
size: "M" as const,
|
||||
reviewLevel: 1,
|
||||
createdAt: "2026-01-01T00:00:00.000Z",
|
||||
updatedAt: "2026-01-01T00:00:00.000Z",
|
||||
columnMovedAt: "2026-01-01T00:00:00.000Z",
|
||||
},
|
||||
];
|
||||
const filteredTasks = [
|
||||
{
|
||||
id: "FN-002",
|
||||
title: "Filtered Task",
|
||||
description: "Filtered description",
|
||||
column: "todo" as const,
|
||||
dependencies: [],
|
||||
steps: [],
|
||||
currentStep: 0,
|
||||
size: "M" as const,
|
||||
reviewLevel: 1,
|
||||
createdAt: "2026-01-01T00:00:00.000Z",
|
||||
updatedAt: "2026-01-01T00:00:00.000Z",
|
||||
columnMovedAt: "2026-01-01T00:00:00.000Z",
|
||||
},
|
||||
];
|
||||
|
||||
mockFetchRemoteNodeTasks
|
||||
.mockResolvedValueOnce(initialTasks)
|
||||
.mockResolvedValueOnce(filteredTasks);
|
||||
|
||||
const { result, rerender } = renderHook(
|
||||
({ searchQuery }: { searchQuery?: string }) =>
|
||||
useRemoteNodeData("node_abc", { projectId: "proj_001", searchQuery }),
|
||||
{ initialProps: { searchQuery: undefined } },
|
||||
);
|
||||
|
||||
await waitFor(() => {
|
||||
expect(result.current.loading).toBe(false);
|
||||
});
|
||||
|
||||
expect(mockFetchRemoteNodeTasks).toHaveBeenCalledTimes(1);
|
||||
expect(mockFetchRemoteNodeTasks).toHaveBeenLastCalledWith("node_abc", "proj_001", undefined);
|
||||
expect(result.current.tasks).toEqual(initialTasks);
|
||||
|
||||
// Update searchQuery
|
||||
rerender({ searchQuery: "filtered" });
|
||||
|
||||
await waitFor(() => {
|
||||
expect(result.current.loading).toBe(false);
|
||||
});
|
||||
|
||||
expect(mockFetchRemoteNodeTasks).toHaveBeenCalledTimes(2);
|
||||
expect(mockFetchRemoteNodeTasks).toHaveBeenLastCalledWith("node_abc", "proj_001", "filtered");
|
||||
expect(result.current.tasks).toEqual(filteredTasks);
|
||||
});
|
||||
|
||||
it("refetches tasks when searchQuery is cleared", async () => {
|
||||
const filteredTasks = [
|
||||
{
|
||||
id: "FN-001",
|
||||
title: "Filtered Task",
|
||||
description: "Filtered description",
|
||||
column: "todo" as const,
|
||||
dependencies: [],
|
||||
steps: [],
|
||||
currentStep: 0,
|
||||
size: "M" as const,
|
||||
reviewLevel: 1,
|
||||
createdAt: "2026-01-01T00:00:00.000Z",
|
||||
updatedAt: "2026-01-01T00:00:00.000Z",
|
||||
columnMovedAt: "2026-01-01T00:00:00.000Z",
|
||||
},
|
||||
];
|
||||
const allTasks = [
|
||||
{
|
||||
id: "FN-001",
|
||||
title: "Filtered Task",
|
||||
description: "Filtered description",
|
||||
column: "todo" as const,
|
||||
dependencies: [],
|
||||
steps: [],
|
||||
currentStep: 0,
|
||||
size: "M" as const,
|
||||
reviewLevel: 1,
|
||||
createdAt: "2026-01-01T00:00:00.000Z",
|
||||
updatedAt: "2026-01-01T00:00:00.000Z",
|
||||
columnMovedAt: "2026-01-01T00:00:00.000Z",
|
||||
},
|
||||
{
|
||||
id: "FN-002",
|
||||
title: "Other Task",
|
||||
description: "Other description",
|
||||
column: "todo" as const,
|
||||
dependencies: [],
|
||||
steps: [],
|
||||
currentStep: 0,
|
||||
size: "M" as const,
|
||||
reviewLevel: 1,
|
||||
createdAt: "2026-01-01T00:00:00.000Z",
|
||||
updatedAt: "2026-01-01T00:00:00.000Z",
|
||||
columnMovedAt: "2026-01-01T00:00:00.000Z",
|
||||
},
|
||||
];
|
||||
|
||||
mockFetchRemoteNodeTasks
|
||||
.mockResolvedValueOnce(filteredTasks)
|
||||
.mockResolvedValueOnce(allTasks);
|
||||
|
||||
const { result, rerender } = renderHook(
|
||||
({ searchQuery }: { searchQuery?: string }) =>
|
||||
useRemoteNodeData("node_abc", { projectId: "proj_001", searchQuery }),
|
||||
{ initialProps: { searchQuery: "filtered" } },
|
||||
);
|
||||
|
||||
await waitFor(() => {
|
||||
expect(result.current.loading).toBe(false);
|
||||
});
|
||||
|
||||
expect(mockFetchRemoteNodeTasks).toHaveBeenCalledTimes(1);
|
||||
expect(mockFetchRemoteNodeTasks).toHaveBeenLastCalledWith("node_abc", "proj_001", "filtered");
|
||||
expect(result.current.tasks).toEqual(filteredTasks);
|
||||
|
||||
// Clear searchQuery
|
||||
rerender({ searchQuery: "" });
|
||||
|
||||
await waitFor(() => {
|
||||
expect(result.current.loading).toBe(false);
|
||||
});
|
||||
|
||||
expect(mockFetchRemoteNodeTasks).toHaveBeenCalledTimes(2);
|
||||
expect(mockFetchRemoteNodeTasks).toHaveBeenLastCalledWith("node_abc", "proj_001", "");
|
||||
expect(result.current.tasks).toEqual(allTasks);
|
||||
});
|
||||
|
||||
it("refresh function re-fetches with current searchQuery", async () => {
|
||||
const mockTasks = [
|
||||
{
|
||||
id: "FN-001",
|
||||
title: "Test Task",
|
||||
description: "Test description",
|
||||
column: "todo" as const,
|
||||
dependencies: [],
|
||||
steps: [],
|
||||
currentStep: 0,
|
||||
size: "M" as const,
|
||||
reviewLevel: 1,
|
||||
createdAt: "2026-01-01T00:00:00.000Z",
|
||||
updatedAt: "2026-01-01T00:00:00.000Z",
|
||||
columnMovedAt: "2026-01-01T00:00:00.000Z",
|
||||
},
|
||||
];
|
||||
|
||||
mockFetchRemoteNodeTasks
|
||||
.mockResolvedValueOnce(mockTasks)
|
||||
.mockResolvedValueOnce(mockTasks);
|
||||
|
||||
const { result } = renderHook(() =>
|
||||
useRemoteNodeData("node_abc", { projectId: "proj_001", searchQuery: "test" }),
|
||||
);
|
||||
|
||||
await waitFor(() => {
|
||||
expect(result.current.loading).toBe(false);
|
||||
});
|
||||
|
||||
expect(mockFetchRemoteNodeTasks).toHaveBeenCalledTimes(1);
|
||||
expect(mockFetchRemoteNodeTasks).toHaveBeenLastCalledWith("node_abc", "proj_001", "test");
|
||||
|
||||
// Call refresh
|
||||
result.current.refresh();
|
||||
|
||||
await waitFor(() => {
|
||||
expect(result.current.loading).toBe(false);
|
||||
});
|
||||
|
||||
expect(mockFetchRemoteNodeTasks).toHaveBeenCalledTimes(2);
|
||||
expect(mockFetchRemoteNodeTasks).toHaveBeenLastCalledWith("node_abc", "proj_001", "test");
|
||||
});
|
||||
});
|
||||
|
||||
describe("useRemoteNodeData", () => {
|
||||
beforeEach(() => {
|
||||
mockFetchRemoteNodeHealth.mockReset();
|
||||
@@ -137,7 +391,7 @@ describe("useRemoteNodeData", () => {
|
||||
});
|
||||
|
||||
expect(mockFetchRemoteNodeTasks).toHaveBeenCalledTimes(1);
|
||||
expect(mockFetchRemoteNodeTasks).toHaveBeenCalledWith("node_abc", "proj_001");
|
||||
expect(mockFetchRemoteNodeTasks).toHaveBeenCalledWith("node_abc", "proj_001", undefined);
|
||||
expect(mockFetchRemoteNodeProjectHealth).toHaveBeenCalledTimes(1);
|
||||
expect(mockFetchRemoteNodeProjectHealth).toHaveBeenCalledWith("node_abc", "proj_001");
|
||||
expect(result.current.tasks).toEqual(mockTasks);
|
||||
|
||||
@@ -16,6 +16,8 @@ import {
|
||||
export interface UseRemoteNodeDataOptions {
|
||||
/** Project ID to fetch tasks for */
|
||||
projectId?: string;
|
||||
/** Search query to filter tasks */
|
||||
searchQuery?: string;
|
||||
}
|
||||
|
||||
export interface UseRemoteNodeDataResult {
|
||||
@@ -42,7 +44,7 @@ export function useRemoteNodeData(
|
||||
nodeId: string | null,
|
||||
options?: UseRemoteNodeDataOptions,
|
||||
): UseRemoteNodeDataResult {
|
||||
const { projectId } = options ?? {};
|
||||
const { projectId, searchQuery } = options ?? {};
|
||||
|
||||
const [projects, setProjects] = useState<ProjectInfo[]>([]);
|
||||
const [tasks, setTasks] = useState<Task[]>([]);
|
||||
@@ -81,7 +83,7 @@ export function useRemoteNodeData(
|
||||
|
||||
// Add tasks and project health fetches if projectId is provided
|
||||
if (projectId) {
|
||||
promises.push(fetchRemoteNodeTasks(nodeId, projectId));
|
||||
promises.push(fetchRemoteNodeTasks(nodeId, projectId, searchQuery));
|
||||
promises.push(fetchRemoteNodeProjectHealth(nodeId, projectId));
|
||||
}
|
||||
|
||||
@@ -130,7 +132,7 @@ export function useRemoteNodeData(
|
||||
setLoading(false);
|
||||
}
|
||||
}
|
||||
}, [nodeId, projectId]);
|
||||
}, [nodeId, projectId, searchQuery]);
|
||||
|
||||
// Fetch on mount and when nodeId changes
|
||||
useEffect(() => {
|
||||
|
||||
Reference in New Issue
Block a user