[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:
parent
8664b55ac2
commit
32f50b0a27
|
@ -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>
|
||||
`;
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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 = [
|
||||
|
|
|
@ -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>
|
||||
);
|
||||
|
|
|
@ -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 (
|
||||
|
|
|
@ -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();
|
||||
});
|
||||
});
|
|
@ -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();
|
||||
});
|
||||
});
|
|
@ -0,0 +1,3 @@
|
|||
export function containsInvalidCharacters(pattern, illegalCharacters) {
|
||||
return !illegalCharacters.some(char => pattern.includes(char));
|
||||
}
|
|
@ -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';
|
||||
|
|
|
@ -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));
|
||||
}
|
Loading…
Reference in a new issue