[Management] Highlight query in results for index pattern creation wizard (#16529)

* Highlight matches in the table

* Address issue with showing an error when the user types `.` which is invalid, but there shouldn't be an error

* Use strong
This commit is contained in:
Chris Roberson 2018-02-08 13:47:28 -05:00 committed by GitHub
parent 8664b55ac2
commit 32f50b0a27
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
10 changed files with 171 additions and 59 deletions

View file

@ -59,6 +59,7 @@ exports[`StepIndexPattern should disable the next step if the index pattern exis
},
]
}
query="k*"
/>
</EuiPanel>
`;
@ -147,6 +148,7 @@ exports[`StepIndexPattern should properly fetch indices for the initial query 1`
},
]
}
query="k*"
/>
</EuiPanel>
`;
@ -159,11 +161,7 @@ exports[`StepIndexPattern should render normally 1`] = `
>
<Header
characterList="\\\\, /, ?, \\", <, >, |"
errors={
Array [
"Your input contains invalid characters or spaces. Please omit: \\\\, /, ?, \\", <, >, |",
]
}
errors={Array []}
goToNextStep={[Function]}
isInputInvalid={false}
isNextStepDisabled={true}
@ -212,6 +210,7 @@ exports[`StepIndexPattern should render normally 1`] = `
},
]
}
query=""
/>
</EuiPanel>
`;
@ -275,6 +274,7 @@ exports[`StepIndexPattern should render some indices 1`] = `
},
]
}
query="k*"
/>
</EuiPanel>
`;
@ -367,6 +367,7 @@ exports[`StepIndexPattern should show errors 1`] = `
},
]
}
query="?"
/>
</EuiPanel>
`;

View file

