diff --git a/frontend/relay-workflows-lib/lib/components/TasksFlow.tsx b/frontend/relay-workflows-lib/lib/components/TasksFlow.tsx index e5e77bd03..f2379240e 100644 --- a/frontend/relay-workflows-lib/lib/components/TasksFlow.tsx +++ b/frontend/relay-workflows-lib/lib/components/TasksFlow.tsx @@ -204,7 +204,7 @@ const TasksFlow: React.FC = ({ panOnDrag={true} preventScrolling={false} defaultViewport={defaultViewport} - fitView={false} + fitView={true} style={{ width: "100%", height: "100%", overflow: "auto" }} /> )} diff --git a/frontend/relay-workflows-lib/lib/components/WorkflowsContent.tsx b/frontend/relay-workflows-lib/lib/components/WorkflowsContent.tsx index 187b694ee..86ce2abeb 100644 --- a/frontend/relay-workflows-lib/lib/components/WorkflowsContent.tsx +++ b/frontend/relay-workflows-lib/lib/components/WorkflowsContent.tsx @@ -38,7 +38,7 @@ interface WorkflowsContentProps { onLimitChange: (limit: number) => void; updatePageInfo: (hasNextPage: boolean, endCursor: string | null) => void; isPaginated: boolean; - setIsPaginated: (b: boolean) => void; + setIsPaginated: (isPaginated: boolean) => void; } export default function WorkflowsContent({ @@ -60,6 +60,7 @@ export default function WorkflowsContent({ const pageInfo = data.pageInfo; const fetchedWorkflows = data.nodes; const prevFetchedRef = useRef([]); + const isPaginatedRef = useRef(isPaginated); const [expandedWorkflows, setExpandedWorkflows] = useState>( new Set(), @@ -74,12 +75,13 @@ export default function WorkflowsContent({ const prevNames = prevFetchedRef.current; const fetchedChanged = JSON.stringify(currentNames) !== JSON.stringify(prevNames); - if (fetchedChanged && isPaginated) { + if (fetchedChanged && isPaginatedRef.current) { setTimeout(() => { + isPaginatedRef.current = false; setIsPaginated(false); }, 0); } - }, [isPaginated, fetchedWorkflows, setIsPaginated]); + }, [isPaginatedRef, fetchedWorkflows, setIsPaginated]); const handleToggleExpanded = (name: string) => { setExpandedWorkflows((prev) => { diff --git a/frontend/relay-workflows-lib/lib/query-components/RetriggerWorkflow.tsx b/frontend/relay-workflows-lib/lib/query-components/RetriggerWorkflow.tsx index 2f26b011e..c60c19a15 100644 --- a/frontend/relay-workflows-lib/lib/query-components/RetriggerWorkflow.tsx +++ b/frontend/relay-workflows-lib/lib/query-components/RetriggerWorkflow.tsx @@ -46,7 +46,6 @@ const RetriggerWorkflowBase: React.FC = ({ return templateName ? ( void] { return [selectedTaskIds, setSelectedTaskIds]; } +function setFetchedTasks(data: WorkflowTasksFragment$data): Task[] { + if (data.status && isWorkflowWithTasks(data.status)) { + return data.status.tasks.map((task: Task) => ({ + id: task.id, + name: task.name, + status: task.status, + depends: [...(task.depends ?? [])], + artifacts: task.artifacts.map((artifact: Artifact) => ({ + ...artifact, + parentTask: task.name, + parentTaskId: task.id, + key: `${task.id}-${artifact.name}`, + })), + workflow: data.name, + instrumentSession: data.visit, + stepType: task.stepType, + })); + } + return []; +} + export function useFetchedTasks( fragmentRef: WorkflowTasksFragment$key | null, ): Task[] { - const [fetchedTasks, setFetchedTasks] = useState([]); const data = useFragment(WorkflowTasksFragment, fragmentRef); - useEffect(() => { - if (data && data.status && isWorkflowWithTasks(data.status)) { - setFetchedTasks( - data.status.tasks.map((task: Task) => ({ - id: task.id, - name: task.name, - status: task.status, - depends: [...(task.depends ?? [])], - artifacts: task.artifacts.map((artifact: Artifact) => ({ - ...artifact, - parentTask: task.name, - parentTaskId: task.id, - key: `${task.id}-${artifact.name}`, - })), - workflow: data.name, - instrumentSession: data.visit, - stepType: task.stepType, - })), - ); + const fetchedTasks: Task[] = useMemo(() => { + if (data == null) { + return []; } + return setFetchedTasks(data); }, [data]); return fetchedTasks; diff --git a/frontend/relay-workflows-lib/lib/views/BaseSingleWorkflowView.tsx b/frontend/relay-workflows-lib/lib/views/BaseSingleWorkflowView.tsx index 9e2690cd9..644771abf 100644 --- a/frontend/relay-workflows-lib/lib/views/BaseSingleWorkflowView.tsx +++ b/frontend/relay-workflows-lib/lib/views/BaseSingleWorkflowView.tsx @@ -34,8 +34,6 @@ export default function BaseSingleWorkflowView({ taskIds, fragmentRef, }: BaseSingleWorkflowViewProps) { - const [artifactList, setArtifactList] = useState([]); - const [outputTaskIds, setOutputTaskIds] = useState([]); const data = useFragment(BaseSingleWorkflowViewFragment, fragmentRef); const fetchedTasks = useFetchedTasks(data ?? null); const [selectedTaskIds, setSelectedTaskIds] = useSelectedTaskIds(); @@ -43,6 +41,26 @@ export default function BaseSingleWorkflowView({ const taskTree = useMemo(() => buildTaskTree(fetchedTasks), [fetchedTasks]); + const outputTaskIds: string[] = useMemo(() => { + const newOutputTaskIds: string[] = []; + const traverse = (tasks: TaskNode[]) => { + const sortedTasks = [...tasks].sort((a, b) => a.id.localeCompare(b.id)); + sortedTasks.forEach((taskNode) => { + if ( + taskNode.children && + taskNode.children.length === 0 && + !newOutputTaskIds.includes(taskNode.id) + ) { + newOutputTaskIds.push(taskNode.id); + } else if (taskNode.children && taskNode.children.length > 0) { + traverse(taskNode.children); + } + }); + }; + traverse(taskTree); + return newOutputTaskIds; + }, [taskTree]); + const handleSelectOutput = () => { setSelectedTaskIds(outputTaskIds); }; @@ -62,35 +80,15 @@ export default function BaseSingleWorkflowView({ setSelectedTaskIds(taskIds ?? []); }, [taskIds, setSelectedTaskIds]); - useEffect(() => { + const artifactList: Artifact[] = useMemo(() => { const filteredTasks = selectedTaskIds.length ? selectedTaskIds .map((id) => fetchedTasks.find((task) => task.id === id)) .filter((task): task is Task => !!task) : fetchedTasks; - setArtifactList(filteredTasks.flatMap((task) => task.artifacts)); + return filteredTasks.flatMap((task) => task.artifacts); }, [selectedTaskIds, fetchedTasks]); - useEffect(() => { - const newOutputTaskIds: string[] = []; - const traverse = (tasks: TaskNode[]) => { - const sortedTasks = [...tasks].sort((a, b) => a.id.localeCompare(b.id)); - sortedTasks.forEach((taskNode) => { - if ( - taskNode.children && - taskNode.children.length === 0 && - !newOutputTaskIds.includes(taskNode.id) - ) { - newOutputTaskIds.push(taskNode.id); - } else if (taskNode.children && taskNode.children.length > 0) { - traverse(taskNode.children); - } - }); - }; - traverse(taskTree); - setOutputTaskIds(newOutputTaskIds); - }, [taskTree]); - if (!data || !data.status) { return null; } diff --git a/frontend/relay-workflows-lib/lib/views/WorkflowsListView.tsx b/frontend/relay-workflows-lib/lib/views/WorkflowsListView.tsx index 4b25307d2..a4d038706 100644 --- a/frontend/relay-workflows-lib/lib/views/WorkflowsListView.tsx +++ b/frontend/relay-workflows-lib/lib/views/WorkflowsListView.tsx @@ -72,10 +72,14 @@ const WorkflowsListView: React.FC = ({ { fetchPolicy: "store-and-network" }, ); - const [isPaginated, setIsPaginated] = useState(false); + const isPaginated = useRef(false); const lastPage = useRef(currentPage); const lastLimit = useRef(selectedLimit); + const setIsPaginated = useCallback((value: boolean) => { + isPaginated.current = value; + }, []); + const load = useCallback(() => { if (visit) { loadQuery( @@ -98,7 +102,7 @@ const WorkflowsListView: React.FC = ({ currentPage !== lastPage.current || selectedLimit !== lastLimit.current ) { - setIsPaginated(true); + isPaginated.current = true; lastPage.current = currentPage; lastLimit.current = selectedLimit; } @@ -154,7 +158,7 @@ const WorkflowsListView: React.FC = ({ onPageChange={goToPage} onLimitChange={changeLimit} updatePageInfo={updatePageInfo} - isPaginated={isPaginated} + isPaginated={isPaginated.current} setIsPaginated={setIsPaginated} /> diff --git a/frontend/relay-workflows-lib/stories/components/WorkflowsContent.stories.tsx b/frontend/relay-workflows-lib/stories/components/WorkflowsContent.stories.tsx index e8ecb6af3..565a99a16 100644 --- a/frontend/relay-workflows-lib/stories/components/WorkflowsContent.stories.tsx +++ b/frontend/relay-workflows-lib/stories/components/WorkflowsContent.stories.tsx @@ -68,6 +68,5 @@ export const Default: Story = { onPageChange: () => {}, onLimitChange: () => {}, updatePageInfo: () => {}, - setIsPaginated: () => {}, }, }; diff --git a/frontend/relay-workflows-lib/tests/components/BaseWorkflowRelay.test.tsx b/frontend/relay-workflows-lib/tests/components/BaseWorkflowRelay.test.tsx index 890b0f7e0..d47331f20 100644 --- a/frontend/relay-workflows-lib/tests/components/BaseWorkflowRelay.test.tsx +++ b/frontend/relay-workflows-lib/tests/components/BaseWorkflowRelay.test.tsx @@ -78,8 +78,8 @@ describe("BaseWorkflowRelay", () => { expect(screen.queryByText("even")).not.toBeVisible(); await user.click(accordionButton); - expect(accordionButton).toHaveAttribute("aria-expanded", "true"); - expect(screen.getByText("even")).toBeVisible(); + expect(screen.getByText("React Flow")).toBeVisible(); + expect(screen.getByText("even")).toBeInTheDocument(); }); }); diff --git a/frontend/relay-workflows-lib/tests/components/TasksFlow.test.tsx b/frontend/relay-workflows-lib/tests/components/TasksFlow.test.tsx index 4e440db94..f9bff5169 100644 --- a/frontend/relay-workflows-lib/tests/components/TasksFlow.test.tsx +++ b/frontend/relay-workflows-lib/tests/components/TasksFlow.test.tsx @@ -112,7 +112,7 @@ describe("TasksFlow Component", () => { nodes: mockLayoutedNodes, edges: mockLayoutedEdges, // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment - nodeTypes: expect.objectContaining({ custom: expect.any(Function) }), + nodeTypes: { custom: expect.any(Function) }, nodesDraggable: false, nodesConnectable: false, elementsSelectable: true, @@ -121,7 +121,7 @@ describe("TasksFlow Component", () => { zoomOnDoubleClick: false, panOnDrag: true, preventScrolling: false, - fitView: false, + fitView: true, style: { width: "100%", overflow: "auto", height: "100%" }, }), {}, diff --git a/frontend/workflows-lib/lib/components/common/PaginationControls.tsx b/frontend/workflows-lib/lib/components/common/PaginationControls.tsx index 935644844..9e44fe8ca 100644 --- a/frontend/workflows-lib/lib/components/common/PaginationControls.tsx +++ b/frontend/workflows-lib/lib/components/common/PaginationControls.tsx @@ -42,11 +42,12 @@ export default function PaginationControls({ boundaryCount={0} /> - Workflows Limit + Limit