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

Saptune summary frontend #1796

Merged
merged 8 commits into from
Sep 12, 2023
Merged
Show file tree
Hide file tree
Changes from 5 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
80 changes: 68 additions & 12 deletions assets/js/components/HostDetails/HostDetails.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import classNames from 'classnames';
import { EOS_CLEAR_ALL, EOS_PLAY_CIRCLE, EOS_SETTINGS } from 'eos-icons-react';

import { agentVersionWarning } from '@lib/agent';
import { isVersionSupported } from '@lib/saptune';

import Button from '@components/Button';
import ListView from '@components/ListView';
Expand All @@ -15,8 +16,10 @@ import WarningBanner from '@components/Banners/WarningBanner';
import CleanUpButton from '@components/CleanUpButton';
import DeregistrationModal from '@components/DeregistrationModal';
import { canStartExecution } from '@components/ChecksSelection';
import { SaptuneVersion, SaptuneTuningState } from '@components/SaptuneDetails';

import SuseLogo from '@static/suse_logo.svg';
import ChecksComingSoon from '@static/checks-coming-soon.svg';

import StatusPill from './StatusPill';
import ProviderDetails from './ProviderDetails';
Expand All @@ -36,10 +39,12 @@ function HostDetails({
heartbeat,
hostID,
hostname,
ipAddresses = [],
provider,
providerData,
sapInstances,
savingChecks,
saptuneStatus = {},
selectedChecks = [],
slesSubscriptions,
cleanUpHost,
Expand All @@ -50,6 +55,12 @@ function HostDetails({

const versionWarningMessage = agentVersionWarning(agentVersion);

const {
package_version: saptuneVersion,
configured_version: saptuneConfigureVersion,
tuning_state: saptuneTuning,
} = saptuneStatus;

const renderedExporters = Object.entries(exportersStatus).map(
([exporterName, exporterStatus]) => (
<StatusPill
Expand Down Expand Up @@ -140,18 +151,63 @@ function HostDetails({
{versionWarningMessage && (
<WarningBanner>{versionWarningMessage}</WarningBanner>
)}
<div className="mt-4 bg-white shadow rounded-lg py-4 px-8">
<ListView
orientation="vertical"
data={[
{ title: 'Name', content: hostname },
{
title: 'Cluster',
content: <ClusterLink cluster={cluster} />,
},
{ title: 'Agent version', content: agentVersion },
]}
/>
<div className="flex xl:flex-row flex-col">
arbulu89 marked this conversation as resolved.
Show resolved Hide resolved
<div className="mt-4 bg-white shadow rounded-lg py-4 px-8 xl:w-2/5 mr-4">
<ListView
className="grid-rows-3"
orientation="vertical"
data={[
{
title: 'Cluster',
content: <ClusterLink cluster={cluster} />,
},
{ title: 'Agent Version', content: agentVersion },
{ title: 'IP addresses', content: ipAddresses.join(',') },
]}
/>
</div>
<div className="flex flex-col mt-4 bg-white shadow rounded-lg pt-8 px-8 xl:w-2/5 mr-4">
<div className="flex justify-between mb-2">
<h1 className="text-2xl font-bold">Saptune Summary</h1>
<Button
type="primary-white-fit"
className="border-green-500 border"
size="small"
disabled={!isVersionSupported(saptuneVersion)}
>
View Details
</Button>
</div>
<ListView
className="grid-rows-2"
orientation="vertical"
data={[
{
title: 'Package',
content: <SaptuneVersion version={saptuneVersion} />,
},
{
title: 'Tunning',
content: <SaptuneTuningState state={saptuneTuning} />,
},
{
title: 'Configured Version',
content: saptuneConfigureVersion || '-',
},
]}
/>
</div>
<div className="mt-4 bg-white shadow rounded-lg py-4 xl:w-1/4">
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@dottorblaster @nelsonkopliku I guess we will need to have some checksAvailable kind of variable to decide if we put this coming soon or the results box.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess, so. We'll be working on that soon.

<div className="flex flex-col items-center h-full">
<h1 className="text-center text-2xl font-bold">Check Results</h1>
<h6 className="opacity-60 text-xs">Coming soon for Hosts</h6>
<img
className="h-full inline-block align-middle"
alt="checks coming soon"
src={ChecksComingSoon}
/>
</div>
</div>
</div>
<div className="mt-8 bg-white shadow rounded-lg py-4 px-8">
<iframe
Expand Down
36 changes: 36 additions & 0 deletions assets/js/components/HostDetails/HostDetails.stories.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,10 @@ export default {
type: { summary: 'string' },
},
},
ipAddresses: {
control: { type: 'array' },
description: 'IP addresses',
},
provider: {
control: 'string',
description: 'The discovered CSP where the host is running',
Expand All @@ -98,6 +102,10 @@ export default {
control: { type: 'array' },
description: 'SAP systems running on the host',
},
saptuneStatus: {
control: 'object',
description: 'Saptune status data',
},
savingChecks: {
control: { type: 'boolean' },
description: 'The checks are being saved',
Expand Down Expand Up @@ -151,10 +159,16 @@ export const Default = {
heartbeat: host.heartbeat,
hostID: host.id,
hostname: host.hostname,
ipAddresses: host.ip_addresses,
provider: host.provider,
providerData: host.provider_data,
sapInstances,
savingChecks: false,
saptuneStatus: {
package_version: '3.1.0',
configured_version: '3',
tuning_state: 'no tuning',
},
selectedChecks: [],
slesSubscriptions: host.sles_subscriptions,
},
Expand All @@ -180,3 +194,25 @@ export const ChecksSelected = {
selectedChecks: ['some-check'],
},
};

export const SaptuneNotInstalled = {
args: {
...Default.args,
saptuneStatus: {
package_version: null,
configured_version: null,
tuning_state: null,
},
},
};

export const SaptuneOldVersion = {
args: {
...Default.args,
saptuneStatus: {
package_version: '3.0.0',
configured_version: null,
tuning_state: null,
},
},
};
62 changes: 61 additions & 1 deletion assets/js/components/HostDetails/HostDetails.test.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,9 @@ import 'intersection-observer';
import '@testing-library/jest-dom';
import { faker } from '@faker-js/faker';

import { SUPPORTED_VERSION } from '@lib/saptune';
import { renderWithRouter } from '@lib/test-utils';
import { hostFactory } from '@lib/test-utils/factories';
import { hostFactory, saptuneStatusFactory } from '@lib/test-utils/factories';

import HostDetails from './HostDetails';

Expand Down Expand Up @@ -132,4 +133,63 @@ describe('HostDetails component', () => {
expect(mockCleanUp).toHaveBeenCalled();
});
});

describe('saptune', () => {
it('should show the summary of saptune', () => {
const saptuneStatus = saptuneStatusFactory.build();
const {
package_version: packageVersion,
configured_version: configuredVersion,
tuning_state: tuningState,
} = saptuneStatus;

renderWithRouter(
<HostDetails agentVersion="2.0.0" saptuneStatus={saptuneStatus} />
);

expect(screen.getByText('Package').nextSibling).toHaveTextContent(
packageVersion
);

expect(
screen.getByText('Configured Version').nextSibling
).toHaveTextContent(configuredVersion);

expect(screen.getByText('Tunning').nextSibling).toHaveTextContent(
new RegExp(tuningState, 'i')
);
});

it('should enable saptune details button', () => {
const saptuneStatus = saptuneStatusFactory.build({
package_version: SUPPORTED_VERSION,
});

renderWithRouter(
<HostDetails agentVersion="2.0.0" saptuneStatus={saptuneStatus} />
);

expect(
screen.getByRole('button', {
name: 'View Details',
})
).toBeEnabled();
});

it('should disable saptune details button', () => {
const saptuneStatus = saptuneStatusFactory.build({
package_version: '3.0.0',
});

renderWithRouter(
<HostDetails agentVersion="2.0.0" saptuneStatus={saptuneStatus} />
);

expect(
screen.getByRole('button', {
name: 'View Details',
})
).toBeDisabled();
});
});
});
2 changes: 2 additions & 0 deletions assets/js/components/HostDetails/HostDetailsPage.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -63,9 +63,11 @@ function HostDetailsPage() {
heartbeat={host.heartbeat}
hostID={host.id}
hostname={host.hostname}
ipAddresses={host.ip_addresses}
provider={host.provider}
providerData={host.provider_data}
sapInstances={sapInstances}
saptuneStatus={{}}
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Temporary empty

savingChecks={saving}
selectedChecks={hostSelectedChecks}
slesSubscriptions={host.sles_subscriptions}
Expand Down
28 changes: 28 additions & 0 deletions assets/js/components/SaptuneDetails/SaptuneTuningState.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import React from 'react';

import HealthIcon from '@components/Health/HealthIcon';

function SaptuneTuningState({ state }) {
switch (state) {
case 'compliant':
return 'Compliant';
arbulu89 marked this conversation as resolved.
Show resolved Hide resolved
case 'not compliant':
return (
<div className="flex">
<HealthIcon health="critical" />
<span className="ml-1">Not compliant</span>
</div>
);
case 'no tuning':
return (
<div className="flex">
<HealthIcon health="warning" />
<span className="ml-1">No tuning</span>
</div>
);
default:
return '-';
arbulu89 marked this conversation as resolved.
Show resolved Hide resolved
}
}

export default SaptuneTuningState;
30 changes: 30 additions & 0 deletions assets/js/components/SaptuneDetails/SaptuneTuningState.test.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import React from 'react';
import { render, screen } from '@testing-library/react';
import '@testing-library/jest-dom';

import SaptuneTuningState from './SaptuneTuningState';

describe('SpatuneTuningState', () => {
it.each([
{ state: 'compliant', text: 'Compliant', iconClass: null },
{
state: 'not compliant',
text: 'Not compliant',
iconClass: 'fill-red-500',
},
{ state: 'no tuning', text: 'No tuning', iconClass: 'fill-yellow-500' },
{ state: null, text: '-', icon: null },
])(
'should render correctly the $state state',
({ state, text, iconClass }) => {
render(<SaptuneTuningState state={state} />);

expect(screen.getByText(text)).toBeTruthy();

if (iconClass) {
const icon = screen.getByTestId('eos-svg-component');
expect(icon).toHaveClass(iconClass);
}
}
);
});
30 changes: 30 additions & 0 deletions assets/js/components/SaptuneDetails/SaptuneVersion.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import React from 'react';

import { isVersionSupported, SUPPORTED_VERSION } from '@lib/saptune';

import Tooltip from '@components/Tooltip';
import HealthIcon from '@components/Health/HealthIcon';

function SaptuneVersion({ version }) {
if (!version) {
return 'Not installed';
arbulu89 marked this conversation as resolved.
Show resolved Hide resolved
}

if (isVersionSupported(version)) {
return version;
}

return (
<div className="flex">
<Tooltip
content={`Saptune version not supported. Minimum supported version is ${SUPPORTED_VERSION}`}
place="bottom"
>
<HealthIcon health="warning" />
</Tooltip>
<span className="ml-1">{version}</span>
</div>
);
}

export default SaptuneVersion;
25 changes: 25 additions & 0 deletions assets/js/components/SaptuneDetails/SaptuneVersion.test.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import React from 'react';
import { render, screen } from '@testing-library/react';
import '@testing-library/jest-dom';

import SaptuneVersion from './SaptuneVersion';

describe('SaptuneVersion', () => {
it.each([
{ version: null, text: 'Not installed', iconCss: null },
{ version: '3.0.0', text: '3.0.0', iconCss: 'fill-yellow-500' },
{ version: '3.1.0', text: '3.1.0', iconCss: null },
])(
'should render correctly the $version version',
({ version, text, iconClass }) => {
render(<SaptuneVersion version={version} />);

expect(screen.getByText(text)).toBeTruthy();

if (iconClass) {
const icon = screen.getByTestId('eos-svg-component');
expect(icon).toHaveClass(iconClass);
}
}
);
});
4 changes: 4 additions & 0 deletions assets/js/components/SaptuneDetails/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import SaptuneTuningState from './SaptuneTuningState';
import SaptuneVersion from './SaptuneVersion';

export { SaptuneTuningState, SaptuneVersion };
Loading