Skip to content

Commit

Permalink
[Search] Delete flow inference endpoint UI (#193642)
Browse files Browse the repository at this point in the history
## Summary

Delete flow for Inference management UI
![Screenshot 2024-09-18 at 11 51
25 PM](https://github.com/user-attachments/assets/4ad46694-36fb-4af1-822c-2ee249edbd1b)

![Screenshot 2024-10-12 at 12 48
20 PM](https://github.com/user-attachments/assets/ecea0d26-36a0-4587-98de-ed4e9e696f93)

![Screenshot 2024-10-12 at 1 13
49 PM](https://github.com/user-attachments/assets/7d1014b2-dbf9-4af7-aa13-f7c43f3e8888)


![Screenshot 2024-10-12 at 1 28
18 PM](https://github.com/user-attachments/assets/23da99dc-5cfe-415d-80a4-932d9a4b9441)


### Checklist

Delete any items that are not applicable to this PR.

- [X] Any text added follows [EUI's writing
guidelines](https://elastic.github.io/eui/#/guidelines/writing), uses
sentence case text and includes [i18n
support](https://github.com/elastic/kibana/blob/main/packages/kbn-i18n/README.md)
- [X]
[Documentation](https://www.elastic.co/guide/en/kibana/master/development-documentation.html)
was added for features that require explanation or tutorials
- [X] [Unit or functional
tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)
were updated or added to match the most common scenarios
- [ ] [Flaky Test
Runner](https://ci-stats.kibana.dev/trigger_flaky_test_runner/1) was
used on any tests changed
- [ ] Any UI touched in this PR is usable by keyboard only (learn more
about [keyboard accessibility](https://webaim.org/techniques/keyboard/))
- [X] Any UI touched in this PR does not create any new axe failures
(run axe in browser:
[FF](https://addons.mozilla.org/en-US/firefox/addon/axe-devtools/),
[Chrome](https://chrome.google.com/webstore/detail/axe-web-accessibility-tes/lhdoppojpmngadmnindnejefpokejbdd?hl=en-US))
- [ ] This renders correctly on smaller devices using a responsive
layout. (You can test this [in your
browser](https://www.browserstack.com/guide/responsive-testing-on-local-server))
- [X] This was checked for [cross-browser
compatibility](https://www.elastic.co/support/matrix#matrix_browsers)

---------

Co-authored-by: kibanamachine <[email protected]>
  • Loading branch information
Samiul-TheSoccerFan and kibanamachine authored Oct 14, 2024
1 parent 3d466a7 commit 25d15c9
Show file tree
Hide file tree
Showing 20 changed files with 846 additions and 19 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
/*
* 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 { ListUsageResults } from './list_usage_results';
import { render, screen, fireEvent } from '@testing-library/react';

describe('ListUsageResults', () => {
const items = [
{
label: 'index-1',
type: 'Index',
},
{
label: 'pipeline-1',
type: 'Pipeline',
},
];
beforeEach(() => {
render(<ListUsageResults list={items} />);
});
it('renders', () => {
expect(screen.getByRole('searchbox')).toBeInTheDocument();
expect(screen.getAllByTestId('usageItem')).toHaveLength(2);

expect(screen.getByText('index-1')).toBeInTheDocument();
expect(screen.getByText('Index')).toBeInTheDocument();
expect(screen.getByText('pipeline-1')).toBeInTheDocument();
expect(screen.getByText('Pipeline')).toBeInTheDocument();
});

it('filters list based on search term', () => {
const searchBox = screen.getByRole('searchbox');
fireEvent.change(searchBox, { target: { value: 'index' } });

expect(screen.getAllByTestId('usageItem')).toHaveLength(1);
expect(screen.getByText('index-1')).toBeInTheDocument();
expect(screen.queryByText('pipeline-1')).not.toBeInTheDocument();
});

it('empty list', () => {
const searchBox = screen.getByRole('searchbox');
fireEvent.change(searchBox, { target: { value: 'coke' } });

expect(screen.queryAllByTestId('usageItem')).toHaveLength(0);
expect(screen.queryByText('index-1')).not.toBeInTheDocument();
expect(screen.queryByText('pipeline-1')).not.toBeInTheDocument();
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
/*
* 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, { useState } from 'react';
import { EuiFieldSearch, EuiFlexGroup, EuiFlexItem } from '@elastic/eui';

import { InferenceUsageInfo } from '../../../../types';
import * as i18n from '../delete/confirm_delete_endpoint/translations';
import { UsageItem } from './usage_item';

interface ListUsageResultsProps {
list: InferenceUsageInfo[];
}

export const ListUsageResults: React.FC<ListUsageResultsProps> = ({ list }) => {
const [term, setTerm] = useState<string>('');

return (
<EuiFlexGroup gutterSize="m" direction="column">
<EuiFlexItem>
<EuiFieldSearch
placeholder={i18n.SEARCH_LABEL}
value={term}
onChange={(e) => setTerm(e.target.value)}
isClearable={true}
aria-label={i18n.SEARCH_ARIA_LABEL}
fullWidth={true}
data-test-subj="usageFieldSearch"
/>
</EuiFlexItem>
<EuiFlexItem>
{list
.filter((item) => item.label.toLowerCase().includes(term.toLowerCase()))
.map((item, id) => (
<UsageItem usageItem={item} key={id} />
))}
</EuiFlexItem>
</EuiFlexGroup>
);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
/*
* 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 { EuiFlexGroup, EuiFlexItem, EuiIcon, EuiText } from '@elastic/eui';
import React from 'react';

interface RenderMessageWithIconProps {
icon: string;
color: string;
label: string;
labelColor?: string;
}
export const RenderMessageWithIcon: React.FC<RenderMessageWithIconProps> = ({
icon,
color,
label,
labelColor,
}) => (
<EuiFlexGroup alignItems={'center'} gutterSize={'s'}>
<EuiFlexItem grow={false}>
<EuiIcon size="s" type={icon} color={color} />
</EuiFlexItem>
<EuiFlexItem grow={false}>
<EuiText size={'xs'} textAlign={'left'} color={labelColor ?? 'default'}>
{label}
</EuiText>
</EuiFlexItem>
</EuiFlexGroup>
);
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
/*
* 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 { render, fireEvent, screen } from '@testing-library/react';
import React from 'react';

import { ScanUsageResults } from './scan_usage_results';
import { useKibana } from '../../../../../../hooks/use_kibana';

jest.mock('../../../../../../hooks/use_kibana');
const mockUseKibana = useKibana as jest.Mock;
const mockNavigateToApp = jest.fn();
const mockOnCheckboxChange = jest.fn();

describe('ScanUsageResults', () => {
const items = [
{
label: 'index-1',
type: 'Index',
},
{
label: 'pipeline-1',
type: 'Pipeline',
},
];
beforeEach(() => {
mockUseKibana.mockReturnValue({
services: {
application: {
navigateToApp: mockNavigateToApp,
},
},
});

render(
<ScanUsageResults
list={items}
ignoreWarningCheckbox={false}
onCheckboxChange={mockOnCheckboxChange}
/>
);
});

it('renders', () => {
expect(screen.getByText('Potential Failures')).toBeInTheDocument();
expect(screen.getByText('Found 2 usages')).toBeInTheDocument();
expect(screen.getByText('Open Index Management')).toBeInTheDocument();
expect(screen.getAllByTestId('usageItem')).toHaveLength(2);

const checkbox = screen.getByTestId('warningCheckbox');
expect(checkbox).toBeInTheDocument();
expect(checkbox).toHaveProperty('checked', false);
});

it('opens index management in a new tab', () => {
fireEvent.click(screen.getByTestId('inferenceManagementOpenIndexManagement'));
expect(mockNavigateToApp).toHaveBeenCalledWith('enterprise_search', {
openInNewTab: true,
path: 'content/search_indices',
});
});

it('onCheckboxChange gets called with correct params', () => {
fireEvent.click(screen.getByTestId('warningCheckbox'));
expect(mockOnCheckboxChange).toHaveBeenCalledWith(true);
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
/*
* 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 {
EuiCheckbox,
EuiFlexGroup,
EuiFlexItem,
EuiHorizontalRule,
EuiPanel,
EuiText,
EuiButtonEmpty,
} from '@elastic/eui';
import React from 'react';
import { euiThemeVars } from '@kbn/ui-theme';
import { css } from '@emotion/react';
import { InferenceUsageInfo } from '../../../../types';
import { useKibana } from '../../../../../../hooks/use_kibana';
import { RenderMessageWithIcon } from './render_message_with_icon';

import * as i18n from '../delete/confirm_delete_endpoint/translations';
import { ListUsageResults } from './list_usage_results';

interface ScanUsageResultsProps {
list: InferenceUsageInfo[];
ignoreWarningCheckbox: boolean;
onCheckboxChange: (state: boolean) => void;
}

export const ScanUsageResults: React.FC<ScanUsageResultsProps> = ({
list,
ignoreWarningCheckbox,
onCheckboxChange,
}) => {
const {
services: { application },
} = useKibana();
const handleNavigateToIndex = () => {
application?.navigateToApp('enterprise_search', {
path: 'content/search_indices',
openInNewTab: true,
});
};

return (
<EuiFlexGroup gutterSize="m" direction="column">
<EuiFlexItem>
<RenderMessageWithIcon
icon="warning"
color="danger"
label={i18n.POTENTIAL_FAILURE_LABEL}
labelColor="danger"
/>
</EuiFlexItem>
<EuiFlexItem>
<EuiPanel hasBorder={true}>
<EuiFlexGroup gutterSize="m" direction="column">
<EuiFlexItem>
<EuiFlexGroup justifyContent="spaceBetween" gutterSize="s">
<EuiFlexItem grow={false}>
<EuiText
size="xs"
css={css`
font-weight: ${euiThemeVars.euiCodeFontWeightBold};
`}
>
<p>{i18n.COUNT_USAGE_LABEL(list.length)}</p>
</EuiText>
</EuiFlexItem>
<EuiFlexItem grow={false}>
<EuiButtonEmpty
onClick={handleNavigateToIndex}
iconType="popout"
iconSide="right"
iconSize="s"
flush="both"
color="text"
aria-label={i18n.OPEN_INDEX_MANAGEMENT}
data-test-subj="inferenceManagementOpenIndexManagement"
>
<EuiText size="xs">{i18n.OPEN_INDEX_MANAGEMENT}</EuiText>
</EuiButtonEmpty>
</EuiFlexItem>
</EuiFlexGroup>
</EuiFlexItem>
<EuiFlexItem>
<ListUsageResults list={list} />
</EuiFlexItem>
</EuiFlexGroup>
</EuiPanel>
</EuiFlexItem>
<EuiFlexItem>
<EuiHorizontalRule margin="s" />
</EuiFlexItem>
<EuiFlexItem>
<EuiPanel hasBorder={true}>
<EuiCheckbox
data-test-subj="warningCheckbox"
id={'ignoreWarningCheckbox'}
label={i18n.IGNORE_POTENTIAL_ERRORS_LABEL}
checked={ignoreWarningCheckbox}
onChange={(e) => onCheckboxChange(e.target.checked)}
/>
</EuiPanel>
</EuiFlexItem>
</EuiFlexGroup>
);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
/*
* 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 { render, fireEvent, screen } from '@testing-library/react';
import React from 'react';

import { UsageItem } from './usage_item';
import { InferenceUsageInfo } from '../../../../types';
import { useKibana } from '../../../../../../hooks/use_kibana';

jest.mock('../../../../../../hooks/use_kibana');
const mockUseKibana = useKibana as jest.Mock;
const mockNavigateToApp = jest.fn();

describe('UsageItem', () => {
beforeEach(() => {
mockUseKibana.mockReturnValue({
services: {
application: {
navigateToApp: mockNavigateToApp,
},
},
});
});

describe('index', () => {
const item: InferenceUsageInfo = {
label: 'index-1',
type: 'Index',
};

beforeEach(() => {
render(<UsageItem usageItem={item} />);
});

it('renders', () => {
expect(screen.getByText('index-1')).toBeInTheDocument();
expect(screen.getByText('Index')).toBeInTheDocument();
});

it('opens index in a new tab', () => {
fireEvent.click(screen.getByRole('button'));
expect(mockNavigateToApp).toHaveBeenCalledWith('enterprise_search', {
openInNewTab: true,
path: 'content/search_indices/index-1',
});
});
});

describe('pipeline', () => {
const item: InferenceUsageInfo = {
label: 'pipeline-1',
type: 'Pipeline',
};

beforeEach(() => {
render(<UsageItem usageItem={item} />);
});
it('renders', () => {
expect(screen.getByText('pipeline-1')).toBeInTheDocument();
expect(screen.getByText('Pipeline')).toBeInTheDocument();
});

it('opens pipeline in a new tab', () => {
fireEvent.click(screen.getByRole('button'));
expect(mockNavigateToApp).toHaveBeenCalledWith('management', {
path: 'ingest/ingest_pipelines?pipeline=pipeline-1',
openInNewTab: true,
});
});
});
});
Loading

0 comments on commit 25d15c9

Please sign in to comment.