Skip to content

Commit

Permalink
Cluster node status frontend (#2345)
Browse files Browse the repository at this point in the history
* Add ClusterNodeName component

* Use the new component in cluster detail views

* Add e2e tests
  • Loading branch information
arbulu89 authored Feb 27, 2024
1 parent eb0f007 commit 9d1aaa9
Show file tree
Hide file tree
Showing 8 changed files with 126 additions and 6 deletions.
2 changes: 2 additions & 0 deletions assets/js/lib/test-utils/factories/clusters.js
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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()],
Expand Down
8 changes: 5 additions & 3 deletions assets/js/pages/ClusterDetails/AscsErsClusterDetails.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand All @@ -30,8 +30,10 @@ const nodeDetailsConfig = {
{
title: 'Hostname',
key: '',
render: (_, { id, name }) => (
<ClusterNodeLink hostId={id}>{name}</ClusterNodeLink>
render: (_, { id, name, status }) => (
<ClusterNodeName hostId={id} status={status}>
{name}
</ClusterNodeName>
),
},
{
Expand Down
40 changes: 40 additions & 0 deletions assets/js/pages/ClusterDetails/ClusterNodeName.jsx
Original file line number Diff line number Diff line change
@@ -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 <EOS_BOLT_FILLED className="tn-online" />;
}
case 'Offline': {
return <EOS_POWER_OFF_OUTLINED className="tn-offline" />;
}
case 'Maintenance': {
return <EOS_BUILD_OUTLINED className="tn-maintenance" />;
}
default: {
return <EOS_WARNING_OUTLINED className="tn-unknown" />;
}
}
};

function ClusterNodeName({ status, hostId, children }) {
return (
<span className="group flex items-center relative space-x-2">
<Tooltip content={status} place="bottom">
{getNodeStatusIcon(status)}
</Tooltip>
<ClusterNodeLink hostId={hostId}>{children}</ClusterNodeLink>
</span>
);
}

export default ClusterNodeName;
45 changes: 45 additions & 0 deletions assets/js/pages/ClusterDetails/ClusterNodeName.test.jsx
Original file line number Diff line number Diff line change
@@ -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(
<ClusterNodeName status={status} hostId={id}>
{hostname}
</ClusterNodeName>
);

const icon = screen.getByTestId('eos-svg-component');
expect(icon).toHaveClass(testID);
await act(async () => user.hover(icon));

expect(screen.getByText(status)).toBeVisible();
});
});
19 changes: 19 additions & 0 deletions assets/js/pages/ClusterDetails/HanaClusterDetails.stories.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -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',
Expand Down Expand Up @@ -130,6 +142,13 @@ export const HanaScaleOut = {
},
};

export const HanaScaleOutWithNodeStatuses = {
args: {
...HanaScaleOut.args,
details: scaleOutDetailsNodeStatus,
},
};

export const Loading = {
args: {
...Hana.args,
Expand Down
8 changes: 5 additions & 3 deletions assets/js/pages/ClusterDetails/HanaClusterSite.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand All @@ -27,8 +27,10 @@ const siteDetailsConfig = {
title: 'Hostname',
key: '',
className: 'table-col-m',
render: (_, hostData) => (
<ClusterNodeLink hostId={hostData.id}>{hostData.name}</ClusterNodeLink>
render: (_, { id, name, status }) => (
<ClusterNodeName hostId={id} status={status}>
{name}
</ClusterNodeName>
),
},
{
Expand Down
8 changes: 8 additions & 0 deletions test/e2e/cypress/e2e/hana_cluster_details.cy.js
Original file line number Diff line number Diff line change
Expand Up @@ -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);
});

Expand Down Expand Up @@ -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);
});
});
});
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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',
Expand Down Expand Up @@ -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',
Expand Down

0 comments on commit 9d1aaa9

Please sign in to comment.