mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 17:59:23 -04:00
* Made eui search field not a controlled component Added validateRegExpString util * Update error message display. Use EuiCallOut and i18n to replicate other search filter behaviour, e.g. index management. * Remove unused variable * Update Jest snapshot * Updated layout for callout The previous callout layout looked off-center next to the controls in the table. * Update copy and remove intl Update "Filter Invalid:" to sentence case Remove inject intl wrapper from CheckupControls component Remove unnecessary grow={true} * Updated Jest component snapshot Co-authored-by: Elastic Machine <elasticmachine@users.noreply.github.com> Co-authored-by: Elastic Machine <elasticmachine@users.noreply.github.com>
This commit is contained in:
parent
72df0bf006
commit
87f366de2d
5 changed files with 121 additions and 45 deletions
|
@ -57,7 +57,7 @@ exports[`CheckupTab render with deprecations 1`] = `
|
|||
<EuiSpacer />
|
||||
<EuiPageContent>
|
||||
<EuiPageContentBody>
|
||||
<InjectIntl(CheckupControlsUI)
|
||||
<CheckupControls
|
||||
allDeprecations={
|
||||
Array [
|
||||
Object {
|
||||
|
@ -170,7 +170,6 @@ exports[`CheckupTab render with deprecations 1`] = `
|
|||
onFilterChange={[Function]}
|
||||
onGroupByChange={[Function]}
|
||||
onSearchChange={[Function]}
|
||||
search=""
|
||||
/>
|
||||
<EuiSpacer />
|
||||
<GroupedDeprecations
|
||||
|
|
|
@ -68,7 +68,7 @@ export class CheckupTab extends UpgradeAssistantTabComponent<CheckupTabProps, Ch
|
|||
setSelectedTabIndex,
|
||||
showBackupWarning = false,
|
||||
} = this.props;
|
||||
const { currentFilter, search, currentGroupBy } = this.state;
|
||||
const { currentFilter, currentGroupBy } = this.state;
|
||||
|
||||
return (
|
||||
<Fragment>
|
||||
|
@ -143,7 +143,6 @@ export class CheckupTab extends UpgradeAssistantTabComponent<CheckupTabProps, Ch
|
|||
loadData={refreshCheckupData}
|
||||
currentFilter={currentFilter}
|
||||
onFilterChange={this.changeFilter}
|
||||
search={search}
|
||||
onSearchChange={this.changeSearch}
|
||||
availableGroupByOptions={this.availableGroupByOptions()}
|
||||
currentGroupBy={currentGroupBy}
|
||||
|
|
|
@ -3,73 +3,112 @@
|
|||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
import React, { FunctionComponent } from 'react';
|
||||
|
||||
import { EuiButton, EuiFieldSearch, EuiFlexGroup, EuiFlexItem } from '@elastic/eui';
|
||||
import { FormattedMessage, injectI18n } from '@kbn/i18n/react';
|
||||
import React, { FunctionComponent, useState } from 'react';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { EuiButton, EuiFieldSearch, EuiFlexGroup, EuiFlexItem, EuiCallOut } from '@elastic/eui';
|
||||
import { FormattedMessage } from '@kbn/i18n/react';
|
||||
|
||||
import { DeprecationInfo } from 'src/legacy/core_plugins/elasticsearch';
|
||||
import { GroupByOption, LevelFilterOption, LoadingState } from '../../types';
|
||||
import { FilterBar } from './filter_bar';
|
||||
import { GroupByBar } from './group_by_bar';
|
||||
|
||||
interface CheckupControlsProps extends ReactIntl.InjectedIntlProps {
|
||||
import { validateRegExpString } from '../../../utils';
|
||||
|
||||
interface CheckupControlsProps {
|
||||
allDeprecations?: DeprecationInfo[];
|
||||
loadingState: LoadingState;
|
||||
loadData: () => void;
|
||||
currentFilter: LevelFilterOption;
|
||||
onFilterChange: (filter: LevelFilterOption) => void;
|
||||
search: string;
|
||||
onSearchChange: (filter: string) => void;
|
||||
availableGroupByOptions: GroupByOption[];
|
||||
currentGroupBy: GroupByOption;
|
||||
onGroupByChange: (groupBy: GroupByOption) => void;
|
||||
}
|
||||
|
||||
export const CheckupControlsUI: FunctionComponent<CheckupControlsProps> = ({
|
||||
export const CheckupControls: FunctionComponent<CheckupControlsProps> = ({
|
||||
allDeprecations,
|
||||
loadingState,
|
||||
loadData,
|
||||
currentFilter,
|
||||
onFilterChange,
|
||||
search,
|
||||
onSearchChange,
|
||||
availableGroupByOptions,
|
||||
currentGroupBy,
|
||||
onGroupByChange,
|
||||
intl,
|
||||
}) => (
|
||||
<EuiFlexGroup alignItems="center" wrap={true} responsive={false}>
|
||||
<EuiFlexItem grow={true}>
|
||||
<EuiFieldSearch
|
||||
aria-label="Filter"
|
||||
placeholder={intl.formatMessage({
|
||||
id: 'xpack.upgradeAssistant.checkupTab.controls.searchBarPlaceholder',
|
||||
defaultMessage: 'Filter',
|
||||
})}
|
||||
value={search}
|
||||
onChange={e => onSearchChange(e.target.value)}
|
||||
/>
|
||||
</EuiFlexItem>
|
||||
}) => {
|
||||
const [searchTermError, setSearchTermError] = useState<null | string>(null);
|
||||
const filterInvalid = Boolean(searchTermError);
|
||||
return (
|
||||
<EuiFlexGroup direction="column" responsive={false}>
|
||||
<EuiFlexItem grow={true}>
|
||||
<EuiFlexGroup alignItems="center" wrap={true} responsive={false}>
|
||||
<EuiFlexItem>
|
||||
<EuiFieldSearch
|
||||
isInvalid={filterInvalid}
|
||||
aria-label={i18n.translate(
|
||||
'xpack.upgradeAssistant.checkupTab.controls.searchBarPlaceholderAriaLabel',
|
||||
{ defaultMessage: 'Filter' }
|
||||
)}
|
||||
placeholder={i18n.translate(
|
||||
'xpack.upgradeAssistant.checkupTab.controls.searchBarPlaceholder',
|
||||
{
|
||||
defaultMessage: 'Filter',
|
||||
}
|
||||
)}
|
||||
onChange={e => {
|
||||
const string = e.target.value;
|
||||
const errorMessage = validateRegExpString(string);
|
||||
if (errorMessage) {
|
||||
// Emit an empty search term to listeners if search term is invalid.
|
||||
onSearchChange('');
|
||||
setSearchTermError(errorMessage);
|
||||
} else {
|
||||
onSearchChange(e.target.value);
|
||||
if (searchTermError) {
|
||||
setSearchTermError(null);
|
||||
}
|
||||
}
|
||||
}}
|
||||
/>
|
||||
</EuiFlexItem>
|
||||
|
||||
{/* These two components provide their own EuiFlexItem wrappers */}
|
||||
<FilterBar {...{ allDeprecations, currentFilter, onFilterChange }} />
|
||||
<GroupByBar {...{ availableGroupByOptions, currentGroupBy, onGroupByChange }} />
|
||||
{/* These two components provide their own EuiFlexItem wrappers */}
|
||||
<FilterBar {...{ allDeprecations, currentFilter, onFilterChange }} />
|
||||
<GroupByBar {...{ availableGroupByOptions, currentGroupBy, onGroupByChange }} />
|
||||
|
||||
<EuiFlexItem grow={false}>
|
||||
<EuiButton
|
||||
fill
|
||||
onClick={loadData}
|
||||
iconType="refresh"
|
||||
isLoading={loadingState === LoadingState.Loading}
|
||||
>
|
||||
<FormattedMessage
|
||||
id="xpack.upgradeAssistant.checkupTab.controls.refreshButtonLabel"
|
||||
defaultMessage="Refresh"
|
||||
/>
|
||||
</EuiButton>
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
);
|
||||
|
||||
export const CheckupControls = injectI18n(CheckupControlsUI);
|
||||
<EuiFlexItem grow={false}>
|
||||
<EuiButton
|
||||
fill
|
||||
onClick={loadData}
|
||||
iconType="refresh"
|
||||
isLoading={loadingState === LoadingState.Loading}
|
||||
>
|
||||
<FormattedMessage
|
||||
id="xpack.upgradeAssistant.checkupTab.controls.refreshButtonLabel"
|
||||
defaultMessage="Refresh"
|
||||
/>
|
||||
</EuiButton>
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
</EuiFlexItem>
|
||||
{filterInvalid && (
|
||||
<EuiFlexItem grow={false}>
|
||||
<EuiCallOut
|
||||
color="danger"
|
||||
title={i18n.translate(
|
||||
'xpack.upgradeAssistant.checkupTab.controls.filterErrorMessageLabel',
|
||||
{
|
||||
defaultMessage: 'Filter invalid: {searchTermError}',
|
||||
values: { searchTermError },
|
||||
}
|
||||
)}
|
||||
iconType="faceSad"
|
||||
/>
|
||||
</EuiFlexItem>
|
||||
)}
|
||||
</EuiFlexGroup>
|
||||
);
|
||||
};
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
import { validateRegExpString } from './utils';
|
||||
|
||||
describe('validRegExpString', () => {
|
||||
it('correctly returns false for invalid strings', () => {
|
||||
expect(validateRegExpString('?asd')).toContain(`Invalid regular expression`);
|
||||
expect(validateRegExpString('*asd')).toContain(`Invalid regular expression`);
|
||||
expect(validateRegExpString('(')).toContain(`Invalid regular expression`);
|
||||
});
|
||||
|
||||
it('correctly returns true for valid strings', () => {
|
||||
expect(validateRegExpString('asd')).toBe('');
|
||||
expect(validateRegExpString('.*asd')).toBe('');
|
||||
expect(validateRegExpString('')).toBe('');
|
||||
});
|
||||
});
|
|
@ -0,0 +1,19 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
import { pipe } from 'fp-ts/lib/pipeable';
|
||||
import { tryCatch, fold } from 'fp-ts/lib/Either';
|
||||
|
||||
export const validateRegExpString = (s: string) =>
|
||||
pipe(
|
||||
tryCatch(
|
||||
() => new RegExp(s),
|
||||
e => (e as Error).message
|
||||
),
|
||||
fold(
|
||||
(errorMessage: string) => errorMessage,
|
||||
() => ''
|
||||
)
|
||||
);
|
Loading…
Add table
Add a link
Reference in a new issue