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',