Commit 4b3d3112 authored by Jose Vargas's avatar Jose Vargas

Make chart panels focusable via keyboard

This makes the chart panels inside the
monitoring dashboard focusable via the
tab key, this changes depending if the panel
has an empty state or if the panel contains a
chart with the actions dropdown
parent 2dfaf90c
...@@ -266,6 +266,9 @@ export default { ...@@ -266,6 +266,9 @@ export default {
this.$delete(this.allAlerts, alertPath); this.$delete(this.allAlerts, alertPath);
} }
}, },
openActionsDropdown() {
this.$refs.actionsDropdown.show();
},
}, },
panelTypes, panelTypes,
}; };
...@@ -277,6 +280,7 @@ export default { ...@@ -277,6 +280,7 @@ export default {
<h5 <h5
ref="graphTitle" ref="graphTitle"
class="prometheus-graph-title gl-font-lg font-weight-bold text-truncate append-right-8" class="prometheus-graph-title gl-font-lg font-weight-bold text-truncate append-right-8"
tabindex="0"
> >
{{ title }} {{ title }}
</h5> </h5>
...@@ -301,14 +305,20 @@ export default { ...@@ -301,14 +305,20 @@ export default {
ref="contextualMenu" ref="contextualMenu"
data-qa-selector="prometheus_graph_widgets" data-qa-selector="prometheus_graph_widgets"
> >
<div class="d-flex align-items-center"> <div
data-testid="actions-dropdown-container"
class="d-flex align-items-center"
@keyup.enter="openActionsDropdown"
>
<gl-dropdown <gl-dropdown
ref="actionsDropdown"
v-gl-tooltip v-gl-tooltip
toggle-class="btn btn-transparent border-0" toggle-class="btn btn-transparent border-0"
data-qa-selector="prometheus_widgets_dropdown" data-qa-selector="prometheus_widgets_dropdown"
right right
no-caret no-caret
:title="__('More actions')" :title="__('More actions')"
tabindex="0"
> >
<template slot="button-content"> <template slot="button-content">
<gl-icon name="ellipsis_v" class="text-secondary" /> <gl-icon name="ellipsis_v" class="text-secondary" />
......
...@@ -52,10 +52,17 @@ export default { ...@@ -52,10 +52,17 @@ export default {
</script> </script>
<template> <template>
<div v-if="showPanels" ref="graph-group" class="card prometheus-panel"> <div v-if="showPanels" ref="graph-group" class="card prometheus-panel" tabindex="0">
<div class="card-header d-flex align-items-center"> <div class="card-header d-flex align-items-center">
<h4 class="flex-grow-1">{{ name }}</h4> <h4 class="flex-grow-1">{{ name }}</h4>
<a role="button" class="js-graph-group-toggle" @click="collapse"> <a
data-testid="group-toggle-button"
role="button"
class="js-graph-group-toggle gl-text-gray-900"
tabindex="0"
@click="collapse"
@keyup.enter="collapse"
>
<icon :size="16" :aria-label="__('Toggle collapse')" :name="caretIcon" /> <icon :size="16" :aria-label="__('Toggle collapse')" :name="caretIcon" />
</a> </a>
</div> </div>
......
---
title: Make chart panels focusable via keyboard
merge_request: 28603
author:
type: added
...@@ -56,6 +56,9 @@ describe('Dashboard Panel', () => { ...@@ -56,6 +56,9 @@ describe('Dashboard Panel', () => {
const findTimeChart = () => wrapper.find({ ref: 'timeSeriesChart' }); const findTimeChart = () => wrapper.find({ ref: 'timeSeriesChart' });
const findTitle = () => wrapper.find({ ref: 'graphTitle' }); const findTitle = () => wrapper.find({ ref: 'graphTitle' });
const findContextualMenu = () => wrapper.find({ ref: 'contextualMenu' }); const findContextualMenu = () => wrapper.find({ ref: 'contextualMenu' });
const findActionsDropdown = () => wrapper.find({ ref: 'actionsDropdown' });
const findActionsDropdownContainer = () =>
wrapper.find('[data-testid="actions-dropdown-container"]');
const createWrapper = (props, options) => { const createWrapper = (props, options) => {
wrapper = shallowMount(DashboardPanel, { wrapper = shallowMount(DashboardPanel, {
...@@ -126,6 +129,10 @@ describe('Dashboard Panel', () => { ...@@ -126,6 +129,10 @@ describe('Dashboard Panel', () => {
expect(wrapper.find(MonitorEmptyChart).exists()).toBe(true); expect(wrapper.find(MonitorEmptyChart).exists()).toBe(true);
expect(wrapper.find(MonitorEmptyChart).isVueInstance()).toBe(true); expect(wrapper.find(MonitorEmptyChart).isVueInstance()).toBe(true);
}); });
it('does not contain a tabindex attribute', () => {
expect(wrapper.find(MonitorEmptyChart).contains('[tabindex]')).toBe(false);
});
}); });
describe('When graphData is null', () => { describe('When graphData is null', () => {
...@@ -194,6 +201,21 @@ describe('Dashboard Panel', () => { ...@@ -194,6 +201,21 @@ describe('Dashboard Panel', () => {
}); });
}); });
it('should set a tabindex for the actions dropdown', () => {
const actionsDropdown = findActionsDropdown();
expect(actionsDropdown.contains('[tabindex]')).toBe(true);
});
it('should open the actions dropdown when enter is pressed', () => {
const openDropdownSpy = jest.spyOn(wrapper.vm, 'openActionsDropdown').mockImplementation();
const container = findActionsDropdownContainer();
container.trigger('keyup.enter');
expect(openDropdownSpy).toHaveBeenCalled();
});
it('includes a default group id', () => { it('includes a default group id', () => {
expect(wrapper.vm.groupId).toBe('dashboard-panel'); expect(wrapper.vm.groupId).toBe('dashboard-panel');
}); });
......
...@@ -8,6 +8,7 @@ describe('Graph group component', () => { ...@@ -8,6 +8,7 @@ describe('Graph group component', () => {
const findGroup = () => wrapper.find({ ref: 'graph-group' }); const findGroup = () => wrapper.find({ ref: 'graph-group' });
const findContent = () => wrapper.find({ ref: 'graph-group-content' }); const findContent = () => wrapper.find({ ref: 'graph-group-content' });
const findCaretIcon = () => wrapper.find(Icon); const findCaretIcon = () => wrapper.find(Icon);
const findToggleButton = () => wrapper.find('[data-testid="group-toggle-button"]');
const createComponent = propsData => { const createComponent = propsData => {
wrapper = shallowMount(GraphGroup, { wrapper = shallowMount(GraphGroup, {
...@@ -41,6 +42,16 @@ describe('Graph group component', () => { ...@@ -41,6 +42,16 @@ describe('Graph group component', () => {
}); });
}); });
it('should contain a tabindex', () => {
expect(findGroup().contains('[tabindex]')).toBe(true);
});
it('should contain a tab index for the collapse button', () => {
const groupToggle = wrapper.find('.js-graph-group-toggle');
expect(groupToggle.contains('[tabindex]')).toBe(true);
});
it('should show the open the group when collapseGroup is set to true', () => { it('should show the open the group when collapseGroup is set to true', () => {
wrapper.setProps({ wrapper.setProps({
collapseGroup: true, collapseGroup: true,
...@@ -69,6 +80,15 @@ describe('Graph group component', () => { ...@@ -69,6 +80,15 @@ describe('Graph group component', () => {
expect(wrapper.vm.caretIcon).toBe('angle-down'); expect(wrapper.vm.caretIcon).toBe('angle-down');
}); });
it('should call the collapse function when the button listen to a keyup enter trigger', () => {
const collapseSpy = jest.spyOn(wrapper.vm, 'collapse');
const button = findToggleButton();
button.trigger('keyup.enter');
expect(collapseSpy).toHaveBeenCalled();
});
}); });
describe('When groups can not be collapsed', () => { describe('When groups can not be collapsed', () => {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment