Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Cluster node status frontend #2345

Merged
merged 3 commits into from
Feb 27, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading