From 774385156c1ff4d3588bb631ceb07f50777cce2d Mon Sep 17 00:00:00 2001 From: Stratoula Kalafateli Date: Wed, 29 Nov 2023 15:33:38 +0200 Subject: [PATCH] [ES|QL] Adds submit feedback link (#171865) ## Summary Closes https://github.com/elastic/kibana/issues/170095 Displays a submit feedback button to the editor **Discover mode** image **Inline editing mode** image ### Checklist Delete any items that are not applicable to this PR. - [ ] 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) - [ ] [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 - [ ] Any UI touched in this PR is usable by keyboard only (learn more about [keyboard accessibility](https://webaim.org/techniques/keyboard/)) - [ ] Any UI touched in this PR does not create any new axe failures (run axe in browser: [FF](https://addons.mozilla.org/en-US/firefox/addon/axe-devtools/), [Chrome](https://chrome.google.com/webstore/detail/axe-web-accessibility-tes/lhdoppojpmngadmnindnejefpokejbdd?hl=en-US)) - [ ] This renders correctly on smaller devices using a responsive layout. (You can test this [in your browser](https://www.browserstack.com/guide/responsive-testing-on-local-server)) - [ ] This was checked for [cross-browser compatibility](https://www.elastic.co/support/matrix#matrix_browsers) --- .../src/editor_footer.tsx | 179 +++++++++++------- .../src/text_based_languages_editor.test.tsx | 129 ++++++------- .../src/text_based_languages_editor.tsx | 2 +- 3 files changed, 171 insertions(+), 139 deletions(-) diff --git a/packages/kbn-text-based-editor/src/editor_footer.tsx b/packages/kbn-text-based-editor/src/editor_footer.tsx index d31f731821bb3..6bc663713a8d0 100644 --- a/packages/kbn-text-based-editor/src/editor_footer.tsx +++ b/packages/kbn-text-based-editor/src/editor_footer.tsx @@ -21,6 +21,7 @@ import { EuiDescriptionListDescription, EuiButton, useEuiTheme, + EuiLink, } from '@elastic/eui'; import { Interpolation, Theme, css } from '@emotion/react'; import { css as classNameCss } from '@emotion/css'; @@ -29,6 +30,7 @@ import type { MonacoError } from './helpers'; const isMac = navigator.platform.toLowerCase().indexOf('mac') >= 0; const COMMAND_KEY = isMac ? '⌘' : '^'; +const FEEDBACK_LINK = 'https://ela.st/esql-feedback'; const getConstsByType = (type: 'error' | 'warning', count: number) => { if (type === 'error') { @@ -56,6 +58,37 @@ const getConstsByType = (type: 'error' | 'warning', count: number) => { } }; +export function SubmitFeedbackComponent({ isSpaceReduced }: { isSpaceReduced?: boolean }) { + const { euiTheme } = useEuiTheme(); + return ( + <> + + + + + + {isSpaceReduced + ? i18n.translate('textBasedEditor.query.textBasedLanguagesEditor.feedback', { + defaultMessage: 'Feedback', + }) + : i18n.translate('textBasedEditor.query.textBasedLanguagesEditor.submitFeedback', { + defaultMessage: 'Submit feedback', + })} + + + + ); +} + export function ErrorsWarningsPopover({ isPopoverOpen, items, @@ -198,31 +231,34 @@ export const EditorFooter = memo(function EditorFooter({

- - - - -

- {isSpaceReduced - ? '@timestamp' - : detectTimestamp - ? i18n.translate( - 'textBasedEditor.query.textBasedLanguagesEditor.timestampDetected', - { - defaultMessage: '@timestamp found', - } - ) - : i18n.translate( - 'textBasedEditor.query.textBasedLanguagesEditor.timestampNotDetected', - { - defaultMessage: '@timestamp not found', - } - )} -

-
-
-
-
+ {/* If there is no space and no @timestamp detected hide the information */} + {(detectTimestamp || !isSpaceReduced) && ( + + + + +

+ {isSpaceReduced + ? '@timestamp' + : detectTimestamp + ? i18n.translate( + 'textBasedEditor.query.textBasedLanguagesEditor.timestampDetected', + { + defaultMessage: '@timestamp found', + } + ) + : i18n.translate( + 'textBasedEditor.query.textBasedLanguagesEditor.timestampNotDetected', + { + defaultMessage: '@timestamp not found', + } + )} +

+
+
+
+
+ )} {errors && errors.length > 0 && ( +

@@ -269,51 +306,61 @@ export const EditorFooter = memo(function EditorFooter({ )} {Boolean(editorIsInline) && ( - - - - - {isSpaceReduced - ? i18n.translate('textBasedEditor.query.textBasedLanguagesEditor.run', { - defaultMessage: 'Run', - }) - : i18n.translate('textBasedEditor.query.textBasedLanguagesEditor.runQuery', { - defaultMessage: 'Run query', - })} - + <> + + + - - {COMMAND_KEY}⏎ - + + + {isSpaceReduced + ? i18n.translate('textBasedEditor.query.textBasedLanguagesEditor.run', { + defaultMessage: 'Run', + }) + : i18n.translate( + 'textBasedEditor.query.textBasedLanguagesEditor.runQuery', + { + defaultMessage: 'Run query', + } + )} + + + + {COMMAND_KEY}⏎ + + + + - - + + )} ); diff --git a/packages/kbn-text-based-editor/src/text_based_languages_editor.test.tsx b/packages/kbn-text-based-editor/src/text_based_languages_editor.test.tsx index 173c023f8b619..0f9ed5c6cb9c5 100644 --- a/packages/kbn-text-based-editor/src/text_based_languages_editor.test.tsx +++ b/packages/kbn-text-based-editor/src/text_based_languages_editor.test.tsx @@ -69,19 +69,15 @@ describe('TextBasedLanguagesEditor', () => { }; }); it('should render the editor component', async () => { - await act(async () => { - const component = mount(renderTextBasedLanguagesEditorComponent({ ...props })); - expect(component.find('[data-test-subj="TextBasedLangEditor"]').length).not.toBe(0); - }); + const component = mount(renderTextBasedLanguagesEditorComponent({ ...props })); + expect(component.find('[data-test-subj="TextBasedLangEditor"]').length).not.toBe(0); }); it('should render the lines badge for the inline mode by default', async () => { - await act(async () => { - const component = mount(renderTextBasedLanguagesEditorComponent({ ...props })); - expect( - component.find('[data-test-subj="TextBasedLangEditor-inline-lines-badge"]').length - ).not.toBe(0); - }); + const component = mount(renderTextBasedLanguagesEditorComponent({ ...props })); + expect( + component.find('[data-test-subj="TextBasedLangEditor-inline-lines-badge"]').length + ).not.toBe(0); }); it('should render the date info with no @timestamp found', async () => { @@ -89,12 +85,21 @@ describe('TextBasedLanguagesEditor', () => { ...props, isCodeEditorExpanded: true, }; - await act(async () => { - const component = mount(renderTextBasedLanguagesEditorComponent({ ...newProps })); - expect( - component.find('[data-test-subj="TextBasedLangEditor-date-info"]').at(0).text() - ).toStrictEqual('@timestamp not found'); - }); + const component = mount(renderTextBasedLanguagesEditorComponent({ ...newProps })); + expect( + component.find('[data-test-subj="TextBasedLangEditor-date-info"]').at(0).text() + ).toStrictEqual('@timestamp not found'); + }); + + it('should render the feedback link', async () => { + const newProps = { + ...props, + isCodeEditorExpanded: true, + }; + const component = mount(renderTextBasedLanguagesEditorComponent({ ...newProps })); + expect(component.find('[data-test-subj="TextBasedLangEditor-feedback-link"]').length).not.toBe( + 0 + ); }); it('should render the date info with @timestamp found if detectTimestamp is true', async () => { @@ -103,12 +108,10 @@ describe('TextBasedLanguagesEditor', () => { isCodeEditorExpanded: true, detectTimestamp: true, }; - await act(async () => { - const component = mount(renderTextBasedLanguagesEditorComponent({ ...newProps })); - expect( - component.find('[data-test-subj="TextBasedLangEditor-date-info"]').at(0).text() - ).toStrictEqual('@timestamp found'); - }); + const component = mount(renderTextBasedLanguagesEditorComponent({ ...newProps })); + expect( + component.find('[data-test-subj="TextBasedLangEditor-date-info"]').at(0).text() + ).toStrictEqual('@timestamp found'); }); it('should render the errors badge for the inline mode by default if errors are provides', async () => { @@ -116,12 +119,10 @@ describe('TextBasedLanguagesEditor', () => { ...props, errors: [new Error('error1')], }; - await act(async () => { - const component = mount(renderTextBasedLanguagesEditorComponent({ ...newProps })); - expect( - component.find('[data-test-subj="TextBasedLangEditor-inline-errors-badge"]').length - ).not.toBe(0); - }); + const component = mount(renderTextBasedLanguagesEditorComponent({ ...newProps })); + expect( + component.find('[data-test-subj="TextBasedLangEditor-inline-errors-badge"]').length + ).not.toBe(0); }); it('should render the warnings badge for the inline mode by default if warning are provides', async () => { @@ -129,12 +130,10 @@ describe('TextBasedLanguagesEditor', () => { ...props, warning: 'Line 1: 20: Warning', }; - await act(async () => { - const component = mount(renderTextBasedLanguagesEditorComponent({ ...newProps })); - expect( - component.find('[data-test-subj="TextBasedLangEditor-inline-warning-badge"]').length - ).not.toBe(0); - }); + const component = mount(renderTextBasedLanguagesEditorComponent({ ...newProps })); + expect( + component.find('[data-test-subj="TextBasedLangEditor-inline-warning-badge"]').length + ).not.toBe(0); }); it('should render the correct buttons for the inline code editor mode', async () => { @@ -156,11 +155,9 @@ describe('TextBasedLanguagesEditor', () => { ...props, expandCodeEditor: expandCodeEditorSpy, }; - await act(async () => { - const component = mount(renderTextBasedLanguagesEditorComponent({ ...newProps })); - findTestSubject(component, 'TextBasedLangEditor-expand').simulate('click'); - expect(expandCodeEditorSpy).toHaveBeenCalled(); - }); + const component = mount(renderTextBasedLanguagesEditorComponent({ ...newProps })); + findTestSubject(component, 'TextBasedLangEditor-expand').simulate('click'); + expect(expandCodeEditorSpy).toHaveBeenCalled(); }); it('should render the correct buttons for the expanded code editor mode', async () => { @@ -211,11 +208,9 @@ describe('TextBasedLanguagesEditor', () => { isCodeEditorExpanded: true, expandCodeEditor: expandCodeEditorSpy, }; - await act(async () => { - const component = mount(renderTextBasedLanguagesEditorComponent({ ...newProps })); - findTestSubject(component, 'TextBasedLangEditor-minimize').simulate('click'); - expect(expandCodeEditorSpy).toHaveBeenCalled(); - }); + const component = mount(renderTextBasedLanguagesEditorComponent({ ...newProps })); + findTestSubject(component, 'TextBasedLangEditor-minimize').simulate('click'); + expect(expandCodeEditorSpy).toHaveBeenCalled(); }); it('should render the resize for the expanded code editor mode', async () => { @@ -223,10 +218,8 @@ describe('TextBasedLanguagesEditor', () => { ...props, isCodeEditorExpanded: true, }; - await act(async () => { - const component = mount(renderTextBasedLanguagesEditorComponent({ ...newProps })); - expect(component.find('[data-test-subj="TextBasedLangEditor-resize"]').length).not.toBe(0); - }); + const component = mount(renderTextBasedLanguagesEditorComponent({ ...newProps })); + expect(component.find('[data-test-subj="TextBasedLangEditor-resize"]').length).not.toBe(0); }); it('should render the footer for the expanded code editor mode', async () => { @@ -234,13 +227,11 @@ describe('TextBasedLanguagesEditor', () => { ...props, isCodeEditorExpanded: true, }; - await act(async () => { - const component = mount(renderTextBasedLanguagesEditorComponent({ ...newProps })); - expect(component.find('[data-test-subj="TextBasedLangEditor-footer"]').length).not.toBe(0); - expect( - component.find('[data-test-subj="TextBasedLangEditor-footer-lines"]').at(0).text() - ).toBe('1 line'); - }); + const component = mount(renderTextBasedLanguagesEditorComponent({ ...newProps })); + expect(component.find('[data-test-subj="TextBasedLangEditor-footer"]').length).not.toBe(0); + expect(component.find('[data-test-subj="TextBasedLangEditor-footer-lines"]').at(0).text()).toBe( + '1 line' + ); }); it('should render the run query text', async () => { @@ -248,10 +239,8 @@ describe('TextBasedLanguagesEditor', () => { ...props, isCodeEditorExpanded: true, }; - await act(async () => { - const component = mount(renderTextBasedLanguagesEditorComponent({ ...newProps })); - expect(component.find('[data-test-subj="TextBasedLangEditor-run-query"]').length).not.toBe(0); - }); + const component = mount(renderTextBasedLanguagesEditorComponent({ ...newProps })); + expect(component.find('[data-test-subj="TextBasedLangEditor-run-query"]').length).not.toBe(0); }); it('should not render the run query text if the hideRunQueryText prop is set to true', async () => { @@ -260,10 +249,8 @@ describe('TextBasedLanguagesEditor', () => { isCodeEditorExpanded: true, hideRunQueryText: true, }; - await act(async () => { - const component = mount(renderTextBasedLanguagesEditorComponent({ ...newProps })); - expect(component.find('[data-test-subj="TextBasedLangEditor-run-query"]').length).toBe(0); - }); + const component = mount(renderTextBasedLanguagesEditorComponent({ ...newProps })); + expect(component.find('[data-test-subj="TextBasedLangEditor-run-query"]').length).toBe(0); }); it('should render correctly if editorIsInline prop is set to true', async () => { @@ -275,14 +262,12 @@ describe('TextBasedLanguagesEditor', () => { editorIsInline: true, onTextLangQuerySubmit, }; - await act(async () => { - const component = mount(renderTextBasedLanguagesEditorComponent({ ...newProps })); - expect(component.find('[data-test-subj="TextBasedLangEditor-run-query"]').length).toBe(0); - expect( - component.find('[data-test-subj="TextBasedLangEditor-run-query-button"]').length - ).not.toBe(1); - findTestSubject(component, 'TextBasedLangEditor-run-query-button').simulate('click'); - expect(onTextLangQuerySubmit).toHaveBeenCalled(); - }); + const component = mount(renderTextBasedLanguagesEditorComponent({ ...newProps })); + expect(component.find('[data-test-subj="TextBasedLangEditor-run-query"]').length).toBe(0); + expect( + component.find('[data-test-subj="TextBasedLangEditor-run-query-button"]').length + ).not.toBe(1); + findTestSubject(component, 'TextBasedLangEditor-run-query-button').simulate('click'); + expect(onTextLangQuerySubmit).toHaveBeenCalled(); }); }); diff --git a/packages/kbn-text-based-editor/src/text_based_languages_editor.tsx b/packages/kbn-text-based-editor/src/text_based_languages_editor.tsx index 9a5eae37ed097..9d175ef86ecf0 100644 --- a/packages/kbn-text-based-editor/src/text_based_languages_editor.tsx +++ b/packages/kbn-text-based-editor/src/text_based_languages_editor.tsx @@ -119,7 +119,7 @@ const KEYCODE_ARROW_UP = 38; const KEYCODE_ARROW_DOWN = 40; // for editor width smaller than this value we want to start hiding some text -const BREAKPOINT_WIDTH = 410; +const BREAKPOINT_WIDTH = 540; const languageId = (language: string) => { switch (language) {