From 12c486f86b2e06a81ed3415f6e60e0bf874a0b88 Mon Sep 17 00:00:00 2001 From: Randy Schott <1815175+schottra@users.noreply.github.com> Date: Fri, 6 Nov 2020 10:53:31 -0800 Subject: [PATCH] fix: stale selected item reference in NE details panel (#115) * fix: stale selected item reference in NE details panel * refactor: syntax cleanup --- .../Tables/test/NodeExecutionsTable.test.tsx | 58 ++++++++++++++----- .../Tables/useNodeExecutionsTableState.ts | 21 +++++-- src/components/common/DetailsPanel.tsx | 1 + 3 files changed, 62 insertions(+), 18 deletions(-) diff --git a/src/components/Executions/Tables/test/NodeExecutionsTable.test.tsx b/src/components/Executions/Tables/test/NodeExecutionsTable.test.tsx index 9467f188f..27d34de29 100644 --- a/src/components/Executions/Tables/test/NodeExecutionsTable.test.tsx +++ b/src/components/Executions/Tables/test/NodeExecutionsTable.test.tsx @@ -1,8 +1,10 @@ import { fireEvent, getAllByRole, + getByText, getByTitle, render, + screen, waitFor } from '@testing-library/react'; import { mockAPIContextValue } from 'components/data/__mocks__/apiContext'; @@ -45,6 +47,7 @@ import { listTaskExecutionChildren, listTaskExecutions } from 'models/Execution/api'; +import { NodeExecutionPhase } from 'models/Execution/enums'; import { mockTasks } from 'models/Task/__mocks__/mockTaskData'; import * as React from 'react'; import { makeIdentifier } from 'test/modelUtils'; @@ -137,20 +140,19 @@ describe('NodeExecutionsTable', () => { }; }); - const renderTable = () => - render( - - - - - - - - - - ); + const Table = (props: NodeExecutionsTableProps) => ( + + + + + + + + + + ); + + const renderTable = () => render(); it('renders task name for task nodes', async () => { const { queryAllByText } = renderTable(); @@ -413,4 +415,32 @@ describe('NodeExecutionsTable', () => { }) ); }); + + describe('when rendering the DetailsPanel', () => { + const selectFirstNode = async (container: HTMLElement) => { + const { nodeId } = mockNodeExecutions[0].id; + const nodeNameAnchor = await waitFor(() => + getByText(container, nodeId) + ); + fireEvent.click(nodeNameAnchor); + // Wait for Details Panel to render and then for the nodeId header + const detailsPanel = await waitFor(() => + screen.getByTestId('details-panel') + ); + await waitFor(() => getByText(detailsPanel, nodeId)); + return detailsPanel; + }; + it('should render updated state if selected nodeExecution object changes', async () => { + mockNodeExecutions[0].closure.phase = NodeExecutionPhase.RUNNING; + // Render table, click first node + const { container, rerender } = renderTable(); + const detailsPanel = await selectFirstNode(container); + await waitFor(() => getByText(detailsPanel, 'Running')); + + props.value = cloneDeep(mockNodeExecutions); + props.value[0].closure.phase = NodeExecutionPhase.FAILED; + rerender(
); + await waitFor(() => getByText(detailsPanel, 'Failed')); + }); + }); }); diff --git a/src/components/Executions/Tables/useNodeExecutionsTableState.ts b/src/components/Executions/Tables/useNodeExecutionsTableState.ts index 579d44abb..62ee6010b 100644 --- a/src/components/Executions/Tables/useNodeExecutionsTableState.ts +++ b/src/components/Executions/Tables/useNodeExecutionsTableState.ts @@ -14,10 +14,23 @@ export function useNodeExecutionsTableState({ [value] ); - const [ - selectedExecution, - setSelectedExecution - ] = useState(null); + const [selectedExecutionKey, setSelectedExecutionKey] = useState< + string | null + >(null); + + const selectedExecution = useMemo( + () => + executions.find( + ({ cacheKey }) => cacheKey === selectedExecutionKey + ) || null, + [executions, selectedExecutionKey] + ); + + const setSelectedExecution = useMemo( + () => (newValue: DetailedNodeExecution | null) => + setSelectedExecutionKey(newValue?.cacheKey ?? null), + [setSelectedExecutionKey] + ); return { executions, diff --git a/src/components/common/DetailsPanel.tsx b/src/components/common/DetailsPanel.tsx index bc00d1b85..3f9f41258 100644 --- a/src/components/common/DetailsPanel.tsx +++ b/src/components/common/DetailsPanel.tsx @@ -41,6 +41,7 @@ export const DetailsPanel: React.FC = ({ return (