[8.17] [Lens] add an accessible label to range slider (#205308) (#208307)

# Backport

This will backport the following commits from `main` to `8.17`:
- [[Lens] add an accessible label to range slider
(#205308)](https://github.com/elastic/kibana/pull/205308)

<!--- Backport version: 9.4.3 -->

### Questions ?
Please refer to the [Backport tool
documentation](https://github.com/sqren/backport)

<!--BACKPORT [{"author":{"name":"Marta
Bondyra","email":"4283304+mbondyra@users.noreply.github.com"},"sourceCommit":{"committedDate":"2025-01-25T22:11:46Z","message":"[Lens]
add an accessible label to range slider (#205308)\n\n##
Summary\r\n\r\nFixes https://github.com/elastic/kibana/issues/182765
(with the solution\r\nsuggested by
@1Copenut)\r\n\r\n---------\r\n\r\nCo-authored-by: kibanamachine
<42973632+kibanamachine@users.noreply.github.com>","sha":"ed5728302a3063af325ea862f64c019bd67cbb5e","branchLabelMapping":{"^v9.0.0$":"main","^v8.18.0$":"8.x","^v(\\d+).(\\d+).\\d+$":"$1.$2"}},"sourcePullRequest":{"labels":["release_note:fix","Team:Visualizations","Feature:Lens","v9.0.0","backport:prev-major"],"title":"[Lens]
add an accessible label to range
slider","number":205308,"url":"https://github.com/elastic/kibana/pull/205308","mergeCommit":{"message":"[Lens]
add an accessible label to range slider (#205308)\n\n##
Summary\r\n\r\nFixes https://github.com/elastic/kibana/issues/182765
(with the solution\r\nsuggested by
@1Copenut)\r\n\r\n---------\r\n\r\nCo-authored-by: kibanamachine
<42973632+kibanamachine@users.noreply.github.com>","sha":"ed5728302a3063af325ea862f64c019bd67cbb5e"}},"sourceBranch":"main","suggestedTargetBranches":[],"targetPullRequestStates":[{"branch":"main","label":"v9.0.0","branchLabelMappingKey":"^v9.0.0$","isSourceBranch":true,"state":"MERGED","url":"https://github.com/elastic/kibana/pull/205308","number":205308,"mergeCommit":{"message":"[Lens]
add an accessible label to range slider (#205308)\n\n##
Summary\r\n\r\nFixes https://github.com/elastic/kibana/issues/182765
(with the solution\r\nsuggested by
@1Copenut)\r\n\r\n---------\r\n\r\nCo-authored-by: kibanamachine
<42973632+kibanamachine@users.noreply.github.com>","sha":"ed5728302a3063af325ea862f64c019bd67cbb5e"}}]}]
BACKPORT-->

Co-authored-by: Marta Bondyra <4283304+mbondyra@users.noreply.github.com>
This commit is contained in:
Kibana Machine 2025-01-26 10:57:07 +11:00 committed by GitHub
parent e20d5d2932
commit d8322265ef
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 105 additions and 15 deletions

View file

@ -10,13 +10,42 @@ import React from 'react';
import { I18nProvider } from '@kbn/i18n-react';
import { ControlSlider } from '.';
const values = [
{
label: '.001%',
value: 0.00001,
accessibleLabel: 'Point zero zero one percent, most performant',
},
{
label: '.01%',
value: 0.0001,
},
{
label: '.1%',
value: 0.001,
},
{
label: '1%',
value: 0.01,
},
{
label: '10%',
value: 0.1,
},
{
label: '100%',
value: 1,
accessibleLabel: 'One hundred percent, most accurate',
},
];
describe('Slider Control', () => {
it('should basically work', () => {
render(
<I18nProvider>
<ControlSlider
values={[0.1, 1]}
currentValue={0.1}
values={values}
currentValue={0.00001}
onChange={jest.fn()}
data-test-subj="test-id"
/>
@ -26,18 +55,35 @@ describe('Slider Control', () => {
expect(input.value).toBe('0'); // index 0 of the values array
});
it('should fallback to 1 when the provided value is not present within the values', () => {
it('should display accessible label when provided', () => {
render(
<I18nProvider>
<ControlSlider
values={[0.1, 0.5, 1]}
currentValue={2}
values={values}
currentValue={0.00001}
onChange={jest.fn()}
data-test-subj="test-id"
/>
</I18nProvider>
);
const input = screen.getByTestId('test-id') as HTMLInputElement;
expect(input.value).toBe('2'); // index 2 of the values array
expect(input.getAttribute('aria-valuetext')).toBe(
'0, (Point zero zero one percent, most performant)'
);
});
it('should fallback to 1 when the provided value is not present within the values', () => {
render(
<I18nProvider>
<ControlSlider
values={values}
currentValue={4}
onChange={jest.fn()}
data-test-subj="test-id"
/>
</I18nProvider>
);
const input = screen.getByTestId('test-id') as HTMLInputElement;
expect(input.value).toBe('5'); // index 5 of the values array
});
});

View file

@ -9,10 +9,11 @@ import { EuiFlexGroup, EuiFlexItem, EuiRange, EuiText, useEuiTheme } from '@elas
import React from 'react';
import { FormattedMessage } from '@kbn/i18n-react';
import { TooltipWrapper } from '@kbn/visualization-utils';
import { i18n } from '@kbn/i18n';
export interface ControlSliderProps {
/** Allowed values to show on the Control Slider */
values: number[];
values: Array<{ label: string; value: number; accessibleLabel?: string }>;
/** Current value set */
currentValue: number | undefined;
/** When set will show the control in a disabled state */
@ -34,8 +35,10 @@ export function ControlSlider({
'data-test-subj': dataTestSubj,
}: ControlSliderProps) {
const { euiTheme } = useEuiTheme();
const samplingIndex = values.findIndex((v) => v === currentValue);
const samplingIndex = values.findIndex((v) => v.value === currentValue);
const currentSamplingIndex = samplingIndex > -1 ? samplingIndex : values.length - 1;
return (
<TooltipWrapper
tooltipContent={disabledReason}
@ -58,11 +61,18 @@ export function ControlSlider({
<EuiFlexItem>
<EuiRange
data-test-subj={dataTestSubj}
aria-label={i18n.translate('randomSampling.ui.sliderControl.ariaLabel', {
defaultMessage: 'Sampling percentages',
})}
aria-describedby={i18n.translate('randomSampling.ui.sliderControl.ariaDescribedby', {
defaultMessage:
'Lower sampling percentages increases the performance, but lowers the accuracy. Lower sampling percentages are best for large datasets.',
})}
value={currentSamplingIndex}
disabled={disabled}
fullWidth
onChange={(e) => {
onChange(values[Number(e.currentTarget.value)]);
onChange(values[Number(e.currentTarget.value)].value);
}}
showInput={false}
showRange={false}
@ -70,10 +80,9 @@ export function ControlSlider({
step={1}
min={0}
max={values.length - 1}
ticks={values.map((v, i) => ({
// Remove the initial 0 from values with decimal digits: 0.001 => .001
label: `${v * 100}%`.slice(Number.isInteger(v * 100) ? 0 : 1),
value: i,
ticks={values.map((tick, index) => ({
...tick,
value: index,
}))}
/>
</EuiFlexItem>

View file

@ -14,6 +14,7 @@
"kbn_references": [
"@kbn/i18n-react",
"@kbn/visualization-utils",
"@kbn/i18n",
],
"exclude": [
"target/**/*",

View file

@ -17,7 +17,41 @@ import { IgnoreGlobalFilterRowControl } from '../../shared_components/ignore_glo
import { trackUiCounterEvents } from '../../lens_ui_telemetry';
import { ExperimentalBadge } from '../../shared_components';
const samplingValues = [0.00001, 0.0001, 0.001, 0.01, 0.1, 1];
const samplingValues = [
{
label: '.001%',
value: 0.00001,
accessibleLabel: i18n.translate(
'xpack.lens.randomSampling.ui.sliderControl.tickLabels.0.00001',
{
defaultMessage: 'Point zero zero one percent, most performant',
}
),
},
{
label: '.01%',
value: 0.0001,
},
{
label: '.1%',
value: 0.001,
},
{
label: '1%',
value: 0.01,
},
{
label: '10%',
value: 0.1,
},
{
label: '100%',
value: 1,
accessibleLabel: i18n.translate('xpack.lens.randomSampling.ui.sliderControl.tickLabels.1', {
defaultMessage: 'One hundred percent, most accurate',
}),
},
];
export function LayerSettingsPanel({
state,
@ -26,7 +60,7 @@ export function LayerSettingsPanel({
}: DatasourceLayerSettingsProps<FormBasedPrivateState>) {
const isSamplingValueDisabled = !isSamplingValueEnabled(state.layers[layerId]);
const currentValue = isSamplingValueDisabled
? samplingValues[samplingValues.length - 1]
? samplingValues[samplingValues.length - 1].value
: state.layers[layerId].sampling;
return (