diff --git a/assets/js/lib/test-utils/factories/clusters.js b/assets/js/lib/test-utils/factories/clusters.js index c0c2898884..369fed345e 100644 --- a/assets/js/lib/test-utils/factories/clusters.js +++ b/assets/js/lib/test-utils/factories/clusters.js @@ -43,6 +43,7 @@ export const hanaClusterDetailsNodesFactory = Factory.define(() => ({ indexserver_actual_role: 'master', nameserver_actual_role: 'slave', hana_status: hanaStatus(), + status: 'Online', attributes: Array.from({ length: 5 }).reduce( (acc, _) => ({ ...acc, @@ -75,6 +76,7 @@ export const hanaClusterDetailsFactory = Factory.define(() => { export const ascsErsClusterNodeFactory = Factory.define(({ sequence }) => ({ name: `${faker.person.firstName()}_${sequence}`, + status: 'Online', roles: [ascsErsRole()], virtual_ips: [faker.internet.ip()], filesystems: [faker.system.filePath()], diff --git a/assets/js/pages/ClusterDetails/AscsErsClusterDetails.jsx b/assets/js/pages/ClusterDetails/AscsErsClusterDetails.jsx index ccf354bc9e..3593ad031a 100644 --- a/assets/js/pages/ClusterDetails/AscsErsClusterDetails.jsx +++ b/assets/js/pages/ClusterDetails/AscsErsClusterDetails.jsx @@ -16,7 +16,7 @@ import SapSystemLink from '@common/SapSystemLink'; import Table from '@common/Table'; import Tooltip from '@common/Tooltip'; -import ClusterNodeLink from '@pages/ClusterDetails/ClusterNodeLink'; +import ClusterNodeName from '@pages/ClusterDetails/ClusterNodeName'; import CheckResultsOverview from '@pages/CheckResultsOverview'; import AttributesDetails from './AttributesDetails'; @@ -30,8 +30,10 @@ const nodeDetailsConfig = { { title: 'Hostname', key: '', - render: (_, { id, name }) => ( - {name} + render: (_, { id, name, status }) => ( + + {name} + ), }, { diff --git a/assets/js/pages/ClusterDetails/ClusterNodeName.jsx b/assets/js/pages/ClusterDetails/ClusterNodeName.jsx new file mode 100644 index 0000000000..4fda61a792 --- /dev/null +++ b/assets/js/pages/ClusterDetails/ClusterNodeName.jsx @@ -0,0 +1,40 @@ +import React from 'react'; +import { + EOS_BOLT_FILLED, + EOS_WARNING_OUTLINED, + EOS_BUILD_OUTLINED, + EOS_POWER_OFF_OUTLINED, +} from 'eos-icons-react'; + +import Tooltip from '@common/Tooltip'; +import ClusterNodeLink from './ClusterNodeLink'; + +const getNodeStatusIcon = (status) => { + switch (status) { + case 'Online': { + return ; + } + case 'Offline': { + return ; + } + case 'Maintenance': { + return ; + } + default: { + return ; + } + } +}; + +function ClusterNodeName({ status, hostId, children }) { + return ( + + + {getNodeStatusIcon(status)} + + {children} + + ); +} + +export default ClusterNodeName; diff --git a/assets/js/pages/ClusterDetails/ClusterNodeName.test.jsx b/assets/js/pages/ClusterDetails/ClusterNodeName.test.jsx new file mode 100644 index 0000000000..18462781ca --- /dev/null +++ b/assets/js/pages/ClusterDetails/ClusterNodeName.test.jsx @@ -0,0 +1,45 @@ +import React from 'react'; +import { screen, act } from '@testing-library/react'; +import userEvent from '@testing-library/user-event'; +import '@testing-library/jest-dom'; +import { renderWithRouter } from '@lib/test-utils'; +import { hostFactory } from '@lib/test-utils/factories'; + +import ClusterNodeName from './ClusterNodeName'; + +describe('ClusterNodeName', () => { + it.each([ + { + status: 'Online', + testID: 'tn-online', + }, + { + status: 'Offline', + testID: 'tn-offline', + }, + { + status: 'Maintenance', + testID: 'tn-maintenance', + }, + { + status: 'Other', + testID: 'tn-unknown', + }, + ])('renders correct icon', async ({ status, testID }) => { + const user = userEvent.setup(); + + const { id, hostname } = hostFactory.build(); + + renderWithRouter( + + {hostname} + + ); + + const icon = screen.getByTestId('eos-svg-component'); + expect(icon).toHaveClass(testID); + await act(async () => user.hover(icon)); + + expect(screen.getByText(status)).toBeVisible(); + }); +}); diff --git a/assets/js/pages/ClusterDetails/HanaClusterDetails.stories.jsx b/assets/js/pages/ClusterDetails/HanaClusterDetails.stories.jsx index 5c52bbfe38..7fd835afa4 100644 --- a/assets/js/pages/ClusterDetails/HanaClusterDetails.stories.jsx +++ b/assets/js/pages/ClusterDetails/HanaClusterDetails.stories.jsx @@ -58,6 +58,18 @@ const scaleOutDetails = hanaClusterDetailsFactory.build({ }), ], }); + +const scaleOutDetailsNodeStatus = { + ...scaleOutDetails, + nodes: [ + { ...scaleOutDetails.nodes[0], status: 'Online' }, + { ...scaleOutDetails.nodes[1], status: 'Offline' }, + { ...scaleOutDetails.nodes[2], status: 'Standby' }, + { ...scaleOutDetails.nodes[3], status: 'Maintenance' }, + { ...scaleOutDetails.nodes[4], status: 'Other' }, + ], +}; + const lastExecution = { data: checksExecutionCompletedFactory.build({ result: 'passing', @@ -130,6 +142,13 @@ export const HanaScaleOut = { }, }; +export const HanaScaleOutWithNodeStatuses = { + args: { + ...HanaScaleOut.args, + details: scaleOutDetailsNodeStatus, + }, +}; + export const Loading = { args: { ...Hana.args, diff --git a/assets/js/pages/ClusterDetails/HanaClusterSite.jsx b/assets/js/pages/ClusterDetails/HanaClusterSite.jsx index 9bba036122..059704a938 100644 --- a/assets/js/pages/ClusterDetails/HanaClusterSite.jsx +++ b/assets/js/pages/ClusterDetails/HanaClusterSite.jsx @@ -4,7 +4,7 @@ import { capitalize } from 'lodash'; import HealthIcon from '@common/HealthIcon'; import Table from '@common/Table'; -import ClusterNodeLink from '@pages/ClusterDetails/ClusterNodeLink'; +import ClusterNodeName from '@pages/ClusterDetails/ClusterNodeName'; import AttributesDetails from './AttributesDetails'; import ReplicationStatusPill from './ReplicationStatusPill'; @@ -27,8 +27,10 @@ const siteDetailsConfig = { title: 'Hostname', key: '', className: 'table-col-m', - render: (_, hostData) => ( - {hostData.name} + render: (_, { id, name, status }) => ( + + {name} + ), }, { diff --git a/test/e2e/cypress/e2e/hana_cluster_details.cy.js b/test/e2e/cypress/e2e/hana_cluster_details.cy.js index 9a9b6fd351..4f6f8c0b21 100644 --- a/test/e2e/cypress/e2e/hana_cluster_details.cy.js +++ b/test/e2e/cypress/e2e/hana_cluster_details.cy.js @@ -158,6 +158,7 @@ context('HANA cluster details', () => { it(`should have correct SR health state in site ${site.name}`, () => { cy.get(`.tn-site-details-${site.name}`) .find('svg') + .eq(0) .should('have.class', site.srHealthState); }); @@ -185,6 +186,13 @@ context('HANA cluster details', () => { capitalize(host.nameserver_actual_role) ); }); + + it(`${host.hostname} should have the expected status`, () => { + cy.get(`.tn-site-details-${site.name}`) + .find('svg') + .eq(1) + .should('have.class', host.status); + }); }); }); }); diff --git a/test/e2e/cypress/fixtures/hana-cluster-details/available_hana_cluster.js b/test/e2e/cypress/fixtures/hana-cluster-details/available_hana_cluster.js index 944dd22c91..4a701b84f5 100644 --- a/test/e2e/cypress/fixtures/hana-cluster-details/available_hana_cluster.js +++ b/test/e2e/cypress/fixtures/hana-cluster-details/available_hana_cluster.js @@ -24,6 +24,7 @@ export const availableHanaCluster = { role: 'Primary', indexserver_actual_role: 'master', nameserver_actual_role: 'master', + status: 'tn-online', attributes: [ { attribute: 'hana_hdp_clone_state', @@ -122,6 +123,7 @@ export const availableHanaCluster = { role: 'Secondary', indexserver_actual_role: 'master', nameserver_actual_role: 'master', + status: 'tn-online', attributes: [ { attribute: 'hana_hdp_clone_state',