Remove dangerously set inner html (#33976)
Fixes #24781 Replaces dangerouslySetInnerHtml with JSX using FormattedMessage for i18n.
This commit is contained in:
parent
5f511fcd83
commit
fd3535fdcf
|
@ -26,12 +26,9 @@ exports[`SuggestionComponent Should display the suggestion and use the provided
|
|||
</div>
|
||||
<div
|
||||
className="kbnSuggestionItem__description"
|
||||
dangerouslySetInnerHTML={
|
||||
Object {
|
||||
"__html": "This is not a helpful suggestion",
|
||||
}
|
||||
}
|
||||
/>
|
||||
>
|
||||
This is not a helpful suggestion
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
@ -62,12 +59,9 @@ exports[`SuggestionComponent Should make the element active if the selected prop
|
|||
</div>
|
||||
<div
|
||||
className="kbnSuggestionItem__description"
|
||||
dangerouslySetInnerHTML={
|
||||
Object {
|
||||
"__html": "This is not a helpful suggestion",
|
||||
}
|
||||
}
|
||||
/>
|
||||
>
|
||||
This is not a helpful suggestion
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
|
|
@ -67,14 +67,7 @@ export const SuggestionComponent: SFC<Props> = props => {
|
|||
<EuiIcon type={getEuiIconType(props.suggestion.type)} />
|
||||
</div>
|
||||
<div className="kbnSuggestionItem__text">{props.suggestion.text}</div>
|
||||
<div
|
||||
className="kbnSuggestionItem__description"
|
||||
// Description currently always comes from us and we escape any potential user input
|
||||
// at the time we're generating the description text
|
||||
// eslint-disable-next-line react/no-danger
|
||||
// @ts-ignore
|
||||
dangerouslySetInnerHTML={{ __html: props.suggestion.description }}
|
||||
/>
|
||||
<div className="kbnSuggestionItem__description">{props.suggestion.description}</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
|
|
@ -113,9 +113,7 @@ function Suggestion(props) {
|
|||
<EuiIcon type={getEuiIconType(props.suggestion.type)} />
|
||||
</Icon>
|
||||
<TextValue>{props.suggestion.text}</TextValue>
|
||||
<Description
|
||||
dangerouslySetInnerHTML={{ __html: props.suggestion.description }}
|
||||
/>
|
||||
<Description>{props.suggestion.description}</Description>
|
||||
</ListItem>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -36,9 +36,7 @@ export class SuggestionItem extends React.Component<SuggestionItemProps> {
|
|||
<EuiIcon type={getEuiIconType(suggestion.type)} />
|
||||
</SuggestionItemIconField>
|
||||
<SuggestionItemTextField>{suggestion.text}</SuggestionItemTextField>
|
||||
<SuggestionItemDescriptionField
|
||||
dangerouslySetInnerHTML={{ __html: suggestion.description }}
|
||||
/>
|
||||
<SuggestionItemDescriptionField>{suggestion.description}</SuggestionItemDescriptionField>
|
||||
</SuggestionItemContainer>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -36,9 +36,7 @@ export class SuggestionItem extends React.Component<SuggestionItemProps> {
|
|||
<EuiIcon type={getEuiIconType(suggestion.type)} />
|
||||
</SuggestionItemIconField>
|
||||
<SuggestionItemTextField>{suggestion.text}</SuggestionItemTextField>
|
||||
<SuggestionItemDescriptionField
|
||||
dangerouslySetInnerHTML={{ __html: suggestion.description }}
|
||||
/>
|
||||
<SuggestionItemDescriptionField>{suggestion.description}</SuggestionItemDescriptionField>
|
||||
</SuggestionItemContainer>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -35,13 +35,14 @@ describe('Kuery conjunction suggestions', function () {
|
|||
expect(suggestions.map(suggestion => suggestion.start)).to.eql([end, end]);
|
||||
expect(suggestions.map(suggestion => suggestion.end)).to.eql([end, end]);
|
||||
});
|
||||
|
||||
it('should have descriptions', function () {
|
||||
const text = ' ';
|
||||
const suggestions = getSuggestions({ text });
|
||||
expect(suggestions.length).to.be(2);
|
||||
expect(typeof suggestions).to.be('object');
|
||||
expect(Object.keys(suggestions).length).to.be(2);
|
||||
suggestions.forEach(suggestion => {
|
||||
expect(suggestion.description.length).to.be.greaterThan(0);
|
||||
expect(typeof suggestion).to.be('object');
|
||||
expect(suggestion).to.have.property('description');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -77,7 +77,7 @@ describe('Kuery field suggestions', function () {
|
|||
const suggestions = getSuggestions({ prefix, suffix });
|
||||
expect(suggestions.length).to.be.greaterThan(0);
|
||||
suggestions.forEach(suggestion => {
|
||||
expect(suggestion.description.length).to.be.greaterThan(0);
|
||||
expect(suggestion).to.have.property('description');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -53,7 +53,7 @@ describe('Kuery operator suggestions', function () {
|
|||
const suggestions = getSuggestions({ fieldName });
|
||||
expect(suggestions.length).to.be.greaterThan(0);
|
||||
suggestions.forEach(suggestion => {
|
||||
expect(suggestion.description.length).to.be.greaterThan(0);
|
||||
expect(suggestion).to.have.property('description');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -3,37 +3,48 @@
|
|||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import React from 'react';
|
||||
import { FormattedMessage } from '@kbn/i18n/react';
|
||||
|
||||
const type = 'conjunction';
|
||||
|
||||
const bothArgumentsText = i18n.translate('xpack.kueryAutocomplete.andOperatorDescription.bothArgumentsText', {
|
||||
defaultMessage: 'both arguments',
|
||||
description: 'Part of xpack.kueryAutocomplete.andOperatorDescription. Full text: "Requires both arguments to be true"'
|
||||
});
|
||||
const oneOrMoreArgumentsText = i18n.translate('xpack.kueryAutocomplete.orOperatorDescription.oneOrMoreArgumentsText', {
|
||||
defaultMessage: 'one or more arguments',
|
||||
description: 'Part of xpack.kueryAutocomplete.orOperatorDescription. Full text: "Requires one or more arguments to be true"'
|
||||
});
|
||||
const bothArgumentsText =
|
||||
(<FormattedMessage
|
||||
id="xpack.kueryAutocomplete.andOperatorDescription.bothArgumentsText"
|
||||
defaultMessage="both arguments"
|
||||
description="Part of xpack.kueryAutocomplete.andOperatorDescription. Full text: 'Requires both arguments to be true'"
|
||||
/>);
|
||||
|
||||
const oneOrMoreArgumentsText =
|
||||
(<FormattedMessage
|
||||
id="xpack.kueryAutocomplete.orOperatorDescription.oneOrMoreArgumentsText"
|
||||
defaultMessage="one or more arguments"
|
||||
description="Part of xpack.kueryAutocomplete.orOperatorDescription. Full text: 'Requires one or more arguments to be true'"
|
||||
/>);
|
||||
|
||||
const conjunctions = {
|
||||
and: '<p>' +
|
||||
i18n.translate('xpack.kueryAutocomplete.andOperatorDescription', {
|
||||
defaultMessage: 'Requires {bothArguments} to be true',
|
||||
values: { bothArguments: `<span class="kbnSuggestionItem__callout">${bothArgumentsText}</span>` },
|
||||
description: 'Full text: "Requires both arguments to be true". See ' +
|
||||
'xpack.kueryAutocomplete.andOperatorDescription.bothArgumentsText for "both arguments" part.'
|
||||
}) +
|
||||
'</p>',
|
||||
or: '<p>' +
|
||||
i18n.translate('xpack.kueryAutocomplete.orOperatorDescription', {
|
||||
defaultMessage: 'Requires {oneOrMoreArguments} to be true',
|
||||
values: { oneOrMoreArguments: `<span class="kbnSuggestionItem__callout">${oneOrMoreArgumentsText}</span>` },
|
||||
description: 'Full text: "Requires one or more arguments to be true". See ' +
|
||||
'xpack.kueryAutocomplete.orOperatorDescription.oneOrMoreArgumentsText for "one or more arguments" part.'
|
||||
}) +
|
||||
'</p>'
|
||||
and: (
|
||||
<p>
|
||||
<FormattedMessage
|
||||
id="xpack.kueryAutocomplete.andOperatorDescription"
|
||||
defaultMessage="Requires {bothArguments} to be true"
|
||||
values={{ bothArguments: <span className="kbnSuggestionItem__callout">{bothArgumentsText}</span> }}
|
||||
description="Full text: ' Requires both arguments to be true'. See
|
||||
'xpack.kueryAutocomplete.andOperatorDescription.bothArgumentsText' for 'both arguments' part."
|
||||
/>
|
||||
</p>
|
||||
),
|
||||
or: (
|
||||
<p>
|
||||
<FormattedMessage
|
||||
id="xpack.kueryAutocomplete.orOperatorDescription"
|
||||
defaultMessage="Requires {oneOrMoreArguments} to be true"
|
||||
values={{ oneOrMoreArguments: <span className="kbnSuggestionItem__callout">{oneOrMoreArgumentsText}</span> }}
|
||||
description="Full text: 'Requires one or more arguments to be true'. See
|
||||
'xpack.kueryAutocomplete.orOperatorDescription.oneOrMoreArgumentsText' for 'one or more arguments' part."
|
||||
/>
|
||||
</p>
|
||||
)
|
||||
};
|
||||
|
||||
function getDescription(conjunction) {
|
||||
|
|
|
@ -3,23 +3,26 @@
|
|||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import { escape, flatten } from 'lodash';
|
||||
import React from 'react';
|
||||
import { flatten } from 'lodash';
|
||||
import { escapeKuery } from './escape_kuery';
|
||||
import { sortPrefixFirst } from 'ui/utils/sort_prefix_first';
|
||||
import { isFilterable } from 'ui/index_patterns/static_utils';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { FormattedMessage } from '@kbn/i18n/react';
|
||||
|
||||
|
||||
const type = 'field';
|
||||
|
||||
function getDescription(fieldName) {
|
||||
return '<p>' +
|
||||
i18n.translate('xpack.kueryAutocomplete.filterResultsDescription', {
|
||||
defaultMessage: 'Filter results that contain {fieldName}',
|
||||
values: { fieldName: `<span class="kbnSuggestionItem__callout">${escape(fieldName)}</span>` }
|
||||
}) +
|
||||
'</p>';
|
||||
return (
|
||||
<p>
|
||||
<FormattedMessage
|
||||
id="xpack.kueryAutocomplete.filterResultsDescription"
|
||||
defaultMessage="Filter results that contain {fieldName}"
|
||||
values={{ fieldName: <span className="kbnSuggestionItem__callout">{fieldName}</span> }}
|
||||
/>
|
||||
</p>
|
||||
);
|
||||
}
|
||||
|
||||
export function getSuggestionsProvider({ indexPatterns }) {
|
||||
|
|
|
@ -4,95 +4,119 @@
|
|||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import { i18n } from '@kbn/i18n';
|
||||
|
||||
import React from 'react';
|
||||
import { FormattedMessage } from '@kbn/i18n/react';
|
||||
import { flatten } from 'lodash';
|
||||
const type = 'operator';
|
||||
|
||||
const equalsText = i18n.translate('xpack.kueryAutocomplete.equalOperatorDescription.equalsText', {
|
||||
defaultMessage: 'equals',
|
||||
description: 'Part of xpack.kueryAutocomplete.equalOperatorDescription. Full text: "equals some value"'
|
||||
});
|
||||
const lessThanOrEqualToText = i18n.translate('xpack.kueryAutocomplete.lessThanOrEqualOperatorDescription.lessThanOrEqualToText', {
|
||||
defaultMessage: 'less than or equal to',
|
||||
description: 'Part of xpack.kueryAutocomplete.lessThanOrEqualOperatorDescription. Full text: "is less than or equal to some value"'
|
||||
});
|
||||
const greaterThanOrEqualToText = i18n.translate('xpack.kueryAutocomplete.greaterThanOrEqualOperatorDescription.greaterThanOrEqualToText', {
|
||||
defaultMessage: 'greater than or equal to',
|
||||
description: 'Part of xpack.kueryAutocomplete.greaterThanOrEqualOperatorDescription. Full text: "is greater than or equal to some value"'
|
||||
});
|
||||
const lessThanText = i18n.translate('xpack.kueryAutocomplete.lessThanOperatorDescription.lessThanText', {
|
||||
defaultMessage: 'less than',
|
||||
description: 'Part of xpack.kueryAutocomplete.lessThanOperatorDescription. Full text: "is less than some value"'
|
||||
});
|
||||
const greaterThanText = i18n.translate('xpack.kueryAutocomplete.greaterThanOperatorDescription.greaterThanText', {
|
||||
defaultMessage: 'greater than',
|
||||
description: 'Part of xpack.kueryAutocomplete.greaterThanOperatorDescription. Full text: "is greater than some value"'
|
||||
});
|
||||
const existsText = i18n.translate('xpack.kueryAutocomplete.existOperatorDescription.existsText', {
|
||||
defaultMessage: 'exists',
|
||||
description: 'Part of xpack.kueryAutocomplete.existOperatorDescription. Full text: "exists in any form"'
|
||||
});
|
||||
const equalsText = (
|
||||
<FormattedMessage
|
||||
id="xpack.kueryAutocomplete.equalOperatorDescription.equalsText"
|
||||
defaultMessage="equals"
|
||||
description="Part of xpack.kueryAutocomplete.equalOperatorDescription. Full text: 'equals some value'"
|
||||
/>);
|
||||
const lessThanOrEqualToText = (
|
||||
<FormattedMessage
|
||||
id="xpack.kueryAutocomplete.lessThanOrEqualOperatorDescription.lessThanOrEqualToText"
|
||||
defaultMessage="less than or equal to"
|
||||
description="Part of xpack.kueryAutocomplete.lessThanOrEqualOperatorDescription. Full text: 'is less than or equal to some value'"
|
||||
/>);
|
||||
const greaterThanOrEqualToText = (
|
||||
<FormattedMessage
|
||||
id="xpack.kueryAutocomplete.greaterThanOrEqualOperatorDescription.greaterThanOrEqualToText"
|
||||
defaultMessage="greater than or equal to"
|
||||
description="Part of xpack.kueryAutocomplete.greaterThanOrEqualOperatorDescription. Full text: 'is greater than or equal to some value'"
|
||||
/>);
|
||||
const lessThanText = (
|
||||
<FormattedMessage
|
||||
id="xpack.kueryAutocomplete.lessThanOperatorDescription.lessThanText"
|
||||
defaultMessage="less than"
|
||||
description="Part of xpack.kueryAutocomplete.lessThanOperatorDescription. Full text: 'is less than some value'"
|
||||
/>);
|
||||
const greaterThanText = (
|
||||
<FormattedMessage
|
||||
id="xpack.kueryAutocomplete.greaterThanOperatorDescription.greaterThanText"
|
||||
defaultMessage="greater than"
|
||||
description="Part of xpack.kueryAutocomplete.greaterThanOperatorDescription. Full text: 'is greater than some value'"
|
||||
/>);
|
||||
const existsText = (
|
||||
<FormattedMessage
|
||||
id="xpack.kueryAutocomplete.existOperatorDescription.existsText"
|
||||
defaultMessage="exists"
|
||||
description="Part of xpack.kueryAutocomplete.existOperatorDescription. Full text: 'exists in any form'"
|
||||
/>);
|
||||
|
||||
const operators = {
|
||||
':': {
|
||||
description: i18n.translate('xpack.kueryAutocomplete.equalOperatorDescription', {
|
||||
defaultMessage: '{equals} some value',
|
||||
values: { equals: `<span class="kbnSuggestionItem__callout">${equalsText}</span>` },
|
||||
description: 'Full text: "equals some value". See ' +
|
||||
'xpack.kueryAutocomplete.equalOperatorDescription.equalsText for "equals" part.'
|
||||
}),
|
||||
description: (
|
||||
<FormattedMessage
|
||||
id="xpack.kueryAutocomplete.equalOperatorDescription"
|
||||
defaultMessage="{equals} some value"
|
||||
values={{ equals: <span className="kbnSuggestionItem__callout">{equalsText}</span> }}
|
||||
description="Full text: 'equals some value'. See
|
||||
'xpack.kueryAutocomplete.equalOperatorDescription.equalsText' for 'equals' part."
|
||||
/>),
|
||||
fieldTypes: ['string', 'number', 'date', 'ip', 'geo_point', 'geo_shape', 'boolean']
|
||||
},
|
||||
'<=': {
|
||||
description: i18n.translate('xpack.kueryAutocomplete.lessThanOrEqualOperatorDescription', {
|
||||
defaultMessage: 'is {lessThanOrEqualTo} some value',
|
||||
values: { lessThanOrEqualTo: `<span class="kbnSuggestionItem__callout">${lessThanOrEqualToText}</span>` },
|
||||
description: 'Full text: "is less than or equal to some value". See ' +
|
||||
'xpack.kueryAutocomplete.lessThanOrEqualOperatorDescription.lessThanOrEqualToText for "less than or equal to" part.'
|
||||
}),
|
||||
description: (
|
||||
<FormattedMessage
|
||||
id="xpack.kueryAutocomplete.lessThanOrEqualOperatorDescription"
|
||||
defaultMessage="is {lessThanOrEqualTo} some value"
|
||||
values={{ lessThanOrEqualTo: <span className="kbnSuggestionItem__callout">{lessThanOrEqualToText}</span> }}
|
||||
description="Full text: 'is less than or equal to some value'. See
|
||||
'xpack.kueryAutocomplete.lessThanOrEqualOperatorDescription.lessThanOrEqualToText' for 'less than or equal to' part."
|
||||
/>),
|
||||
fieldTypes: ['number', 'date', 'ip']
|
||||
},
|
||||
'>=': {
|
||||
description: i18n.translate('xpack.kueryAutocomplete.greaterThanOrEqualOperatorDescription', {
|
||||
defaultMessage: 'is {greaterThanOrEqualTo} some value',
|
||||
values: { greaterThanOrEqualTo: `<span class="kbnSuggestionItem__callout">${greaterThanOrEqualToText}</span>` },
|
||||
description: 'Full text: "is greater than or equal to some value". See ' +
|
||||
'xpack.kueryAutocomplete.greaterThanOrEqualOperatorDescription.greaterThanOrEqualToText for "greater than or equal to" part.'
|
||||
}),
|
||||
description: (
|
||||
<FormattedMessage
|
||||
id="xpack.kueryAutocomplete.greaterThanOrEqualOperatorDescription"
|
||||
defaultMessage="is {greaterThanOrEqualTo} some value"
|
||||
values={{ greaterThanOrEqualTo: <span className="kbnSuggestionItem__callout">{greaterThanOrEqualToText}</span> }}
|
||||
description="Full text: 'is greater than or equal to some value'. See
|
||||
'xpack.kueryAutocomplete.greaterThanOrEqualOperatorDescription.greaterThanOrEqualToText' for 'greater than or equal to' part."
|
||||
/>),
|
||||
fieldTypes: ['number', 'date', 'ip']
|
||||
},
|
||||
'<': {
|
||||
description: i18n.translate('xpack.kueryAutocomplete.lessThanOperatorDescription', {
|
||||
defaultMessage: 'is {lessThan} some value',
|
||||
values: { lessThan: `<span class="kbnSuggestionItem__callout">${lessThanText}</span>` },
|
||||
description: 'Full text: "is less than some value". See ' +
|
||||
'xpack.kueryAutocomplete.lessThanOperatorDescription.lessThanText for "less than" part.'
|
||||
}),
|
||||
description: (
|
||||
<FormattedMessage
|
||||
id="xpack.kueryAutocomplete.lessThanOperatorDescription"
|
||||
defaultMessage="is {lessThan} some value"
|
||||
values={{ lessThan: <span className="kbnSuggestionItem__callout">{lessThanText}</span> }}
|
||||
description="Full text: 'is less than some value'. See
|
||||
'xpack.kueryAutocomplete.lessThanOperatorDescription.lessThanText' for 'less than' part."
|
||||
/>),
|
||||
fieldTypes: ['number', 'date', 'ip']
|
||||
},
|
||||
'>': {
|
||||
description: i18n.translate('xpack.kueryAutocomplete.greaterThanOperatorDescription', {
|
||||
defaultMessage: 'is {greaterThan} some value',
|
||||
values: { greaterThan: `<span class="kbnSuggestionItem__callout">${greaterThanText}</span>` },
|
||||
description: 'Full text: "is greater than some value". See ' +
|
||||
'xpack.kueryAutocomplete.greaterThanOperatorDescription.greaterThanText for "greater than" part.'
|
||||
}),
|
||||
description: (
|
||||
<FormattedMessage
|
||||
id="xpack.kueryAutocomplete.greaterThanOperatorDescription"
|
||||
defaultMessage="is {greaterThan} some value"
|
||||
values={{ greaterThan: <span className="kbnSuggestionItem__callout">{greaterThanText}</span> }}
|
||||
description="Full text: 'is greater than some value'. See
|
||||
'xpack.kueryAutocomplete.greaterThanOperatorDescription.greaterThanText' for 'greater than' part."
|
||||
/>),
|
||||
fieldTypes: ['number', 'date', 'ip']
|
||||
},
|
||||
':*': {
|
||||
description: i18n.translate('xpack.kueryAutocomplete.existOperatorDescription', {
|
||||
defaultMessage: '{exists} in any form',
|
||||
values: { exists: `<span class="kbnSuggestionItem__callout">${existsText}</span>` },
|
||||
description: 'Full text: "exists in any form". See ' +
|
||||
'xpack.kueryAutocomplete.existOperatorDescription.existsText for "exists" part.'
|
||||
})
|
||||
description: (
|
||||
<FormattedMessage
|
||||
id="xpack.kueryAutocomplete.existOperatorDescription"
|
||||
defaultMessage="{exists} in any form"
|
||||
values={{ exists: <span className="kbnSuggestionItem__callout">{existsText}</span> }}
|
||||
description="Full text: 'exists in any form'. See
|
||||
'xpack.kueryAutocomplete.existOperatorDescription.existsText' for 'exists' part."
|
||||
/>)
|
||||
},
|
||||
};
|
||||
|
||||
function getDescription(operator) {
|
||||
const { description } = operators[operator];
|
||||
return `<p>${description}</p>`;
|
||||
return <p>{description}</p>;
|
||||
}
|
||||
|
||||
export function getSuggestionsProvider({ indexPatterns }) {
|
||||
|
|
|
@ -17,12 +17,8 @@ exports[`Suggestion snapshot 1`] = `
|
|||
<styled.div>
|
||||
fieldValue
|
||||
</styled.div>
|
||||
<styled.div
|
||||
dangerouslySetInnerHTML={
|
||||
Object {
|
||||
"__html": "<p>Test description for fieldValue</p>",
|
||||
}
|
||||
}
|
||||
/>
|
||||
<styled.div>
|
||||
<p>Test description for fieldValue</p>
|
||||
</styled.div>
|
||||
</styled.li>
|
||||
`;
|
||||
|
|
|
@ -106,9 +106,7 @@ export const Suggestion = (props) => {
|
|||
<EuiIcon type={getEuiIconType(props.suggestion.type)} />
|
||||
</Icon>
|
||||
<TextValue>{props.suggestion.text}</TextValue>
|
||||
<Description
|
||||
dangerouslySetInnerHTML={{ __html: props.suggestion.description }}
|
||||
/>
|
||||
<Description>{props.suggestion.description}</Description>
|
||||
</ListItem>
|
||||
);
|
||||
};
|
||||
|
|
Loading…
Reference in a new issue