diff --git a/assets/js/components/Health/HealthIcon.jsx b/assets/js/components/Health/HealthIcon.jsx index 435fc29f56..322d396a12 100644 --- a/assets/js/components/Health/HealthIcon.jsx +++ b/assets/js/components/Health/HealthIcon.jsx @@ -15,6 +15,7 @@ function HealthIcon({ health = undefined, centered = false, hoverOpacity = true, + size = 'l', }) { const hoverOpacityClass = { 'hover:opacity-75': hoverOpacity, @@ -24,7 +25,7 @@ function HealthIcon({ case 'passing': return ( ; +} + +export function Warning() { + return ; +} + +export function Critical() { + return ; +} + +export function Pending() { + return ; +} + +export function Default() { + return ; +} + +export function ExtraLarge() { + return ; +} diff --git a/assets/js/components/Health/HealthIcon.test.jsx b/assets/js/components/Health/HealthIcon.test.jsx index 149ac72c66..f475ec3bd1 100644 --- a/assets/js/components/Health/HealthIcon.test.jsx +++ b/assets/js/components/Health/HealthIcon.test.jsx @@ -11,6 +11,7 @@ describe('HealthIcon', () => { expect(svgEl.classList.toString()).toContain( 'hover:opacity-75 fill-jungle-green-500' ); + expect(svgEl).toHaveAttribute('width', '24'); }); it('should display a yellow svg when the health is warning', () => { const { container } = render(); @@ -32,4 +33,9 @@ describe('HealthIcon', () => { const svgEl = container.querySelector("[data-testid='eos-svg-component']"); expect(svgEl.classList.toString()).toContain('hover:opacity-100'); }); + it('should display the icon with the applied size', () => { + const { container } = render(); + const svgEl = container.querySelector("[data-testid='eos-svg-component']"); + expect(svgEl).toHaveAttribute('width', '18'); + }); }); diff --git a/assets/js/components/HostDetails/HostDetails.jsx b/assets/js/components/HostDetails/HostDetails.jsx index 26fbd8a678..2782f96498 100644 --- a/assets/js/components/HostDetails/HostDetails.jsx +++ b/assets/js/components/HostDetails/HostDetails.jsx @@ -3,6 +3,7 @@ import { useParams } from 'react-router-dom'; import { useSelector } from 'react-redux'; import { networkClient } from '@lib/network'; +import { agentVersionWarning } from '@lib/agent'; import ListView from '@components/ListView'; import Table from '@components/Table'; @@ -10,6 +11,7 @@ import Table from '@components/Table'; import PageHeader from '@components/PageHeader'; import BackButton from '@components/BackButton'; import ClusterLink from '@components/ClusterLink'; +import WarningBanner from '@components/Banners/WarningBanner'; import SuseLogo from '@static/suse_logo.svg'; import { getInstancesOnHost, @@ -50,6 +52,8 @@ function HostDetails() { return
Not Found
; } + const versionWarningMessage = agentVersionWarning(host.agent_version); + return (
Back to Hosts @@ -76,6 +80,9 @@ function HostDetails() { ) )}
+ {versionWarningMessage && ( + {versionWarningMessage} + )}
{ + beforeEach(() => { + axiosMock.reset(); + }); + + it('should not show any warning message if the agent version is correct', () => { + const hosts = hostFactory.buildList(1, { agent_version: '2.0.0' }); + const { id: hostID } = hosts[0]; + const state = { + ...defaultInitialState, + hostsList: { + hosts, + }, + }; + const [StatefulHostDetails] = withState(, state); + + renderWithRouterMatch(StatefulHostDetails, { + path: '/hosts/:hostID', + route: `/hosts/${hostID}`, + }); + + expect( + screen.queryByText( + 'Agent version 2.0.0 or greater is required for the new checks engine.' + ) + ).not.toBeInTheDocument(); + }); + + it('should show 2.0.0 version required warning message', () => { + const hosts = hostFactory.buildList(1, { agent_version: '1.0.0' }); + const { id: hostID } = hosts[0]; + const state = { + ...defaultInitialState, + hostsList: { + hosts, + }, + }; + const [StatefulHostDetails] = withState(, state); + + renderWithRouterMatch(StatefulHostDetails, { + path: '/hosts/:hostID', + route: `/hosts/${hostID}`, + }); + + expect( + screen.getByText( + 'Agent version 2.0.0 or greater is required for the new checks engine.' + ) + ).toBeInTheDocument(); + }); +}); diff --git a/assets/js/components/HostsList.jsx b/assets/js/components/HostsList.jsx index cf9cc279bd..108fbcfa1a 100644 --- a/assets/js/components/HostsList.jsx +++ b/assets/js/components/HostsList.jsx @@ -1,19 +1,25 @@ -import React, { Fragment } from 'react'; +import React from 'react'; + +import { useSearchParams } from 'react-router-dom'; +import { useSelector, useDispatch } from 'react-redux'; +import { EOS_WARNING_OUTLINED } from 'eos-icons-react'; + import Table from '@components/Table'; import HealthIcon from '@components/Health/HealthIcon'; -import { useSearchParams } from 'react-router-dom'; import Tags from '@components/Tags'; -import { addTagToHost, removeTagFromHost } from '@state/hosts'; import HostLink from '@components/HostLink'; import ClusterLink from '@components/ClusterLink'; import SapSystemLink from '@components/SapSystemLink'; import PageHeader from '@components/PageHeader'; -import { useSelector, useDispatch } from 'react-redux'; - -import { post, del } from '@lib/network'; +import Pill from '@components/Pill'; import HealthSummary from '@components/HealthSummary/HealthSummary'; import { getCounters } from '@components/HealthSummary/summarySelection'; import ProviderLabel from '@components/ProviderLabel'; +import Tooltip from '@components/Tooltip'; + +import { addTagToHost, removeTagFromHost } from '@state/hosts'; +import { post, del } from '@lib/network'; +import { agentVersionWarning } from '@lib/agent'; const getInstancesByHost = (applicationInstances, databaseInstances, hostId) => applicationInstances @@ -118,11 +124,33 @@ function HostsList() { { title: 'Agent version', key: 'agent_version', - render: (content) => ( - - {content} - - ), + render: (content) => { + const warning = agentVersionWarning(content); + if (warning) { + return ( + + + {content} + + + ); + } + return ( + + {content} + + ); + }, }, { title: 'Tags', diff --git a/assets/js/components/HostsList.test.jsx b/assets/js/components/HostsList.test.jsx index 2c021addf9..bea4874217 100644 --- a/assets/js/components/HostsList.test.jsx +++ b/assets/js/components/HostsList.test.jsx @@ -1,10 +1,16 @@ import React from 'react'; import { screen, waitFor } from '@testing-library/react'; +import userEvent from '@testing-library/user-event'; import 'intersection-observer'; import '@testing-library/jest-dom'; import { hostFactory } from '@lib/test-utils/factories'; -import { renderWithRouter, withDefaultState, withState } from '@lib/test-utils'; +import { + renderWithRouter, + withDefaultState, + withState, + defaultInitialState, +} from '@lib/test-utils'; import { filterTable, clearFilter } from '@components/Table/Table.test'; @@ -50,6 +56,47 @@ describe('HostsLists component', () => { ); }); }); + + it('should show a warning state if the agent version is not compatible', () => { + const user = userEvent.setup(); + + const host1 = hostFactory.build({ agent_version: '1.0.0' }); + const host2 = hostFactory.build({ agent_version: '2.0.0' }); + const state = { + ...defaultInitialState, + hostsList: { + hosts: [].concat(host1, host2), + }, + }; + + const [StatefulHostsList] = withState(, state); + + renderWithRouter(StatefulHostsList); + const table = screen.getByRole('table'); + const host1VersionCell = table.querySelector( + 'tr:nth-child(1) > td:nth-child(7)' + ); + expect(host1VersionCell).toHaveTextContent('1.0.0'); + const icon1 = host1VersionCell.querySelector( + "[data-testid='eos-svg-component']" + ); + expect(icon1.classList.toString()).toContain('fill-yellow-800'); + + const host2VersionCell = table.querySelector( + 'tr:nth-child(2) > td:nth-child(7)' + ); + expect(host2VersionCell).toHaveTextContent('2.0.0'); + expect( + host2VersionCell.querySelector("[data-testid='eos-svg-component']") + ).toBeNull(); + + user.hover(host2VersionCell); + expect( + screen.queryByText( + 'Agent version 2.0.0 or greater is required for the new checks engine.' + ) + ).toBeInTheDocument(); + }); }); describe('filtering', () => { diff --git a/assets/js/components/Pill/Pill.jsx b/assets/js/components/Pill/Pill.jsx index b5133d853e..c43c0973fa 100644 --- a/assets/js/components/Pill/Pill.jsx +++ b/assets/js/components/Pill/Pill.jsx @@ -12,17 +12,19 @@ function Pill({ onClick = () => {}, size = 'sm', roundedMode = 'rounded-full', + display = 'inline-flex', }) { return (