Skip to content

Commit

Permalink
[Search][a11y] Add validation to extraction rules form (#202980)
Browse files Browse the repository at this point in the history
## Closes: #199154

This adds more validations to the Crawler extraction rules form.

The original issue of the error being at the top of the page is not
easily fixable, as it's a catch-all server error display. Ideally, we
shouldn't have server errors occurring at all, so it makes sense to me
to just add a front-end validation to the inputs in this field.

These validations cover the following previously-missed scenarios:

1. When a user has not added any rules
2. When rule is for a specific URL and the URL pattern field is empty,
or doesn't begin with `/`
3. When the value for "Source" is empty (covers both HTML element and
URL selectors)
4. When "Content" is "A fixed value" and the value field is empty

(cherry picked from commit 9865da3)
  • Loading branch information
navarone-feekery committed Dec 27, 2024
1 parent 324eb8f commit 3d3b0d7
Show file tree
Hide file tree
Showing 2 changed files with 81 additions and 28 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -298,9 +298,34 @@ export const EditExtractionRule: React.FC<EditExtractionRuleProps> = ({
<Controller
control={control}
name={`url_filters.${index}.pattern`}
render={({ field }) => (
rules={{
validate: (rule) => {
if (!rule?.trim()) {
return i18n.translate(
'xpack.enterpriseSearch.content.indices.extractionRules.editContentField.fieldInput.requiredError',
{
defaultMessage: 'A value is required.',
}
);
}

if (rule[0] !== '/') {
return i18n.translate(
'xpack.enterpriseSearch.content.indices.extractionRules.editContentField.fieldInput.slashMissingError',
{
defaultMessage: 'Value must begin with a /.',
}
);
}

return true;
},
}}
render={({ field, fieldState: { error, isTouched } }) => (
<>
<EuiFormRow
isInvalid={!!error && isTouched}
error={error?.message}
label={i18n.translate(
'xpack.enterpriseSearch.content.indices.extractionRules.editRule.url.urlFilter.',
{
Expand All @@ -311,6 +336,7 @@ export const EditExtractionRule: React.FC<EditExtractionRuleProps> = ({
<EuiFieldText
data-telemetry-id="entSearchContent-crawler-domainDetail-extractionRules-urlPattern"
fullWidth
isInvalid={!!error && isTouched}
placeholder={i18n.translate(
'xpack.enterpriseSearch.content.indices.extractionRules.editRule.url.urlFilters.patternPlaceholder',
{
Expand Down Expand Up @@ -414,7 +440,7 @@ export const EditExtractionRule: React.FC<EditExtractionRuleProps> = ({
data-telemetry-id="entSearchContent-crawler-domainDetail-extractionRules-saveExtractionRule"
type="submit"
onClick={() => saveRule({ ...getValues() })}
disabled={!formState.isValid}
disabled={!formState.isValid || !rulesFields || rulesFields.length === 0}
>
{i18n.translate(
'xpack.enterpriseSearch.content.indices.extractionRules.editRule.saveButtonLabel',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -227,28 +227,39 @@ export const EditFieldRuleFlyout: React.FC<EditFieldRuleFlyoutProps> = ({
{!!field.value && (
<>
<EuiSpacer />
<EuiFormRow
fullWidth
label={
field.value === FieldType.HTML
? i18n.translate(
'xpack.enterpriseSearch.content.indices.extractionRules.editContentField.content.htmlLabel',
{
defaultMessage: 'CSS selector or XPath expression',
}
)
: i18n.translate(
'xpack.enterpriseSearch.content.indices.extractionRules.editContentField.content.urlLabel',
{
defaultMessage: 'URL pattern',
}
)
}
>
<Controller
control={control}
name="selector"
render={({ field: selectorField, fieldState: { error, isTouched } }) => (
<Controller
control={control}
name="selector"
rules={{
validate: (rule) =>
!!rule?.trim() ||
i18n.translate(
'xpack.enterpriseSearch.content.indices.extractionRules.editContentField.fieldInput.requiredError',
{
defaultMessage: 'A value is required.',
}
),
}}
render={({ field: selectorField, fieldState: { error, isTouched } }) => (
<EuiFormRow
isInvalid={!!error && isTouched}
error={error?.message}
label={
field.value === FieldType.HTML
? i18n.translate(
'xpack.enterpriseSearch.content.indices.extractionRules.editContentField.content.htmlLabel',
{
defaultMessage: 'CSS selector or XPath expression',
}
)
: i18n.translate(
'xpack.enterpriseSearch.content.indices.extractionRules.editContentField.content.urlLabel',
{
defaultMessage: 'URL pattern',
}
)
}
>
<EuiFieldText
data-telemetry-id="entSearchContent-crawler-domainDetail-extractionRules-editContentRuleSelector"
isInvalid={!!error && isTouched}
Expand All @@ -273,9 +284,9 @@ export const EditFieldRuleFlyout: React.FC<EditFieldRuleFlyoutProps> = ({
onChange={selectorField.onChange}
value={selectorField.value ?? ''}
/>
)}
/>
</EuiFormRow>
</EuiFormRow>
)}
/>
<EuiSpacer />
{field.value === FieldType.HTML ? (
<EuiLink
Expand Down Expand Up @@ -443,8 +454,23 @@ export const EditFieldRuleFlyout: React.FC<EditFieldRuleFlyoutProps> = ({
<Controller
control={control}
name="content_from.value"
render={({ field: valueField }) => (
rules={{
validate: (rule) =>
!!rule?.trim() ||
i18n.translate(
'xpack.enterpriseSearch.content.indices.extractionRules.editContentField.contentFixedValue.requiredError',
{
defaultMessage: 'A value is required',
}
),
}}
render={({
field: valueField,
fieldState: { error: fieldError, isTouched: fieldIsTouched },
}) => (
<EuiFormRow
isInvalid={!!fieldError && fieldIsTouched}
error={fieldError?.message}
helpText={i18n.translate(
'xpack.enterpriseSearch.content.indices.extractionRules.editContentField.fixedValue.helpText',
{
Expand All @@ -461,6 +487,7 @@ export const EditFieldRuleFlyout: React.FC<EditFieldRuleFlyoutProps> = ({
<EuiFieldText
data-telemetry-id="entSearchContent-crawler-domainDetail-extractionRules-editContentRuleFixedValue"
fullWidth
isInvalid={!!fieldError && fieldIsTouched}
placeholder={i18n.translate(
'xpack.enterpriseSearch.content.indices.extractionRules.editContentField.fixedValue.placeHolder',
{
Expand Down

0 comments on commit 3d3b0d7

Please sign in to comment.