@ -200,6 +200,111 @@ exports[`IndicesList should change per page 1`] = `
</div>
`;
exports[`IndicesList should highlight the query in the matches 1`] = `
<div>
<EuiTable>
<EuiTableBody>
<EuiTableRow
key="0"
>
<EuiTableRowCell
align="left"
textOnly={true}
>
<span>
<strong>
ki
</strong>
bana
</span>
</EuiTableRowCell>
</EuiTableRow>
<EuiTableRow
key="1"
>
<EuiTableRowCell
align="left"
textOnly={true}
>
es
</EuiTableRowCell>
</EuiTableRow>
</EuiTableBody>
</EuiTable>
<EuiSpacer
size="m"
/>
<EuiFlexGroup
alignItems="center"
component="div"
gutterSize="l"
justifyContent="spaceBetween"
responsive={true}
wrap={false}
>
<EuiFlexItem
component="div"
grow={false}
>
<EuiPopover
anchorPosition="downCenter"
button={
<EuiButtonEmpty
color="text"
iconSide="right"
iconType="arrowDown"
onClick={[Function]}
size="s"
type="button"
>
Rows per page:
10
</EuiButtonEmpty>
}
closePopover={[Function]}
id="customizablePagination"
isOpen={false}
ownFocus={false}
panelPaddingSize="none"
withTitle={true}
>
<EuiContextMenuPanel
hasFocus={true}
items={
Array [
<EuiContextMenuItem
icon="empty"
onClick={[Function]}
>
5
</EuiContextMenuItem>,
<EuiContextMenuItem
icon="empty"
onClick={[Function]}
>
10
</EuiContextMenuItem>,
<EuiContextMenuItem
icon="empty"
onClick={[Function]}
>
20
</EuiContextMenuItem>,
<EuiContextMenuItem
icon="empty"
onClick={[Function]}
>
50
</EuiContextMenuItem>,
]
}
/>
</EuiPopover>
</EuiFlexItem>
</EuiFlexGroup>
</div>
`;
exports[`IndicesList should render normally 1`] = `
<div>
<EuiTable>

View file

@ -10,7 +10,7 @@ const indices = [
describe('IndicesList', () => {
it('should render normally', () => {
const component = shallow(
<IndicesList indices={indices}/>
<IndicesList indices={indices} query=""/>
);
expect(component).toMatchSnapshot();
@ -18,7 +18,7 @@ describe('IndicesList', () => {
it('should change pages', () => {
const component = shallow(
<IndicesList indices={indices}/>
<IndicesList indices={indices} query=""/>
);
const instance = component.instance();
@ -32,7 +32,7 @@ describe('IndicesList', () => {
it('should change per page', () => {
const component = shallow(
<IndicesList indices={indices}/>
<IndicesList indices={indices} query="" />
);
const instance = component.instance();
@ -42,10 +42,18 @@ describe('IndicesList', () => {
expect(component).toMatchSnapshot();
});
it('should highlight the query in the matches', () => {
const component = shallow(
<IndicesList indices={indices} query="ki" />
);
expect(component).toMatchSnapshot();
});
describe('updating props', () => {
it('should render all new indices', () => {
const component = shallow(
<IndicesList indices={indices}/>
<IndicesList indices={indices} query=""/>
);
const moreIndices = [

View file

@ -24,6 +24,7 @@ import {
export class IndicesList extends Component {
static propTypes = {
indices: PropTypes.array.isRequired,
query: PropTypes.string.isRequired,
}
constructor(props) {
@ -129,15 +130,35 @@ export class IndicesList extends Component {
);
}
highlightIndexName(indexName, query) {
const queryIdx = indexName.indexOf(query);
if (!query || queryIdx === -1) {
return indexName;
}
const preStr = indexName.substr(0, queryIdx);
const postStr = indexName.substr(queryIdx + query.length);
return (
<span>
{preStr}
<strong>{query}</strong>
{postStr}
</span>
);
}
render() {
const { indices } = this.props;
const { indices, query } = this.props;
const queryWithoutWildcard = query.endsWith('*') ? query.substr(0, query.length - 1) : query;
const paginatedIndices = indices.slice(this.pager.firstItemIndex, this.pager.lastItemIndex + 1);
const rows = paginatedIndices.map((index, key) => {
return (
<EuiTableRow key={key}>
<EuiTableRowCell>
{index.name}
{this.highlightIndexName(index.name, queryWithoutWildcard)}
</EuiTableRowCell>
</EuiTableRow>
);

View file

@ -3,7 +3,7 @@ import PropTypes from 'prop-types';
import { ILLEGAL_CHARACTERS, MAX_SEARCH_SIZE } from '../../constants';
import {
getIndices,
isIndexPatternQueryValid,
containsInvalidCharacters,
getMatchedIndices,
canAppendWildcard,
createReasonableWait
@ -139,6 +139,7 @@ export class StepIndexPattern extends Component {
return (
<IndicesList
query={query}
indices={indicesToList}
/>
);
@ -170,12 +171,16 @@ export class StepIndexPattern extends Component {
const errors = [];
const characterList = ILLEGAL_CHARACTERS.slice(0, ILLEGAL_CHARACTERS.length - 1).join(', ');
if (!isIndexPatternQueryValid(query, ILLEGAL_CHARACTERS)) {
if (!query || !query.length || query === '.' || query === '..') {
// This is an error scenario but do not report an error
containsErrors = true;
}
else if (!containsInvalidCharacters(query, ILLEGAL_CHARACTERS)) {
errors.push(`Your input contains invalid characters or spaces. Please omit: ${characterList}`);
containsErrors = true;
}
const isInputInvalid = showingIndexPatternQueryErrors && containsErrors;
const isInputInvalid = showingIndexPatternQueryErrors && containsErrors && errors.length > 0;
const isNextStepDisabled = containsErrors || indices.length === 0 || indexPatternExists;
return (

View file

@ -0,0 +1,13 @@
import { containsInvalidCharacters } from '../contains_invalid_characters';
describe('containsInvalidCharacters', () => {
it('should fail with illegal characters', () => {
const valid = containsInvalidCharacters('abc', ['a']);
expect(valid).toBeFalsy();
});
it('should pass with no illegal characters', () => {
const valid = containsInvalidCharacters('abc', ['%']);
expect(valid).toBeTruthy();
});
});

View file

@ -1,33 +0,0 @@
import { isIndexPatternQueryValid } from '../is_index_pattern_query_valid';
describe('isIndexPatternQueryValid', () => {
it('should fail with illegal characters', () => {
const valid = isIndexPatternQueryValid('abc', ['a']);
expect(valid).toBeFalsy();
});
it('should pass with no illegal characters', () => {
const valid = isIndexPatternQueryValid('abc', ['%']);
expect(valid).toBeTruthy();
});
it('should fail if the pattern starts with a single dot', () => {
const valid = isIndexPatternQueryValid('.');
expect(valid).toBeFalsy();
});
it('should fail if the pattern starts with a double dot', () => {
const valid = isIndexPatternQueryValid('..');
expect(valid).toBeFalsy();
});
it('should fail if no pattern is passed in', () => {
const valid = isIndexPatternQueryValid(null);
expect(valid).toBeFalsy();
});
it('should fail if an empty pattern is passed in', () => {
const valid = isIndexPatternQueryValid('');
expect(valid).toBeFalsy();
});
});

View file

@ -0,0 +1,3 @@
export function containsInvalidCharacters(pattern, illegalCharacters) {
return !illegalCharacters.some(char => pattern.includes(char));
}

View file

@ -6,6 +6,6 @@ export { getIndices } from './get_indices';
export { getMatchedIndices } from './get_matched_indices';
export { isIndexPatternQueryValid } from './is_index_pattern_query_valid';
export { containsInvalidCharacters } from './contains_invalid_characters';
export { extractTimeFields } from './extract_time_fields';

View file

@ -1,11 +0,0 @@
export function isIndexPatternQueryValid(pattern, illegalCharacters) {
if (!pattern || !pattern.length) {
return false;
}
if (pattern === '.' || pattern === '..') {
return false;
}
return !illegalCharacters.some(char => pattern.includes(char));
}