mirror of
https://github.com/elastic/kibana.git
synced 2025-04-23 09:19:04 -04:00
[Console] Add a setting to disable the a11y overlay (#158844)
## Summary Fixes https://github.com/elastic/kibana/issues/16139 This PR adds a setting in Console that allows to disable the a11y overlay. The default will be set to `enabled` so that the default behaviour should not change. A user can disable the overlay in their browser and the setting is saved in local storage. So that other users are not affected by that change. The reason to allow disabling the overlay is that it can be flaky and sometimes it's displayed when not intended. The code relies on `querySelector` (see this [file](1b3f23829c/src/plugins/es_ui_shared/__packages_do_not_import__/ace/use_ui_ace_keyboard_mode.tsx (L25)
)) so I think that causes the flakiness and that is very difficult to test reliably. ### Screenshot #### A11y overlay (no changes) <img width="1483" alt="Screenshot 2023-06-01 at 16 34 23" src="d776625c
-92cd-4bd9-8e5e-2f672df351a4"> #### Settings modal with the new option to disable the a11y overlay <img width="474" alt="Screenshot 2023-06-01 at 16 29 02" src="8745c7a0
-62f4-41a9-9eff-ff8bebd4f767"> #### How to test 1. Start Kibana and navigate to the Console 2. Press ESC when textarea is focused and now autocomplete popup is displayed to see the a11y overlay 3. Open the Settings modal and disable the a11y overlay 4. Press ESC in the textarea again to see that no overlay is now displayed 5. Check that the value is persisted in the local storage Flaky test runner https://buildkite.com/elastic/kibana-flaky-test-suite-runner/builds/2346 ### Checklist - [x] Any text added follows [EUI's writing guidelines](https://elastic.github.io/eui/#/guidelines/writing), uses sentence case text and includes [i18n support](https://github.com/elastic/kibana/blob/main/packages/kbn-i18n/README.md) - [x] [Unit or functional tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html) were updated or added to match the most common scenarios
This commit is contained in:
parent
f5e79f7626
commit
3c8b26b53d
7 changed files with 120 additions and 7 deletions
|
@ -81,6 +81,9 @@ export const DevToolsSettingsModal = (props: DevToolsSettingsModalProps) => {
|
|||
const [isKeyboardShortcutsEnabled, setIsKeyboardShortcutsEnabled] = useState(
|
||||
props.settings.isKeyboardShortcutsEnabled
|
||||
);
|
||||
const [isAccessibilityOverlayEnabled, setIsAccessibilityOverlayEnabled] = useState(
|
||||
props.settings.isAccessibilityOverlayEnabled
|
||||
);
|
||||
|
||||
const autoCompleteCheckboxes = [
|
||||
{
|
||||
|
@ -142,6 +145,7 @@ export const DevToolsSettingsModal = (props: DevToolsSettingsModalProps) => {
|
|||
tripleQuotes,
|
||||
isHistoryEnabled,
|
||||
isKeyboardShortcutsEnabled,
|
||||
isAccessibilityOverlayEnabled,
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -162,6 +166,11 @@ export const DevToolsSettingsModal = (props: DevToolsSettingsModalProps) => {
|
|||
[props.editorInstance]
|
||||
);
|
||||
|
||||
const toggleAccessibilityOverlay = useCallback(
|
||||
(isEnabled: boolean) => setIsAccessibilityOverlayEnabled(isEnabled),
|
||||
[]
|
||||
);
|
||||
|
||||
const toggleSavingToHistory = useCallback(
|
||||
(isEnabled: boolean) => setIsHistoryEnabled(isEnabled),
|
||||
[]
|
||||
|
@ -320,6 +329,27 @@ export const DevToolsSettingsModal = (props: DevToolsSettingsModalProps) => {
|
|||
/>
|
||||
</EuiFormRow>
|
||||
|
||||
<EuiFormRow
|
||||
label={
|
||||
<FormattedMessage
|
||||
id="console.settingsPage.accessibilityOverlayLabel"
|
||||
defaultMessage="Accessibility overlay"
|
||||
/>
|
||||
}
|
||||
>
|
||||
<EuiSwitch
|
||||
data-test-subj="enableA11yOverlay"
|
||||
checked={isAccessibilityOverlayEnabled}
|
||||
label={
|
||||
<FormattedMessage
|
||||
defaultMessage="Enable accessibility overlay"
|
||||
id="console.settingsPage.enableAccessibilityOverlayLabel"
|
||||
/>
|
||||
}
|
||||
onChange={(e) => toggleAccessibilityOverlay(e.target.checked)}
|
||||
/>
|
||||
</EuiFormRow>
|
||||
|
||||
<EuiFormRow
|
||||
labelType="legend"
|
||||
label={
|
||||
|
|
|
@ -87,7 +87,7 @@ function EditorUI({ initialTextValue, setEditorInstance }: EditorProps) {
|
|||
const editorInstanceRef = useRef<senseEditor.SenseEditor | null>(null);
|
||||
|
||||
const [textArea, setTextArea] = useState<HTMLTextAreaElement | null>(null);
|
||||
useUIAceKeyboardMode(textArea);
|
||||
useUIAceKeyboardMode(textArea, settings.isAccessibilityOverlayEnabled);
|
||||
|
||||
const openDocumentation = useCallback(async () => {
|
||||
const documentation = await getDocumentation(editorInstanceRef.current!, docLinkVersion);
|
||||
|
|
|
@ -22,6 +22,7 @@ export const DEFAULT_SETTINGS = Object.freeze({
|
|||
}),
|
||||
isHistoryEnabled: true,
|
||||
isKeyboardShortcutsEnabled: true,
|
||||
isAccessibilityOverlayEnabled: true,
|
||||
});
|
||||
|
||||
export interface DevToolsSettings {
|
||||
|
@ -38,6 +39,7 @@ export interface DevToolsSettings {
|
|||
tripleQuotes: boolean;
|
||||
isHistoryEnabled: boolean;
|
||||
isKeyboardShortcutsEnabled: boolean;
|
||||
isAccessibilityOverlayEnabled: boolean;
|
||||
}
|
||||
|
||||
enum SettingKeys {
|
||||
|
@ -49,6 +51,7 @@ enum SettingKeys {
|
|||
POLL_INTERVAL = 'poll_interval',
|
||||
IS_HISTORY_ENABLED = 'is_history_enabled',
|
||||
IS_KEYBOARD_SHORTCUTS_ENABLED = 'is_keyboard_shortcuts_enabled',
|
||||
IS_ACCESSIBILITY_OVERLAY_ENABLED = 'is_accessibility_overlay_enabled',
|
||||
}
|
||||
|
||||
export class Settings {
|
||||
|
@ -141,6 +144,11 @@ export class Settings {
|
|||
return true;
|
||||
}
|
||||
|
||||
setIsAccessibilityOverlayEnabled(isEnabled: boolean) {
|
||||
this.storage.set(SettingKeys.IS_ACCESSIBILITY_OVERLAY_ENABLED, isEnabled);
|
||||
return true;
|
||||
}
|
||||
|
||||
getIsKeyboardShortcutsDisabled() {
|
||||
return this.storage.get(
|
||||
SettingKeys.IS_KEYBOARD_SHORTCUTS_ENABLED,
|
||||
|
@ -148,6 +156,13 @@ export class Settings {
|
|||
);
|
||||
}
|
||||
|
||||
getIsAccessibilityOverlayEnabled() {
|
||||
return this.storage.get(
|
||||
SettingKeys.IS_ACCESSIBILITY_OVERLAY_ENABLED,
|
||||
DEFAULT_SETTINGS.isAccessibilityOverlayEnabled
|
||||
);
|
||||
}
|
||||
|
||||
toJSON(): DevToolsSettings {
|
||||
return {
|
||||
autocomplete: this.getAutocomplete(),
|
||||
|
@ -158,6 +173,7 @@ export class Settings {
|
|||
pollInterval: this.getPollInterval(),
|
||||
isHistoryEnabled: Boolean(this.getIsHistoryEnabled()),
|
||||
isKeyboardShortcutsEnabled: Boolean(this.getIsKeyboardShortcutsDisabled()),
|
||||
isAccessibilityOverlayEnabled: Boolean(this.getIsAccessibilityOverlayEnabled()),
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -170,6 +186,7 @@ export class Settings {
|
|||
pollInterval,
|
||||
isHistoryEnabled,
|
||||
isKeyboardShortcutsEnabled,
|
||||
isAccessibilityOverlayEnabled,
|
||||
}: DevToolsSettings) {
|
||||
this.setFontSize(fontSize);
|
||||
this.setWrapMode(wrapMode);
|
||||
|
@ -179,6 +196,7 @@ export class Settings {
|
|||
this.setPollInterval(pollInterval);
|
||||
this.setIsHistoryEnabled(isHistoryEnabled);
|
||||
this.setIsKeyboardShortcutsEnabled(isKeyboardShortcutsEnabled);
|
||||
this.setIsAccessibilityOverlayEnabled(isAccessibilityOverlayEnabled);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -17,15 +17,19 @@ const OverlayText = () => (
|
|||
// in this case
|
||||
//
|
||||
<>
|
||||
<EuiText size="s">Press Enter to start editing.</EuiText>
|
||||
<EuiText size="s" data-test-subj="a11y-overlay">
|
||||
Press Enter to start editing.
|
||||
</EuiText>
|
||||
<EuiText size="s">When you’re done, press Escape to stop editing.</EuiText>
|
||||
</>
|
||||
);
|
||||
|
||||
export function useUIAceKeyboardMode(aceTextAreaElement: HTMLTextAreaElement | null) {
|
||||
export function useUIAceKeyboardMode(
|
||||
aceTextAreaElement: HTMLTextAreaElement | null,
|
||||
isAccessibilityOverlayEnabled: boolean = true
|
||||
) {
|
||||
const overlayMountNode = useRef<HTMLDivElement | null>(null);
|
||||
const autoCompleteVisibleRef = useRef<boolean>(false);
|
||||
|
||||
useEffect(() => {
|
||||
function onDismissOverlay(event: KeyboardEvent) {
|
||||
if (event.key === keys.ENTER) {
|
||||
|
@ -60,7 +64,7 @@ export function useUIAceKeyboardMode(aceTextAreaElement: HTMLTextAreaElement | n
|
|||
enableOverlay();
|
||||
}
|
||||
};
|
||||
if (aceTextAreaElement) {
|
||||
if (aceTextAreaElement && isAccessibilityOverlayEnabled) {
|
||||
// We don't control HTML elements inside of ace so we imperatively create an element
|
||||
// that acts as a container and insert it just before ace's textarea element
|
||||
// so that the overlay lives at the correct spot in the DOM hierarchy.
|
||||
|
@ -86,7 +90,7 @@ export function useUIAceKeyboardMode(aceTextAreaElement: HTMLTextAreaElement | n
|
|||
aceTextAreaElement.addEventListener('keydown', aceKeydownListener);
|
||||
}
|
||||
return () => {
|
||||
if (aceTextAreaElement) {
|
||||
if (aceTextAreaElement && isAccessibilityOverlayEnabled) {
|
||||
document.removeEventListener('keydown', documentKeyDownListener, { capture: true });
|
||||
aceTextAreaElement.removeEventListener('keydown', aceKeydownListener);
|
||||
const textAreaContainer = aceTextAreaElement.parentElement;
|
||||
|
@ -95,5 +99,5 @@ export function useUIAceKeyboardMode(aceTextAreaElement: HTMLTextAreaElement | n
|
|||
}
|
||||
}
|
||||
};
|
||||
}, [aceTextAreaElement]);
|
||||
}, [aceTextAreaElement, isAccessibilityOverlayEnabled]);
|
||||
}
|
||||
|
|
41
test/functional/apps/console/_settings.ts
Normal file
41
test/functional/apps/console/_settings.ts
Normal file
|
@ -0,0 +1,41 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0 and the Server Side Public License, v 1; you may not use this file except
|
||||
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import expect from '@kbn/expect';
|
||||
import { FtrProviderContext } from '../../ftr_provider_context';
|
||||
|
||||
export default function ({ getService, getPageObjects }: FtrProviderContext) {
|
||||
const log = getService('log');
|
||||
const PageObjects = getPageObjects(['common', 'console']);
|
||||
|
||||
describe('console settings', function testSettings() {
|
||||
this.tags('includeFirefox');
|
||||
before(async () => {
|
||||
log.debug('navigateTo console');
|
||||
await PageObjects.common.navigateToApp('console');
|
||||
// Ensure that the text area can be interacted with
|
||||
await PageObjects.console.closeHelpIfExists();
|
||||
await PageObjects.console.clearTextArea();
|
||||
});
|
||||
|
||||
it('displays the a11y overlay', async () => {
|
||||
await PageObjects.console.pressEscape();
|
||||
const isOverlayVisible = await PageObjects.console.isA11yOverlayVisible();
|
||||
expect(isOverlayVisible).to.be(true);
|
||||
});
|
||||
|
||||
it('disables the a11y overlay via settings', async () => {
|
||||
await PageObjects.console.openSettings();
|
||||
await PageObjects.console.toggleA11yOverlaySetting();
|
||||
|
||||
await PageObjects.console.pressEscape();
|
||||
const isOverlayVisible = await PageObjects.console.isA11yOverlayVisible();
|
||||
expect(isOverlayVisible).to.be(false);
|
||||
});
|
||||
});
|
||||
}
|
|
@ -26,6 +26,7 @@ export default function ({ getService, loadTestFile }) {
|
|||
loadTestFile(require.resolve('./_misc_console_behavior'));
|
||||
loadTestFile(require.resolve('./_context_menu'));
|
||||
loadTestFile(require.resolve('./_text_input'));
|
||||
loadTestFile(require.resolve('./_settings'));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
@ -49,6 +49,16 @@ export class ConsolePageObject extends FtrService {
|
|||
await this.testSubjects.click('consoleSettingsButton');
|
||||
}
|
||||
|
||||
public async toggleA11yOverlaySetting() {
|
||||
// while the settings form opens/loads this may fail, so retry for a while
|
||||
await this.retry.try(async () => {
|
||||
const toggle = await this.testSubjects.find('enableA11yOverlay');
|
||||
await toggle.click();
|
||||
});
|
||||
|
||||
await this.testSubjects.click('settings-save-button');
|
||||
}
|
||||
|
||||
public async openVariablesModal() {
|
||||
await this.testSubjects.click('consoleVariablesButton');
|
||||
}
|
||||
|
@ -191,6 +201,11 @@ export class ConsolePageObject extends FtrService {
|
|||
await textArea.pressKeys(Key.ENTER);
|
||||
}
|
||||
|
||||
public async pressEscape() {
|
||||
const textArea = await this.testSubjects.find('console-textarea');
|
||||
await textArea.pressKeys(Key.ESCAPE);
|
||||
}
|
||||
|
||||
public async clearTextArea() {
|
||||
await this.retry.waitForWithTimeout('text area is cleared', 20000, async () => {
|
||||
const textArea = await this.testSubjects.find('console-textarea');
|
||||
|
@ -403,6 +418,10 @@ export class ConsolePageObject extends FtrService {
|
|||
return await this.testSubjects.exists('consoleMenuAutoIndent');
|
||||
}
|
||||
|
||||
public async isA11yOverlayVisible() {
|
||||
return await this.testSubjects.exists('a11y-overlay');
|
||||
}
|
||||
|
||||
public async clickCopyAsCurlButton() {
|
||||
const button = await this.testSubjects.find('consoleMenuCopyAsCurl');
|
||||
await button.click();
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue