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) {