Skip to content

Commit c0de50f

Browse files
use Slider component from grafana-ui (#13)
1 parent e1b84de commit c0de50f

File tree

10 files changed

+320
-598
lines changed

10 files changed

+320
-598
lines changed

package-lock.json

Lines changed: 295 additions & 406 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,10 @@
22
"author": "Grafana Labs",
33
"dependencies": {
44
"@emotion/css": "^11.13.5",
5-
"@grafana/data": "^12.0.1",
6-
"@grafana/runtime": "^12.0.1",
5+
"@grafana/data": "^12.3.0",
6+
"@grafana/runtime": "^12.3.0",
77
"@grafana/scenes": "^5.42.0",
8-
"@grafana/ui": "^12.0.1",
8+
"@grafana/ui": "^12.3.0",
99
"@tanstack/react-table": "^8.21.3",
1010
"@tanstack/react-virtual": "3.13.9",
1111
"@volkovlabs/components": "^4.6.0",
Lines changed: 0 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,33 +1,7 @@
1-
import { TEST_IDS } from 'constants/tests';
21
import React from 'react';
32

43
const actual = jest.requireActual('@volkovlabs/components');
54

6-
/**
7-
* Mock Slider
8-
*/
9-
const SliderMock: React.FC<any> = ({ onChange, value, onAfterChange }) => {
10-
return (
11-
<input
12-
type="range"
13-
onChange={(event) => {
14-
if (onChange) {
15-
onChange(Number(event.target.value));
16-
}
17-
}}
18-
onBlur={(event) => {
19-
if (onAfterChange) {
20-
onAfterChange(Number(event.target.value));
21-
}
22-
}}
23-
data-testid={TEST_IDS.sliderView.slider}
24-
value={value}
25-
/>
26-
);
27-
};
28-
29-
const Slider = jest.fn(SliderMock);
30-
315
/**
326
* Mock DatasourcePayloadEditor
337
*/
@@ -60,12 +34,10 @@ const useDatasourceRequest = jest.fn();
6034
*/
6135
beforeEach(() => {
6236
DatasourcePayloadEditor.mockImplementation(DatasourcePayloadEditorMock);
63-
Slider.mockImplementation(SliderMock);
6437
});
6538

6639
module.exports = {
6740
...actual,
68-
Slider,
6941
DatasourcePayloadEditor,
7042
useDatasourceRequest,
7143
};

src/components/GroupsEditor/GroupsEditor.tsx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -203,6 +203,7 @@ export const GroupsEditor: React.FC<Props> = ({ context: { options, data }, onCh
203203
/>
204204
</InlineField>
205205
<Button
206+
aria-label="Cancel rename"
206207
variant="secondary"
207208
fill="text"
208209
className={styles.actionButton}
@@ -234,6 +235,7 @@ export const GroupsEditor: React.FC<Props> = ({ context: { options, data }, onCh
234235
<>
235236
{editItem !== name && (
236237
<Button
238+
aria-label="Edit group name"
237239
icon="edit"
238240
variant="secondary"
239241
fill="text"
@@ -250,6 +252,7 @@ export const GroupsEditor: React.FC<Props> = ({ context: { options, data }, onCh
250252
/>
251253
)}
252254
<Button
255+
aria-label="Remove group"
253256
icon="trash-alt"
254257
variant="secondary"
255258
fill="text"

src/components/SliderView/SliderView.test.tsx

Lines changed: 7 additions & 154 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { act, fireEvent, render, screen } from '@testing-library/react';
1+
import { render, screen } from '@testing-library/react';
22
import { getJestSelectors } from '@volkovlabs/jest-selectors';
33
import React from 'react';
44

@@ -52,6 +52,7 @@ describe('SliderView', () => {
5252
const deviceVariable = {
5353
multi: true,
5454
includeAll: true,
55+
label: 'Device',
5556
type: VariableType.CUSTOM,
5657
current: {
5758
text: 'device2',
@@ -194,7 +195,7 @@ describe('SliderView', () => {
194195

195196
expect(selectors.field()).toBeInTheDocument();
196197
expect(selectors.field()).toHaveTextContent('Device');
197-
expect(selectors.slider()).toBeInTheDocument();
198+
expect(screen.getByLabelText('Use arrow keys to change the value')).toBeInTheDocument();
198199

199200
expect(selectors.root()).toHaveStyle('padding:20px');
200201
});
@@ -220,7 +221,7 @@ describe('SliderView', () => {
220221

221222
expect(selectors.field()).toBeInTheDocument();
222223
expect(selectors.field()).toHaveTextContent('Device');
223-
expect(selectors.slider()).toBeInTheDocument();
224+
expect(screen.getByLabelText('Use arrow keys to change the value')).toBeInTheDocument();
224225

225226
expect(selectors.root()).not.toHaveStyle('padding:20px');
226227
expect(selectors.root()).toHaveStyle('padding:0px');
@@ -251,7 +252,7 @@ describe('SliderView', () => {
251252

252253
expect(selectors.field()).toBeInTheDocument();
253254
expect(selectors.field()).toHaveTextContent('Device');
254-
expect(selectors.slider()).toBeInTheDocument();
255+
expect(screen.getByLabelText('Use arrow keys to change the value')).toBeInTheDocument();
255256
});
256257

257258
it('Should not display label', async () => {
@@ -273,156 +274,8 @@ describe('SliderView', () => {
273274

274275
expect(selectors.field()).toBeInTheDocument();
275276
expect(selectors.field()).toHaveTextContent('');
276-
expect(selectors.slider()).toBeInTheDocument();
277-
});
278-
});
279-
280-
describe('Update value', () => {
281-
const options = [
282-
{
283-
text: ALL_VALUE,
284-
value: ALL_VALUE_PARAMETER,
285-
selected: false,
286-
},
287-
{
288-
text: 'device1',
289-
value: 'device1',
290-
selected: true,
291-
},
292-
{
293-
text: 'device2',
294-
value: 'device2',
295-
selected: false,
296-
},
297-
{
298-
text: 'device3',
299-
value: 'device3',
300-
selected: false,
301-
},
302-
];
303-
304-
const deviceVariable = {
305-
multi: false,
306-
includeAll: true,
307-
type: VariableType.CUSTOM,
308-
current: {
309-
text: 'device1',
310-
},
311-
options: options,
312-
};
313-
314-
beforeEach(() => {
315-
jest.mocked(useRuntimeVariables).mockImplementationOnce(
316-
() =>
317-
({
318-
variable: deviceVariable,
319-
}) as any
320-
);
321-
});
322-
323-
it('Should update slider value without updating variable', async () => {
324-
const setValue = jest.fn();
325-
326-
jest.mocked(useSlider).mockReturnValueOnce({
327-
value: 1,
328-
min: 0,
329-
max: 10,
330-
variableValue: 'device1',
331-
setValue,
332-
text: 'Device 1',
333-
marks: {},
334-
});
335-
336-
render(
337-
getComponent({
338-
options: {
339-
variable: 'device',
340-
persistent: true,
341-
} as any,
342-
})
343-
);
344-
345-
expect(selectors.field()).toBeInTheDocument();
346-
expect(selectors.slider()).toBeInTheDocument();
347-
348-
await act(() => fireEvent.change(selectors.slider(), { target: { value: 3 } }));
349-
350-
expect(setValue).toHaveBeenCalled();
351-
expect(setValue).toHaveBeenCalledWith(3);
352-
353-
expect(updateVariableOptions).not.toHaveBeenCalled();
354-
});
355-
356-
it('Should update variable value on blur', async () => {
357-
const setValue = jest.fn();
358-
359-
jest.mocked(useSlider).mockReturnValueOnce({
360-
value: 1,
361-
min: 0,
362-
max: 10,
363-
variableValue: 'device1',
364-
setValue,
365-
text: 'Device 1',
366-
marks: {},
367-
});
368-
369-
render(
370-
getComponent({
371-
options: {
372-
variable: 'device',
373-
persistent: true,
374-
} as any,
375-
})
376-
);
377-
378-
expect(selectors.field()).toBeInTheDocument();
379-
expect(selectors.slider()).toBeInTheDocument();
380-
381-
await act(() => fireEvent.change(selectors.slider(), { target: { value: 3 } }));
382-
await act(() => fireEvent.blur(selectors.slider(), { target: { value: 3 } }));
383-
384-
expect(setValue).toHaveBeenCalled();
385-
expect(setValue).toHaveBeenCalledWith(3);
386-
387-
/**
388-
* Check if variable value updated
389-
*/
390-
expect(updateVariableOptions).toHaveBeenCalledWith(
391-
expect.objectContaining({
392-
value: options[3].value,
393-
previousValues: ['device1'],
394-
variable: deviceVariable,
395-
})
396-
);
397-
});
398-
399-
it('Should not update variable value if value not changed', async () => {
400-
const setValue = jest.fn();
401-
402-
jest.mocked(useSlider).mockReturnValueOnce({
403-
value: 1,
404-
min: 0,
405-
max: 10,
406-
variableValue: 'device1',
407-
setValue,
408-
text: 'Device 1',
409-
marks: {},
410-
});
411-
412-
render(
413-
getComponent({
414-
options: {
415-
variable: 'device',
416-
} as any,
417-
})
418-
);
419-
420-
expect(selectors.field()).toBeInTheDocument();
421-
expect(selectors.slider()).toBeInTheDocument();
422-
423-
await act(() => fireEvent.change(selectors.slider(), { target: { value: 1 } }));
424-
425-
expect(setValue).not.toHaveBeenCalled();
277+
expect(screen.queryByLabelText('Device')).not.toBeInTheDocument();
278+
expect(screen.getByLabelText('Use arrow keys to change the value')).toBeInTheDocument();
426279
});
427280
});
428281
});

src/components/SliderView/SliderView.tsx

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
11
import { css, cx } from '@emotion/css';
22
import { EventBus, PanelProps } from '@grafana/data';
3-
import { Alert, InlineField, useStyles2 } from '@grafana/ui';
4-
import { Slider } from '@volkovlabs/components';
5-
import React from 'react';
3+
import { Alert, InlineField, Slider, useStyles2 } from '@grafana/ui';
4+
import React, { useId } from 'react';
65

76
import { NO_VARIABLE_DEFAULT_MESSAGE, TEST_IDS } from '../../constants';
87
import { useRuntimeVariables, useSlider } from '../../hooks';
@@ -53,6 +52,7 @@ export const SliderView: React.FC<Props> = ({
5352
* Styles and Theme
5453
*/
5554
const styles = useStyles2(getStyles, slider.text, width);
55+
const sliderId = useId();
5656

5757
/**
5858
* No variable selected
@@ -102,12 +102,13 @@ export const SliderView: React.FC<Props> = ({
102102
label={showLabel && (variable.label || variable.name)}
103103
className={styles.field}
104104
grow
105+
htmlFor={sliderId}
105106
labelWidth={labelWidth}
106107
data-testid={TEST_IDS.sliderView.field}
107108
>
108109
<div className={styles.slider}>
109110
<Slider
110-
data-testid={TEST_IDS.sliderView.slider}
111+
inputId={sliderId}
111112
included={true}
112113
max={slider.max}
113114
min={slider.min}
@@ -128,7 +129,7 @@ export const SliderView: React.FC<Props> = ({
128129
}}
129130
marks={slider.marks}
130131
value={slider.value}
131-
inputWidth={0}
132+
showInput={false}
132133
/>
133134
</div>
134135
</InlineField>

src/components/Table/Filter.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,7 @@ export const Filter = <TTableData extends object>({ column, alwaysVisible }: Pro
111111
addonAfter={
112112
columnFilterValue ? (
113113
<Button
114+
aria-label="Clear filter value"
114115
variant="secondary"
115116
icon="times"
116117
onClick={() => column.setFilterValue('')}
@@ -134,6 +135,7 @@ export const Filter = <TTableData extends object>({ column, alwaysVisible }: Pro
134135
return (
135136
<>
136137
<Button
138+
aria-label="Toggle filter visibility"
137139
icon="filter"
138140
fill="text"
139141
onClick={onToggleVisibility}

src/components/Table/Table.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -291,7 +291,7 @@ export const Table = <TTableData extends TableItem>({
291291
className={styles.headerButton}
292292
variant={header.column.getIsSorted() ? 'primary' : 'secondary'}
293293
data-testid={TEST_IDS.table.buttonSort}
294-
title="Sort by status"
294+
aria-label="Sort by status"
295295
/>
296296
)}
297297
{header.column.getCanFilter() && (

src/hooks/useTable.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -340,6 +340,7 @@ export const useTable = ({
340340
)}
341341
{table.getCanSomeRowsExpand() && (
342342
<Button
343+
aria-label={table.getIsAllRowsExpanded() ? 'Collapse all' : 'Expand all'}
343344
className={styles.expandButton}
344345
onClick={table.getToggleAllRowsExpandedHandler()}
345346
variant="secondary"
@@ -427,6 +428,7 @@ export const useTable = ({
427428

428429
{row.getCanExpand() && (
429430
<Button
431+
aria-label={row.getIsExpanded() ? 'Collapse row' : 'Expand row'}
430432
className={styles.expandButton}
431433
onClick={row.getToggleExpandedHandler()}
432434
variant="secondary"

src/plugin.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"$schema": "https://raw.githubusercontent.com/grafana/grafana/main/docs/sources/developers/plugins/plugin.schema.json",
33
"dependencies": {
4-
"grafanaDependency": ">=11.5.0",
4+
"grafanaDependency": ">=12.3.0",
55
"plugins": []
66
},
77
"id": "volkovlabs-variable-panel",

0 commit comments

Comments
 (0)