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

Load selectable checks for a host #1600

Merged
merged 10 commits into from
Jul 11, 2023
6 changes: 3 additions & 3 deletions assets/js/components/ChecksSelection/ChecksSelection.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ function ChecksSelection({
useEffect(() => {
onUpdateCatalog();
onClear();
}, [onUpdateCatalog, onClear]);
}, []);

const onCheckSelectionGroupChange = (checks, groupSelected) => {
const groupChecks = checks.map((check) => check.id);
Expand All @@ -83,7 +83,7 @@ function ChecksSelection({
<div className={classNames('bg-white rounded p-3', className)}>
<CatalogContainer
onRefresh={onUpdateCatalog}
isCatalogEmpty={catalog.size === 0}
isCatalogEmpty={catalog.length === 0}
catalogError={catalogError}
loading={loading}
>
Expand Down Expand Up @@ -128,7 +128,7 @@ function ChecksSelection({
<EOS_LOADING_ANIMATED color="green" size={25} />
</span>
) : (
'Select Checks for Execution'
'Save Check Selection'
)}
</button>
{error && (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,13 @@ export const Default = {
},
};

export const Empty = {
args: {
...Default.args,
catalog: [],
},
};

export const Loading = {
args: {
...Default.args,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@ describe('ChecksSelection component', () => {
const switches = screen.getAllByRole('switch');

await user.click(switches[0]);
await user.click(screen.getByText('Select Checks for Execution'));
await user.click(screen.getByText('Save Check Selection'));

expect(onSave).toBeCalledWith([checkID1, checkID2], targetID);
expect(onUpdateCatalog).toBeCalled();
Expand Down
2 changes: 1 addition & 1 deletion assets/js/components/ClusterDetails/ChecksSelection.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ function ChecksSelection({ clusterId, cluster }) {
<div className="bg-white rounded p-3">
<CatalogContainer
onRefresh={() => dispatch(updateCatalog(catalogEnv))}
isCatalogEmpty={catalogData.size === 0}
isCatalogEmpty={catalogData.length === 0}
catalogError={catalogError}
loading={loading}
>
Expand Down
45 changes: 45 additions & 0 deletions assets/js/components/HostDetails/HostChecksSelection.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import React from 'react';
import PageHeader from '@components/PageHeader';
import BackButton from '@components/BackButton';
import { HostInfoBox } from '@components/HostDetails';

import ChecksSelection from '@components/ChecksSelection/ChecksSelection';

function HostChecksSelection({
host,
nelsonkopliku marked this conversation as resolved.
Show resolved Hide resolved
catalog,
catalogError,
catalogLoading,
onUpdateCatalog,
}) {
const { hostID } = host;

return (
<div className="w-full px-2 sm:px-0">
<BackButton url={`/hosts/${hostID}`}>Back to Host Details</BackButton>
<PageHeader>
Check Settings for <span className="font-bold">{host.hostname}</span>
</PageHeader>
<HostInfoBox provider={host.provider} agentVersion={host.agent_version} />
<ChecksSelection
targetID={hostID}
catalog={catalog}
catalogError={catalogError}
loading={catalogLoading}
selected={host.selected_checks}
onSave={(_selectedChecks, _hostID) => {
// TODO: dispatch check selection for a host
}}
onUpdateCatalog={() => onUpdateCatalog()}
onClear={() => {
// TODO
}}
saving={false}
error={null}
success={false}
/>
</div>
);
}

export default HostChecksSelection;
80 changes: 80 additions & 0 deletions assets/js/components/HostDetails/HostChecksSelection.stories.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
import React from 'react';
import { faker } from '@faker-js/faker';
import { MemoryRouter } from 'react-router-dom';

import { catalogCheckFactory, hostFactory } from '@lib/test-utils/factories';
import HostChecksSelection from './HostChecksSelection';

const catalog = [
...catalogCheckFactory.buildList(3, { group: faker.animal.cat() }),
...catalogCheckFactory.buildList(6, { group: faker.animal.dog() }),
...catalogCheckFactory.buildList(2, { group: faker.lorem.word() }),
];

const selectedChecks = [
catalog[0].id,
catalog[1].id,
catalog[2].id,
catalog[5].id,
catalog[6].id,
];

const host = hostFactory.build({ provider: 'azure' });

export default {
title: 'HostChecksSelection',
component: HostChecksSelection,
decorators: [
(Story) => (
<MemoryRouter>
<Story />
</MemoryRouter>
),
],
argTypes: {
host: {
control: 'object',
description: 'The host for which to select checks',
table: {
type: { summary: 'object' },
},
},
catalog: {
control: 'object',
description: 'Catalog data',
table: {
type: { summary: 'object' },
},
},
catalogError: {
control: 'text',
description: 'Error occurred while loading che relevant checks catalog',
nelsonkopliku marked this conversation as resolved.
Show resolved Hide resolved
table: {
type: { summary: 'string' },
defaultValue: { summary: null },
},
},
catalogLoading: {
control: { type: 'boolean' },
description: 'Whether the catalog is loading',
table: {
type: { summary: 'string' },
defaultValue: { summary: false },
},
},
onUpdateCatalog: {
action: 'Update catalog',
description: 'Called on mount to load the catalog for the host.',
},
},
};

export const Default = {
args: {
host: { ...host, selected_checks: selectedChecks },
catalog,
catalogError: null,
catalogLoading: false,
onUpdateCatalog: () => {},
},
};
54 changes: 54 additions & 0 deletions assets/js/components/HostDetails/HostChecksSelection.test.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import React from 'react';

import { screen } from '@testing-library/react';
import '@testing-library/jest-dom';

import { faker } from '@faker-js/faker';
import { catalogCheckFactory, hostFactory } from '@lib/test-utils/factories';

import HostChecksSelection from './HostChecksSelection';
import { renderWithRouter } from '../../lib/test-utils';

describe('HostChecksSelection component', () => {
it('should render host check selection', async () => {
const group0 = faker.animal.cat();
const group1 = faker.animal.dog();
const group2 = faker.lorem.word();
const catalog = [
...catalogCheckFactory.buildList(2, { group: group0 }),
...catalogCheckFactory.buildList(2, { group: group1 }),
...catalogCheckFactory.buildList(2, { group: group2 }),
];

const onUpdateCatalog = jest.fn();

const host = hostFactory.build({ provider: 'azure' });

const { agent_version: agentVersion } = host;

renderWithRouter(
<HostChecksSelection
host={host}
catalog={catalog}
catalogError={null}
catalogLoading={false}
onUpdateCatalog={onUpdateCatalog}
/>
);

expect(screen.getByText('Provider')).toBeVisible();
expect(screen.getByText('Azure')).toBeVisible();
expect(screen.getByText('Agent version')).toBeVisible();
expect(screen.getByText(agentVersion)).toBeVisible();
expect(screen.getByText(group0)).toBeVisible();
expect(screen.getByText(group1)).toBeVisible();
expect(screen.getByText(group2)).toBeVisible();
expect(
screen.getByRole('button', { name: 'Back to Host Details' })
).toBeVisible();
expect(
screen.getByRole('button', { name: 'Save Check Selection' })
).toBeVisible();
expect(onUpdateCatalog).toHaveBeenCalled();
});
});
28 changes: 28 additions & 0 deletions assets/js/components/HostDetails/HostInfoBox.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import React from 'react';

import ListView from '@components/ListView';
import ProviderLabel from '@components/ProviderLabel';

function HostInfoBox({ provider, agentVersion }) {
return (
<div className="my-4 bg-white shadow rounded-lg px-8 py-4">
<ListView
orientation="vertical"
data={[
{
title: 'Provider',
content: provider,
render: (content) => <ProviderLabel provider={content} />,
},
{ title: 'Agent version', content: agentVersion },
{
title: '',
nelsonkopliku marked this conversation as resolved.
Show resolved Hide resolved
content: '',
},
]}
/>
</div>
);
}

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

describe('Host Info Box', () => {
const scenarios = [
{
agentVersion: '1.1.0+git.dev17.1660137228.fe5ba8a',
provider: 'aws',
providerText: 'AWS',
},
{
agentVersion: '1.2.0+git.dev17.1660137228.fe5ba8a',
provider: 'aws',
providerText: 'AWS',
},
{
agentVersion: '2.0.0+git.dev17.1660137228.fe5ba8a',
provider: 'azure',
providerText: 'Azure',
},
{
agentVersion: '1.1.0',
provider: 'gcp',
providerText: 'GCP',
},
{
agentVersion: '1.2.0',
provider: 'kvm',
providerText: 'KVM',
},
{
agentVersion: '2.0.0',
provider: 'vmware',
providerText: 'VMware',
},
{
agentVersion: '2.1.0',
provider: 'nutanix',
providerText: 'Nutanix',
},
];

it.each(scenarios)(
'should display host info box for $providerText',
({ agentVersion, provider, providerText }) => {
render(<HostInfoBox provider={provider} agentVersion={agentVersion} />);
expect(screen.getByText(providerText)).toBeTruthy();
expect(screen.getByText(agentVersion)).toBeTruthy();
}
);
});
46 changes: 46 additions & 0 deletions assets/js/components/HostDetails/HostSettingsPage.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import React from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { useParams } from 'react-router-dom';

import LoadingBox from '@components/LoadingBox';

import { updateCatalog } from '@state/actions/catalog';
import { getCatalog } from '@state/selectors/catalog';
import { getHost } from '@state/selectors';
import HostChecksSelection from './HostChecksSelection';

function HostSettingsPage() {
const dispatch = useDispatch();

const { hostID } = useParams();
const host = useSelector(getHost(hostID));

const {
data: catalog,
error: catalogError,
loading: catalogLoading,
} = useSelector(getCatalog());

if (!host) {
return <LoadingBox text="Loading..." />;
}

return (
<HostChecksSelection
host={host}
catalog={catalog}
catalogError={catalogError}
catalogLoading={catalogLoading}
onUpdateCatalog={() =>
dispatch(
updateCatalog({
provider: host.provider,
target_type: 'host',
})
)
}
/>
);
}

export default HostSettingsPage;
Loading
Loading