diff --git a/assets/js/components/ExecutionResults/ExecutionResults.jsx b/assets/js/components/ExecutionResults/ExecutionResults.jsx index 31628f14df..868e94faa7 100644 --- a/assets/js/components/ExecutionResults/ExecutionResults.jsx +++ b/assets/js/components/ExecutionResults/ExecutionResults.jsx @@ -4,22 +4,57 @@ import Table from '@components/Table'; import ReactMarkdown from 'react-markdown'; import remarkGfm from 'remark-gfm'; import LoadingBox from '@components/LoadingBox'; +import Modal from '@components/Modal'; -import { getCheckResults, getCheckDescription } from './checksUtils'; +import { + getCheckResults, + getCheckDescription, + getCheckRemediation, +} from './checksUtils'; import ResultsContainer from './ResultsContainer'; import { ExecutionIcon } from './ExecutionIcon'; import CheckResultOutline from './CheckResultOutline'; import ExecutionHeader from './ExecutionHeader'; +const addHostnameToTargets = (targets, hostnames) => + targets?.map((target) => { + const { agent_id } = target; + + const { hostname } = hostnames.find(({ id }) => agent_id === id); + return { + ...target, + hostname, + }; + }); + +function MarkdownContent({ children }) { + return ( + + {children} + + ); +} + const resultsTableConfig = { usePadding: false, columns: [ { title: 'Id', key: 'checkID', - render: (checkID) => ( -
{checkID}
+ render: (checkID, item) => ( +
+ +
), }, { @@ -50,25 +85,6 @@ const resultsTableConfig = { ), }; -const addHostnameToTargets = (targets, hostnames) => - targets?.map((target) => { - const { agent_id } = target; - - const { hostname } = hostnames.find(({ id }) => agent_id === id); - return { - ...target, - hostname, - }; - }); - -function MarkdownContent({ children }) { - return ( - - {children} - - ); -} - function ExecutionResults({ clusterID, clusterName, @@ -89,6 +105,8 @@ function ExecutionResults({ onStartExecution = () => {}, }) { const [predicates, setPredicates] = useState([]); + const [selectedCheck, setSelectedCheck] = useState(null); + const [modalOpen, setModalOpen] = useState(false); const hosts = hostnames.map((item) => item.id); @@ -135,6 +153,10 @@ function ExecutionResults({ description: getCheckDescription(catalog, checkID), expectationResults, agentsCheckResults: addHostnameToTargets(agentsCheckResults, hostnames), + onClickRemediation: () => { + setModalOpen(true); + setSelectedCheck(checkID); + }, }) ); @@ -159,9 +181,23 @@ function ExecutionResults({ hosts={hosts} onContentRefresh={onContentRefresh} onStartExecution={onStartExecution} + selectedCheck={selectedCheck} > + + {getCheckDescription(catalog, selectedCheck)} + + } + onClose={() => setModalOpen(false)} + > + + {getCheckRemediation(catalog, selectedCheck)} + + ); } diff --git a/assets/js/components/ExecutionResults/ExecutionResults.test.jsx b/assets/js/components/ExecutionResults/ExecutionResults.test.jsx index 512e34f683..899778b245 100644 --- a/assets/js/components/ExecutionResults/ExecutionResults.test.jsx +++ b/assets/js/components/ExecutionResults/ExecutionResults.test.jsx @@ -1,6 +1,5 @@ import React from 'react'; -import { screen } from '@testing-library/react'; - +import { screen, fireEvent } from '@testing-library/react'; import { faker } from '@faker-js/faker'; import { renderWithRouter } from '@lib/test-utils'; @@ -411,4 +410,75 @@ describe('ExecutionResults', () => { ) ).toBeTruthy(); }); + + it('should open remediation modal when clicking on checkID', async () => { + const { + clusterID, + hostnames, + loading, + catalog, + executionError, + executionStarted, + executionResult, + checks, + } = prepareStateData('completed'); + + renderWithRouter( + + ); + + const { id: checkID, remediation } = catalog[0]; + const clickableID = screen.getByText(checkID); + expect(clickableID.textContent).toBe(checks[0]); + let remediationModalElement = screen.queryByText(remediation); + expect(remediationModalElement).not.toBeInTheDocument(); + fireEvent.click(clickableID); + remediationModalElement = screen.getByText(remediation); + expect(remediationModalElement).toBeInTheDocument(); + }); + + it('should not open remediation modal when clicking on description', async () => { + const { + clusterID, + hostnames, + loading, + catalog, + executionError, + executionStarted, + executionResult, + checks, + } = prepareStateData('completed'); + + renderWithRouter( + + ); + + const { remediation, description } = catalog[0]; + const checkDescriptionText = screen.getByText(description); + expect(description).toBe(checkDescriptionText.textContent); + let remediationModalElement = screen.queryByText(remediation); + fireEvent.click(checkDescriptionText); + remediationModalElement = screen.queryByText(remediation); + expect(remediationModalElement).not.toBeInTheDocument(); + }); });