Skip to content

Commit

Permalink
[App Search] Migrate Crawler Status Indicator, Crawler Status Banner,…
Browse files Browse the repository at this point in the history
… and Crawl Request polling (elastic#107603) (elastic#107810)

Co-authored-by: Byron Hulcher <[email protected]>
  • Loading branch information
kibanamachine and byronhulcher authored Aug 5, 2021
1 parent c33dc8d commit 3520109
Show file tree
Hide file tree
Showing 14 changed files with 1,045 additions and 64 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/

import { setMockValues } from '../../../../__mocks__/kea_logic';

import React from 'react';

import { shallow } from 'enzyme';

import { EuiCallOut } from '@elastic/eui';

import { CrawlerStatus } from '../types';

import { CrawlerStatusBanner } from './crawler_status_banner';

describe('CrawlerStatusBanner', () => {
beforeEach(() => {
jest.clearAllMocks();
});

[(CrawlerStatus.Starting, CrawlerStatus.Running, CrawlerStatus.Canceling)].forEach((status) => {
describe(`when the status is ${status}`, () => {
it('renders a callout', () => {
setMockValues({
mostRecentCrawlRequestStatus: status,
});

const wrapper = shallow(<CrawlerStatusBanner />);

expect(wrapper.find(EuiCallOut)).toHaveLength(1);
});
});
});

[
CrawlerStatus.Success,
CrawlerStatus.Failed,
CrawlerStatus.Canceled,
CrawlerStatus.Pending,
CrawlerStatus.Suspended,
CrawlerStatus.Suspending,
].forEach((status) => {
describe(`when the status is ${status}`, () => {
it('does not render a banner/callout', () => {
setMockValues({
mostRecentCrawlRequestStatus: status,
});

const wrapper = shallow(<CrawlerStatusBanner />);

expect(wrapper.isEmptyRender()).toBe(true);
});
});
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/

import React from 'react';

import { useValues } from 'kea';

import { EuiCallOut } from '@elastic/eui';

import { i18n } from '@kbn/i18n';

import { CrawlerOverviewLogic } from '../crawler_overview_logic';
import { CrawlerStatus } from '../types';

export const CrawlerStatusBanner: React.FC = () => {
const { mostRecentCrawlRequestStatus } = useValues(CrawlerOverviewLogic);
if (
mostRecentCrawlRequestStatus === CrawlerStatus.Running ||
mostRecentCrawlRequestStatus === CrawlerStatus.Starting ||
mostRecentCrawlRequestStatus === CrawlerStatus.Canceling
) {
return (
<EuiCallOut
iconType="iInCircle"
title={i18n.translate(
'xpack.enterpriseSearch.appSearch.crawler.crawlerStatusBanner.changesCalloutTitle',
{
defaultMessage:
"Changes you make now won't take effect until the start of your next crawl.",
}
)}
/>
);
}
return null;
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,156 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/

import { setMockActions, setMockValues } from '../../../../../__mocks__/kea_logic';

import React from 'react';

import { shallow } from 'enzyme';

import { EuiButton } from '@elastic/eui';

import { CrawlerDomain, CrawlerStatus } from '../../types';

import { CrawlerStatusIndicator } from './crawler_status_indicator';
import { StopCrawlPopoverContextMenu } from './stop_crawl_popover_context_menu';

const MOCK_VALUES = {
domains: [{}, {}] as CrawlerDomain[],
mostRecentCrawlRequestStatus: CrawlerStatus.Success,
};

const MOCK_ACTIONS = {
startCrawl: jest.fn(),
stopCrawl: jest.fn(),
};

describe('CrawlerStatusIndicator', () => {
beforeEach(() => {
jest.clearAllMocks();
setMockActions(MOCK_ACTIONS);
});

describe('when status is not a valid status', () => {
it('is disabled', () => {
// this tests a codepath that should be impossible to reach, status should always be a CrawlerStatus
// but we use a switch statement and need to test the default case for this to recieve 100% coverage
setMockValues({
...MOCK_VALUES,
mostRecentCrawlRequestStatus: null,
});

const wrapper = shallow(<CrawlerStatusIndicator />);
expect(wrapper.is(EuiButton)).toEqual(true);
expect(wrapper.render().text()).toContain('Start a crawl');
expect(wrapper.prop('disabled')).toEqual(true);
});
});

describe('when there are no domains', () => {
it('is disabled', () => {
setMockValues({
...MOCK_VALUES,
domains: [],
});

const wrapper = shallow(<CrawlerStatusIndicator />);
expect(wrapper.is(EuiButton)).toEqual(true);
expect(wrapper.render().text()).toContain('Start a crawl');
expect(wrapper.prop('disabled')).toEqual(true);
});
});

describe('when the status is success', () => {
it('renders an CrawlerStatusIndicator with a start crawl button', () => {
setMockValues({
...MOCK_VALUES,
mostRecentCrawlRequestStatus: CrawlerStatus.Success,
});

const wrapper = shallow(<CrawlerStatusIndicator />);
expect(wrapper.is(EuiButton)).toEqual(true);
expect(wrapper.render().text()).toContain('Start a crawl');
expect(wrapper.prop('onClick')).toEqual(MOCK_ACTIONS.startCrawl);
});
});

[CrawlerStatus.Failed, CrawlerStatus.Canceled].forEach((status) => {
describe(`when the status is ready for retry: ${status}`, () => {
it('renders an CrawlerStatusIndicator with a retry crawl button', () => {
setMockValues({
...MOCK_VALUES,
mostRecentCrawlRequestStatus: status,
});

const wrapper = shallow(<CrawlerStatusIndicator />);
expect(wrapper.is(EuiButton)).toEqual(true);
expect(wrapper.render().text()).toContain('Retry crawl');
expect(wrapper.prop('onClick')).toEqual(MOCK_ACTIONS.startCrawl);
});
});
});

[CrawlerStatus.Pending, CrawlerStatus.Suspended].forEach((status) => {
describe(`when the status is ${status}`, () => {
it('renders an CrawlerStatusIndicator with a pending indicator', () => {
setMockValues({
...MOCK_VALUES,
mostRecentCrawlRequestStatus: status,
});

const wrapper = shallow(<CrawlerStatusIndicator />);
expect(wrapper.is(EuiButton)).toEqual(true);
expect(wrapper.render().text()).toContain('Pending...');
expect(wrapper.prop('disabled')).toEqual(true);
expect(wrapper.prop('isLoading')).toEqual(true);
});
});
});

describe('when the status is Starting', () => {
it('renders an appropriate CrawlerStatusIndicator', () => {
setMockValues({
...MOCK_VALUES,
mostRecentCrawlRequestStatus: CrawlerStatus.Starting,
});

const wrapper = shallow(<CrawlerStatusIndicator />);
expect(wrapper.is(EuiButton)).toEqual(true);
expect(wrapper.render().text()).toContain('Starting...');
expect(wrapper.prop('isLoading')).toEqual(true);
});
});

describe('when the status is Running', () => {
it('renders a stop crawl popover menu', () => {
setMockValues({
...MOCK_VALUES,
mostRecentCrawlRequestStatus: CrawlerStatus.Running,
});

const wrapper = shallow(<CrawlerStatusIndicator />);
expect(wrapper.is(StopCrawlPopoverContextMenu)).toEqual(true);
expect(wrapper.prop('stopCrawl')).toEqual(MOCK_ACTIONS.stopCrawl);
});
});

[CrawlerStatus.Canceling, CrawlerStatus.Suspending].forEach((status) => {
describe(`when the status is ${status}`, () => {
it('renders an CrawlerStatusIndicator with a stopping indicator', () => {
setMockValues({
...MOCK_VALUES,
mostRecentCrawlRequestStatus: status,
});

const wrapper = shallow(<CrawlerStatusIndicator />);
expect(wrapper.is(EuiButton)).toEqual(true);
expect(wrapper.render().text()).toContain('Stopping...');
expect(wrapper.prop('isLoading')).toEqual(true);
});
});
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/

import React from 'react';

import { useActions, useValues } from 'kea';

import { EuiButton } from '@elastic/eui';

import { i18n } from '@kbn/i18n';

import { CrawlerOverviewLogic } from '../../crawler_overview_logic';
import { CrawlerStatus } from '../../types';

import { StopCrawlPopoverContextMenu } from './stop_crawl_popover_context_menu';

export const CrawlerStatusIndicator: React.FC = () => {
const { domains, mostRecentCrawlRequestStatus } = useValues(CrawlerOverviewLogic);
const { startCrawl, stopCrawl } = useActions(CrawlerOverviewLogic);

const disabledButton = (
<EuiButton disabled>
{i18n.translate(
'xpack.enterpriseSearch.appSearch.crawler.crawlerStatusIndicator.startACrawlButtonLabel',
{
defaultMessage: 'Start a crawl',
}
)}
</EuiButton>
);

if (domains.length === 0) {
return disabledButton;
}

switch (mostRecentCrawlRequestStatus) {
case CrawlerStatus.Success:
return (
<EuiButton fill onClick={startCrawl}>
{i18n.translate(
'xpack.enterpriseSearch.appSearch.crawler.crawlerStatusIndicator.startACrawlButtonLabel',
{
defaultMessage: 'Start a crawl',
}
)}
</EuiButton>
);
case CrawlerStatus.Failed:
case CrawlerStatus.Canceled:
return (
<EuiButton fill onClick={startCrawl}>
{i18n.translate(
'xpack.enterpriseSearch.appSearch.crawler.crawlerStatusIndicator.retryCrawlButtonLabel',
{
defaultMessage: 'Retry crawl',
}
)}
</EuiButton>
);
case CrawlerStatus.Pending:
case CrawlerStatus.Suspended:
return (
<EuiButton disabled isLoading>
{i18n.translate(
'xpack.enterpriseSearch.appSearch.crawler.crawlerStatusIndicator.pendingButtonLabel',
{
defaultMessage: 'Pending...',
}
)}
</EuiButton>
);
case CrawlerStatus.Starting:
return (
<EuiButton isLoading>
{i18n.translate(
'xpack.enterpriseSearch.appSearch.crawler.crawlerStatusIndicator.startingButtonLabel',
{
defaultMessage: 'Starting...',
}
)}
</EuiButton>
);
case CrawlerStatus.Running:
return <StopCrawlPopoverContextMenu stopCrawl={stopCrawl} />;
case CrawlerStatus.Canceling:
case CrawlerStatus.Suspending:
return (
<EuiButton isLoading fill>
{i18n.translate(
'xpack.enterpriseSearch.appSearch.crawler.crawlerStatusIndicator.stoppingButtonLabel',
{
defaultMessage: 'Stopping...',
}
)}
</EuiButton>
);
default:
// We should never get here, you would have to pass a CrawlerStatus option not covered
// in the switch cases above
return disabledButton;
}
};
Loading

0 comments on commit 3520109

Please sign in to comment.