mirror of
https://github.com/elastic/kibana.git
synced 2025-04-23 09:19:04 -04:00
fix: [Rules > Add/Edit rule exception][AXE-CORE]: Form elements must have an accessible label (#177923)
Closes: https://github.com/elastic/security-team/issues/8572 Closes: https://github.com/elastic/security-team/issues/8573 Closes: https://github.com/elastic/security-team/issues/8613 Closes: https://github.com/elastic/security-team/issues/8614 ## Description The [axe browser plugin](https://deque.com/axe) is reporting two form elements without labels in the Create endpoint exception flyout. Screenshot attached below. ### Steps to recreate 1. Open [Shared Exception Lists](https://kibana.siem.estc.dev/app/security/exceptions) 2. Click the Create Endpoint Exception button 3. Run an axe browser scan in Chrome, Edge, or Firefox 4. Verify the form label missing errors ### Screens #### a11y attributes <img width="1419" alt="image" src="61ef3ea1
-bd65-46e0-9274-ae9aa329a04d"> #### Axe report <img width="1419" alt="image" src="df5ba30c
-78f5-4418-b3b6-09a028e1c606"> --------- Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com> Co-authored-by: Vitalii Dmyterko <92328789+vitaliidm@users.noreply.github.com>
This commit is contained in:
parent
8f39000270
commit
b63c9e2824
12 changed files with 124 additions and 33 deletions
|
@ -28,6 +28,7 @@ export const FieldComponent: React.FC<FieldProps> = ({
|
|||
selectedField,
|
||||
acceptsCustomOptions = false,
|
||||
showMappingConflicts = false,
|
||||
'aria-label': ariaLabel,
|
||||
}): JSX.Element => {
|
||||
const {
|
||||
isInvalid,
|
||||
|
@ -71,6 +72,7 @@ export const FieldComponent: React.FC<FieldProps> = ({
|
|||
})}
|
||||
fullWidth
|
||||
renderOption={renderFields}
|
||||
aria-label={ariaLabel}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
@ -91,6 +93,7 @@ export const FieldComponent: React.FC<FieldProps> = ({
|
|||
style={fieldWidth}
|
||||
fullWidth
|
||||
renderOption={renderFields}
|
||||
aria-label={ariaLabel}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
|
|
@ -17,6 +17,7 @@ export interface FieldProps extends FieldBaseProps {
|
|||
placeholder: string;
|
||||
acceptsCustomOptions?: boolean;
|
||||
showMappingConflicts?: boolean;
|
||||
'aria-label'?: string;
|
||||
}
|
||||
export interface FieldBaseProps {
|
||||
indexPattern: DataViewBase | undefined;
|
||||
|
|
|
@ -14,11 +14,13 @@ const NO_OPTIONS_FOR_EXIST: EuiComboBoxOptionOption[] = [];
|
|||
interface AutocompleteFieldExistsProps {
|
||||
placeholder: string;
|
||||
rowLabel?: string;
|
||||
'aria-label'?: string;
|
||||
}
|
||||
|
||||
export const AutocompleteFieldExistsComponent: React.FC<AutocompleteFieldExistsProps> = ({
|
||||
placeholder,
|
||||
rowLabel,
|
||||
'aria-label': ariaLabel,
|
||||
}): JSX.Element => (
|
||||
<EuiFormRow label={rowLabel} fullWidth>
|
||||
<EuiComboBox
|
||||
|
@ -28,6 +30,7 @@ export const AutocompleteFieldExistsComponent: React.FC<AutocompleteFieldExistsP
|
|||
onChange={undefined}
|
||||
isDisabled
|
||||
data-test-subj="valuesAutocompleteComboBox existsComboxBox"
|
||||
aria-label={ariaLabel}
|
||||
fullWidth
|
||||
/>
|
||||
</EuiFormRow>
|
||||
|
|
|
@ -35,6 +35,7 @@ interface AutocompleteFieldListsProps {
|
|||
selectedField: DataViewFieldBase | undefined;
|
||||
selectedValue: string | undefined;
|
||||
allowLargeValueLists?: boolean;
|
||||
'aria-label'?: string;
|
||||
}
|
||||
|
||||
export interface AutocompleteListsData {
|
||||
|
@ -53,6 +54,7 @@ export const AutocompleteFieldListsComponent: React.FC<AutocompleteFieldListsPro
|
|||
selectedField,
|
||||
selectedValue,
|
||||
allowLargeValueLists = false,
|
||||
'aria-label': ariaLabel,
|
||||
}): JSX.Element => {
|
||||
const [error, setError] = useState<string | undefined>(undefined);
|
||||
const [listData, setListData] = useState<AutocompleteListsData>({
|
||||
|
@ -162,6 +164,7 @@ export const AutocompleteFieldListsComponent: React.FC<AutocompleteFieldListsPro
|
|||
selectedOptions={selectedComboOptions}
|
||||
singleSelection={SINGLE_SELECTION}
|
||||
sortMatchesBy="startsWith"
|
||||
aria-label={ariaLabel}
|
||||
/>
|
||||
</EuiFormRow>
|
||||
);
|
||||
|
|
|
@ -54,6 +54,7 @@ interface AutocompleteFieldMatchProps {
|
|||
autocompleteService: AutocompleteStart;
|
||||
onChange: (arg: string) => void;
|
||||
onError?: (arg: boolean) => void;
|
||||
'aria-label'?: string;
|
||||
}
|
||||
|
||||
export const AutocompleteFieldMatchComponent: React.FC<AutocompleteFieldMatchProps> = ({
|
||||
|
@ -70,6 +71,7 @@ export const AutocompleteFieldMatchComponent: React.FC<AutocompleteFieldMatchPro
|
|||
autocompleteService,
|
||||
onChange,
|
||||
onError,
|
||||
'aria-label': ariaLabel,
|
||||
}): JSX.Element => {
|
||||
const [searchQuery, setSearchQuery] = useState('');
|
||||
const [touched, setIsTouched] = useState(false);
|
||||
|
@ -245,27 +247,29 @@ export const AutocompleteFieldMatchComponent: React.FC<AutocompleteFieldMatchPro
|
|||
sortMatchesBy="startsWith"
|
||||
data-test-subj="valuesAutocompleteMatch"
|
||||
style={fieldInputWidth ? { width: `${fieldInputWidth}px` } : {}}
|
||||
aria-label={ariaLabel}
|
||||
fullWidth
|
||||
async
|
||||
/>
|
||||
</EuiFormRow>
|
||||
);
|
||||
}, [
|
||||
comboOptions,
|
||||
error,
|
||||
fieldInputWidth,
|
||||
inputPlaceholder,
|
||||
isClearable,
|
||||
isDisabled,
|
||||
isLoadingState,
|
||||
rowLabel,
|
||||
selectedComboOptions,
|
||||
error,
|
||||
selectedField,
|
||||
showSpacesWarning,
|
||||
handleCreateOption,
|
||||
handleSearchChange,
|
||||
inputPlaceholder,
|
||||
isDisabled,
|
||||
isLoadingState,
|
||||
isClearable,
|
||||
comboOptions,
|
||||
selectedComboOptions,
|
||||
handleValuesChange,
|
||||
handleSearchChange,
|
||||
handleCreateOption,
|
||||
setIsTouchedValue,
|
||||
fieldInputWidth,
|
||||
ariaLabel,
|
||||
]);
|
||||
|
||||
if (!isSuggestingValues && selectedField != null) {
|
||||
|
@ -290,6 +294,7 @@ export const AutocompleteFieldMatchComponent: React.FC<AutocompleteFieldMatchPro
|
|||
onChange={handleNonComboBoxInputChange}
|
||||
data-test-subj="valueAutocompleteFieldMatchNumber"
|
||||
style={fieldInputWidth ? { width: `${fieldInputWidth}px` } : {}}
|
||||
aria-label={ariaLabel}
|
||||
fullWidth
|
||||
/>
|
||||
</EuiFormRow>
|
||||
|
@ -310,6 +315,7 @@ export const AutocompleteFieldMatchComponent: React.FC<AutocompleteFieldMatchPro
|
|||
onChange={handleBooleanInputChange}
|
||||
data-test-subj="valuesAutocompleteMatchBoolean"
|
||||
style={fieldInputWidth ? { width: `${fieldInputWidth}px` } : {}}
|
||||
aria-label={ariaLabel}
|
||||
fullWidth
|
||||
/>
|
||||
</EuiFormRow>
|
||||
|
|
|
@ -38,6 +38,7 @@ interface AutocompleteFieldMatchAnyProps {
|
|||
autocompleteService: AutocompleteStart;
|
||||
onChange: (arg: string[]) => void;
|
||||
onError?: (arg: boolean) => void;
|
||||
'aria-label'?: string;
|
||||
}
|
||||
|
||||
export const AutocompleteFieldMatchAnyComponent: React.FC<AutocompleteFieldMatchAnyProps> = ({
|
||||
|
@ -53,6 +54,7 @@ export const AutocompleteFieldMatchAnyComponent: React.FC<AutocompleteFieldMatch
|
|||
onChange,
|
||||
onError,
|
||||
autocompleteService,
|
||||
'aria-label': ariaLabel,
|
||||
}): JSX.Element => {
|
||||
const [searchQuery, setSearchQuery] = useState('');
|
||||
const [touched, setIsTouched] = useState(false);
|
||||
|
@ -187,26 +189,28 @@ export const AutocompleteFieldMatchAnyComponent: React.FC<AutocompleteFieldMatch
|
|||
isCaseSensitive
|
||||
onBlur={setIsTouchedValue}
|
||||
data-test-subj="valuesAutocompleteMatchAny"
|
||||
aria-label={ariaLabel}
|
||||
fullWidth
|
||||
async
|
||||
/>
|
||||
</EuiFormRow>
|
||||
);
|
||||
}, [
|
||||
comboOptions,
|
||||
error,
|
||||
handleCreateOption,
|
||||
handleSearchChange,
|
||||
handleValuesChange,
|
||||
inputPlaceholder,
|
||||
isClearable,
|
||||
isDisabled,
|
||||
isLoadingState,
|
||||
rowLabel,
|
||||
selectedComboOptions,
|
||||
error,
|
||||
selectedField,
|
||||
showSpacesWarning,
|
||||
inputPlaceholder,
|
||||
isLoadingState,
|
||||
isClearable,
|
||||
isDisabled,
|
||||
comboOptions,
|
||||
selectedComboOptions,
|
||||
handleValuesChange,
|
||||
handleSearchChange,
|
||||
handleCreateOption,
|
||||
setIsTouchedValue,
|
||||
ariaLabel,
|
||||
]);
|
||||
|
||||
if (!isSuggestingValues && selectedField != null) {
|
||||
|
@ -232,6 +236,7 @@ export const AutocompleteFieldMatchAnyComponent: React.FC<AutocompleteFieldMatch
|
|||
isInvalid={selectedField != null && error != null}
|
||||
onFocus={setIsTouchedValue}
|
||||
data-test-subj="valuesAutocompleteMatchAnyNumber"
|
||||
aria-label={ariaLabel}
|
||||
fullWidth
|
||||
/>
|
||||
</EuiFormRow>
|
||||
|
|
|
@ -46,6 +46,7 @@ interface AutocompleteFieldWildcardProps {
|
|||
onError: (arg: boolean) => void;
|
||||
onWarning: (arg: boolean) => void;
|
||||
warning?: Warning;
|
||||
'aria-label'?: string;
|
||||
}
|
||||
|
||||
export const AutocompleteFieldWildcardComponent: React.FC<AutocompleteFieldWildcardProps> = memo(
|
||||
|
@ -65,6 +66,7 @@ export const AutocompleteFieldWildcardComponent: React.FC<AutocompleteFieldWildc
|
|||
onError,
|
||||
onWarning,
|
||||
warning,
|
||||
'aria-label': ariaLabel,
|
||||
}): JSX.Element => {
|
||||
const [searchQuery, setSearchQuery] = useState('');
|
||||
const [touched, setIsTouched] = useState(false);
|
||||
|
@ -252,26 +254,28 @@ export const AutocompleteFieldWildcardComponent: React.FC<AutocompleteFieldWildc
|
|||
style={fieldInputWidth ? { width: `${fieldInputWidth}px` } : {}}
|
||||
fullWidth
|
||||
async
|
||||
aria-label={ariaLabel}
|
||||
/>
|
||||
</EuiFormRow>
|
||||
);
|
||||
}, [
|
||||
comboOptions,
|
||||
error,
|
||||
fieldInputWidth,
|
||||
handleCreateOption,
|
||||
handleSearchChange,
|
||||
handleValuesChange,
|
||||
inputPlaceholder,
|
||||
isClearable,
|
||||
isDisabled,
|
||||
isLoadingState,
|
||||
rowLabel,
|
||||
selectedComboOptions,
|
||||
selectedField,
|
||||
setIsTouchedValue,
|
||||
error,
|
||||
warning,
|
||||
showSpacesWarning,
|
||||
selectedField,
|
||||
inputPlaceholder,
|
||||
isDisabled,
|
||||
isLoadingState,
|
||||
isClearable,
|
||||
comboOptions,
|
||||
selectedComboOptions,
|
||||
handleValuesChange,
|
||||
handleSearchChange,
|
||||
handleCreateOption,
|
||||
setIsTouchedValue,
|
||||
fieldInputWidth,
|
||||
ariaLabel,
|
||||
]);
|
||||
|
||||
return defaultInput;
|
||||
|
|
|
@ -29,6 +29,7 @@ interface OperatorState {
|
|||
operatorOptions?: OperatorOption[];
|
||||
placeholder: string;
|
||||
selectedField: DataViewFieldBase | undefined;
|
||||
'aria-label'?: string;
|
||||
}
|
||||
|
||||
export const OperatorComponent: React.FC<OperatorState> = ({
|
||||
|
@ -41,6 +42,7 @@ export const OperatorComponent: React.FC<OperatorState> = ({
|
|||
operatorInputWidth = 150,
|
||||
placeholder,
|
||||
selectedField,
|
||||
'aria-label': ariaLabel,
|
||||
}): JSX.Element => {
|
||||
const getLabel = useCallback(({ message }): string => message, []);
|
||||
const optionsMemo = useMemo(
|
||||
|
@ -90,6 +92,7 @@ export const OperatorComponent: React.FC<OperatorState> = ({
|
|||
singleSelection={AS_PLAIN_TEXT}
|
||||
data-test-subj="operatorAutocompleteComboBox"
|
||||
style={inputWidth}
|
||||
aria-label={ariaLabel}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
|
|
@ -82,6 +82,7 @@ describe('BuilderEntryItem', () => {
|
|||
onChange={jest.fn()}
|
||||
setErrorsExist={jest.fn()}
|
||||
setWarningsExist={jest.fn()}
|
||||
exceptionItemIndex={0}
|
||||
showLabel
|
||||
/>
|
||||
);
|
||||
|
@ -116,6 +117,7 @@ describe('BuilderEntryItem', () => {
|
|||
setWarningsExist={jest.fn()}
|
||||
showLabel
|
||||
allowCustomOptions
|
||||
exceptionItemIndex={0}
|
||||
/>
|
||||
);
|
||||
|
||||
|
@ -153,6 +155,7 @@ describe('BuilderEntryItem', () => {
|
|||
setWarningsExist={jest.fn()}
|
||||
showLabel
|
||||
allowCustomOptions
|
||||
exceptionItemIndex={0}
|
||||
/>
|
||||
);
|
||||
|
||||
|
@ -188,6 +191,7 @@ describe('BuilderEntryItem', () => {
|
|||
setWarningsExist={jest.fn()}
|
||||
showLabel
|
||||
allowCustomOptions={false}
|
||||
exceptionItemIndex={0}
|
||||
/>
|
||||
);
|
||||
|
||||
|
@ -225,6 +229,7 @@ describe('BuilderEntryItem', () => {
|
|||
showLabel
|
||||
allowCustomOptions
|
||||
getExtendedFields={(): Promise<FieldSpec[]> => Promise.resolve([field])}
|
||||
exceptionItemIndex={0}
|
||||
/>
|
||||
);
|
||||
|
||||
|
@ -261,6 +266,7 @@ describe('BuilderEntryItem', () => {
|
|||
setErrorsExist={jest.fn()}
|
||||
setWarningsExist={jest.fn()}
|
||||
showLabel={false}
|
||||
exceptionItemIndex={0}
|
||||
/>
|
||||
);
|
||||
|
||||
|
@ -300,6 +306,7 @@ describe('BuilderEntryItem', () => {
|
|||
setErrorsExist={jest.fn()}
|
||||
setWarningsExist={jest.fn()}
|
||||
showLabel={false}
|
||||
exceptionItemIndex={0}
|
||||
/>
|
||||
);
|
||||
|
||||
|
@ -339,6 +346,7 @@ describe('BuilderEntryItem', () => {
|
|||
setErrorsExist={jest.fn()}
|
||||
setWarningsExist={jest.fn()}
|
||||
showLabel={false}
|
||||
exceptionItemIndex={0}
|
||||
/>
|
||||
);
|
||||
|
||||
|
@ -378,6 +386,7 @@ describe('BuilderEntryItem', () => {
|
|||
setErrorsExist={jest.fn()}
|
||||
setWarningsExist={jest.fn()}
|
||||
showLabel={false}
|
||||
exceptionItemIndex={0}
|
||||
/>
|
||||
);
|
||||
|
||||
|
@ -418,6 +427,7 @@ describe('BuilderEntryItem', () => {
|
|||
setErrorsExist={jest.fn()}
|
||||
setWarningsExist={jest.fn()}
|
||||
showLabel
|
||||
exceptionItemIndex={0}
|
||||
/>
|
||||
);
|
||||
|
||||
|
@ -459,6 +469,7 @@ describe('BuilderEntryItem', () => {
|
|||
setErrorsExist={jest.fn()}
|
||||
setWarningsExist={jest.fn()}
|
||||
showLabel
|
||||
exceptionItemIndex={0}
|
||||
/>
|
||||
);
|
||||
|
||||
|
@ -499,6 +510,7 @@ describe('BuilderEntryItem', () => {
|
|||
setErrorsExist={jest.fn()}
|
||||
setWarningsExist={jest.fn()}
|
||||
showLabel={false}
|
||||
exceptionItemIndex={0}
|
||||
/>
|
||||
);
|
||||
|
||||
|
@ -542,6 +554,7 @@ describe('BuilderEntryItem', () => {
|
|||
setErrorsExist={jest.fn()}
|
||||
setWarningsExist={jest.fn()}
|
||||
showLabel={false}
|
||||
exceptionItemIndex={0}
|
||||
/>
|
||||
);
|
||||
|
||||
|
@ -585,6 +598,7 @@ describe('BuilderEntryItem', () => {
|
|||
setErrorsExist={jest.fn()}
|
||||
setWarningsExist={jest.fn()}
|
||||
showLabel={false}
|
||||
exceptionItemIndex={0}
|
||||
/>
|
||||
);
|
||||
|
||||
|
@ -628,6 +642,7 @@ describe('BuilderEntryItem', () => {
|
|||
setErrorsExist={jest.fn()}
|
||||
setWarningsExist={jest.fn()}
|
||||
showLabel={false}
|
||||
exceptionItemIndex={0}
|
||||
/>
|
||||
);
|
||||
|
||||
|
@ -662,6 +677,7 @@ describe('BuilderEntryItem', () => {
|
|||
setErrorsExist={jest.fn()}
|
||||
setWarningsExist={jest.fn()}
|
||||
showLabel={false}
|
||||
exceptionItemIndex={0}
|
||||
/>
|
||||
);
|
||||
|
||||
|
@ -721,6 +737,7 @@ describe('BuilderEntryItem', () => {
|
|||
setErrorsExist={jest.fn()}
|
||||
setWarningsExist={jest.fn()}
|
||||
showLabel={false}
|
||||
exceptionItemIndex={0}
|
||||
/>
|
||||
);
|
||||
|
||||
|
@ -764,6 +781,7 @@ describe('BuilderEntryItem', () => {
|
|||
setErrorsExist={jest.fn()}
|
||||
setWarningsExist={jest.fn()}
|
||||
showLabel={false}
|
||||
exceptionItemIndex={0}
|
||||
/>
|
||||
);
|
||||
|
||||
|
@ -805,6 +823,7 @@ describe('BuilderEntryItem', () => {
|
|||
setErrorsExist={jest.fn()}
|
||||
setWarningsExist={jest.fn()}
|
||||
showLabel={false}
|
||||
exceptionItemIndex={0}
|
||||
/>
|
||||
);
|
||||
|
||||
|
@ -846,6 +865,7 @@ describe('BuilderEntryItem', () => {
|
|||
setErrorsExist={jest.fn()}
|
||||
setWarningsExist={jest.fn()}
|
||||
showLabel={false}
|
||||
exceptionItemIndex={0}
|
||||
/>
|
||||
);
|
||||
|
||||
|
@ -887,6 +907,7 @@ describe('BuilderEntryItem', () => {
|
|||
setErrorsExist={jest.fn()}
|
||||
setWarningsExist={jest.fn()}
|
||||
showLabel={false}
|
||||
exceptionItemIndex={0}
|
||||
/>
|
||||
);
|
||||
|
||||
|
@ -928,6 +949,7 @@ describe('BuilderEntryItem', () => {
|
|||
setErrorsExist={jest.fn()}
|
||||
setWarningsExist={jest.fn()}
|
||||
showLabel={false}
|
||||
exceptionItemIndex={0}
|
||||
/>
|
||||
);
|
||||
|
||||
|
@ -975,6 +997,7 @@ describe('BuilderEntryItem', () => {
|
|||
setErrorsExist={jest.fn()}
|
||||
setWarningsExist={jest.fn()}
|
||||
showLabel={false}
|
||||
exceptionItemIndex={0}
|
||||
/>
|
||||
);
|
||||
|
||||
|
@ -1016,6 +1039,7 @@ describe('BuilderEntryItem', () => {
|
|||
setErrorsExist={mockSetErrorExists}
|
||||
setWarningsExist={jest.fn()}
|
||||
showLabel={false}
|
||||
exceptionItemIndex={0}
|
||||
/>
|
||||
);
|
||||
|
||||
|
@ -1056,6 +1080,7 @@ describe('BuilderEntryItem', () => {
|
|||
setErrorsExist={mockSetErrorExists}
|
||||
setWarningsExist={jest.fn()}
|
||||
showLabel={false}
|
||||
exceptionItemIndex={0}
|
||||
/>
|
||||
);
|
||||
|
||||
|
@ -1105,6 +1130,7 @@ describe('BuilderEntryItem', () => {
|
|||
setErrorsExist={jest.fn()}
|
||||
setWarningsExist={mockSetWarningsExists}
|
||||
showLabel={false}
|
||||
exceptionItemIndex={0}
|
||||
/>
|
||||
);
|
||||
|
||||
|
@ -1154,6 +1180,7 @@ describe('BuilderEntryItem', () => {
|
|||
setErrorsExist={jest.fn()}
|
||||
setWarningsExist={mockSetWarningsExists}
|
||||
showLabel={false}
|
||||
exceptionItemIndex={0}
|
||||
/>
|
||||
);
|
||||
|
||||
|
@ -1202,6 +1229,7 @@ describe('BuilderEntryItem', () => {
|
|||
osTypes={['windows']}
|
||||
showLabel={false}
|
||||
isDisabled={true}
|
||||
exceptionItemIndex={0}
|
||||
/>
|
||||
);
|
||||
expect(
|
||||
|
|
|
@ -81,6 +81,7 @@ export interface EntryItemProps {
|
|||
onlyShowListOperators?: boolean;
|
||||
setErrorsExist: (arg: EntryFieldError) => void;
|
||||
setWarningsExist: (arg: boolean) => void;
|
||||
exceptionItemIndex: number;
|
||||
isDisabled?: boolean;
|
||||
operatorsList?: OperatorOption[];
|
||||
allowCustomOptions?: boolean;
|
||||
|
@ -104,6 +105,7 @@ export const BuilderEntryItem: React.FC<EntryItemProps> = ({
|
|||
operatorsList,
|
||||
allowCustomOptions = false,
|
||||
getExtendedFields,
|
||||
exceptionItemIndex,
|
||||
}): JSX.Element => {
|
||||
const sPaddingSize = useEuiPaddingSize('s');
|
||||
|
||||
|
@ -209,6 +211,11 @@ export const BuilderEntryItem: React.FC<EntryItemProps> = ({
|
|||
}
|
||||
indexPattern={filteredIndexPatterns}
|
||||
selectedField={entry.field}
|
||||
aria-label={i18n.EXCEPTION_ITEM_ARIA_LABEL(
|
||||
i18n.FIELD,
|
||||
exceptionItemIndex,
|
||||
entry.entryIndex
|
||||
)}
|
||||
isClearable={false}
|
||||
isLoading={false}
|
||||
isDisabled={isDisabled || indexPattern == null}
|
||||
|
@ -301,6 +308,7 @@ export const BuilderEntryItem: React.FC<EntryItemProps> = ({
|
|||
[
|
||||
indexPattern,
|
||||
entry,
|
||||
exceptionItemIndex,
|
||||
isDisabled,
|
||||
handleFieldChange,
|
||||
allowCustomOptions,
|
||||
|
@ -340,6 +348,11 @@ export const BuilderEntryItem: React.FC<EntryItemProps> = ({
|
|||
isLoading={false}
|
||||
isClearable={false}
|
||||
onChange={handleOperatorChange}
|
||||
aria-label={i18n.EXCEPTION_ITEM_ARIA_LABEL(
|
||||
i18n.OPERATOR,
|
||||
exceptionItemIndex,
|
||||
entry.entryIndex
|
||||
)}
|
||||
data-test-subj="exceptionBuilderEntryOperator"
|
||||
/>
|
||||
);
|
||||
|
@ -380,6 +393,12 @@ export const BuilderEntryItem: React.FC<EntryItemProps> = ({
|
|||
|
||||
// eslint-disable-next-line complexity
|
||||
const getFieldValueComboBox = (type: OperatorTypeEnum, isFirst: boolean): JSX.Element => {
|
||||
const ariaLabel = i18n.EXCEPTION_ITEM_ARIA_LABEL(
|
||||
i18n.VALUE,
|
||||
exceptionItemIndex,
|
||||
entry.entryIndex
|
||||
);
|
||||
|
||||
switch (type) {
|
||||
case OperatorTypeEnum.MATCH:
|
||||
const value = typeof entry.value === 'string' ? entry.value : undefined;
|
||||
|
@ -398,6 +417,7 @@ export const BuilderEntryItem: React.FC<EntryItemProps> = ({
|
|||
onChange={handleFieldMatchValueChange}
|
||||
isRequired
|
||||
data-test-subj="exceptionBuilderEntryFieldMatch"
|
||||
aria-label={ariaLabel}
|
||||
/>
|
||||
);
|
||||
case OperatorTypeEnum.MATCH_ANY:
|
||||
|
@ -420,6 +440,7 @@ export const BuilderEntryItem: React.FC<EntryItemProps> = ({
|
|||
onError={handleError}
|
||||
onChange={handleFieldMatchAnyValueChange}
|
||||
isRequired
|
||||
aria-label={ariaLabel}
|
||||
data-test-subj="exceptionBuilderEntryFieldMatchAny"
|
||||
/>
|
||||
);
|
||||
|
@ -459,6 +480,7 @@ export const BuilderEntryItem: React.FC<EntryItemProps> = ({
|
|||
rowLabel={isFirst ? i18n.VALUE : undefined}
|
||||
selectedField={entry.correspondingKeywordField ?? entry.field}
|
||||
selectedValue={wildcardValue}
|
||||
aria-label={ariaLabel}
|
||||
/>
|
||||
);
|
||||
case OperatorTypeEnum.LIST:
|
||||
|
@ -476,6 +498,7 @@ export const BuilderEntryItem: React.FC<EntryItemProps> = ({
|
|||
onChange={handleFieldListValueChange}
|
||||
data-test-subj="exceptionBuilderEntryFieldList"
|
||||
allowLargeValueLists={allowLargeValueLists}
|
||||
aria-label={ariaLabel}
|
||||
/>
|
||||
);
|
||||
case OperatorTypeEnum.EXISTS:
|
||||
|
@ -484,6 +507,7 @@ export const BuilderEntryItem: React.FC<EntryItemProps> = ({
|
|||
rowLabel={isFirst ? i18n.VALUE : undefined}
|
||||
placeholder={getEmptyValue()}
|
||||
data-test-subj="exceptionBuilderEntryFieldExists"
|
||||
aria-label={ariaLabel}
|
||||
/>
|
||||
);
|
||||
default:
|
||||
|
|
|
@ -158,6 +158,7 @@ export const BuilderExceptionListItemComponent = React.memo<BuilderExceptionList
|
|||
operatorsList={operatorsList}
|
||||
allowCustomOptions={allowCustomOptions}
|
||||
getExtendedFields={getExtendedFields}
|
||||
exceptionItemIndex={exceptionItemIndex}
|
||||
/>
|
||||
</MyOverflowContainer>
|
||||
<BuilderEntryDeleteButtonComponent
|
||||
|
|
|
@ -19,6 +19,16 @@ export const VALUE = i18n.translate('xpack.lists.exceptions.builder.valueLabel',
|
|||
defaultMessage: 'Value',
|
||||
});
|
||||
|
||||
export const EXCEPTION_ITEM_ARIA_LABEL = (
|
||||
name: string,
|
||||
groupIndex: number,
|
||||
positionIndex: number
|
||||
): string =>
|
||||
i18n.translate('xpack.lists.exceptions.item.ariaLabel', {
|
||||
defaultMessage: '"{name}" in group {group}, position {position} ',
|
||||
values: { group: groupIndex + 1, name, position: positionIndex + 1 },
|
||||
});
|
||||
|
||||
export const EXCEPTION_FIELD_VALUE_PLACEHOLDER = i18n.translate(
|
||||
'xpack.lists.exceptions.builder.exceptionFieldValuePlaceholder',
|
||||
{
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue