mirror of
https://github.com/elastic/kibana.git
synced 2025-04-23 17:28:26 -04:00
[Console] Fix small UX bugs (#193887)
This commit is contained in:
parent
89f64384ef
commit
8af23349e1
7 changed files with 153 additions and 109 deletions
|
@ -7,17 +7,10 @@
|
|||
* License v3.0 only", or the "Server Side Public License, v 1".
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import React, { useMemo } from 'react';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import {
|
||||
EuiPopover,
|
||||
EuiTitle,
|
||||
EuiText,
|
||||
EuiFlexGroup,
|
||||
EuiFlexItem,
|
||||
EuiButtonIcon,
|
||||
EuiSpacer,
|
||||
} from '@elastic/eui';
|
||||
import { EuiPopover, EuiTitle, EuiText, EuiPanel, EuiSpacer, EuiListGroup } from '@elastic/eui';
|
||||
import { css } from '@emotion/react';
|
||||
import { useServicesContext } from '../contexts';
|
||||
|
||||
interface HelpPopoverProps {
|
||||
|
@ -27,9 +20,81 @@ interface HelpPopoverProps {
|
|||
resetTour: () => void;
|
||||
}
|
||||
|
||||
const styles = {
|
||||
// Hide the external svg icon for the link given that we have a custom icon for it.
|
||||
// Also remove the the hover effect on the action icon since it's a bit distracting.
|
||||
listItem: css`
|
||||
.euiListGroupItem__button {
|
||||
> svg {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
.euiButtonIcon:hover {
|
||||
background: transparent;
|
||||
}
|
||||
`,
|
||||
};
|
||||
|
||||
export const HelpPopover = ({ button, isOpen, closePopover, resetTour }: HelpPopoverProps) => {
|
||||
const { docLinks } = useServicesContext();
|
||||
|
||||
const listItems = useMemo(
|
||||
() => [
|
||||
{
|
||||
label: i18n.translate('console.helpPopover.aboutConsoleLabel', {
|
||||
defaultMessage: 'About Console',
|
||||
}),
|
||||
href: docLinks.console.guide,
|
||||
target: '_blank',
|
||||
css: styles.listItem,
|
||||
extraAction: {
|
||||
iconType: 'popout',
|
||||
href: docLinks.console.guide,
|
||||
target: '_blank',
|
||||
alwaysShow: true,
|
||||
'aria-label': i18n.translate('console.helpPopover.aboutConsoleButtonAriaLabel', {
|
||||
defaultMessage: 'About Console link',
|
||||
}),
|
||||
},
|
||||
},
|
||||
{
|
||||
label: i18n.translate('console.helpPopover.aboutQueryDSLLabel', {
|
||||
defaultMessage: 'About Query DSL',
|
||||
}),
|
||||
href: docLinks.query.queryDsl,
|
||||
target: '_blank',
|
||||
css: styles.listItem,
|
||||
extraAction: {
|
||||
iconType: 'popout',
|
||||
href: docLinks.query.queryDsl,
|
||||
target: '_blank',
|
||||
alwaysShow: true,
|
||||
'aria-label': i18n.translate('console.helpPopover.aboutQueryDSLButtonAriaLabel', {
|
||||
defaultMessage: 'About QueryDSL link',
|
||||
}),
|
||||
},
|
||||
},
|
||||
{
|
||||
label: i18n.translate('console.helpPopover.rerunTourLabel', {
|
||||
defaultMessage: 'Re-run feature tour',
|
||||
}),
|
||||
css: styles.listItem,
|
||||
onClick: resetTour,
|
||||
extraAction: {
|
||||
iconType: 'refresh',
|
||||
alwaysShow: true,
|
||||
onClick: resetTour,
|
||||
'data-test-subj': 'consoleRerunTourButton',
|
||||
'aria-label': i18n.translate('console.helpPopover.rerunTourButtonAriaLabel', {
|
||||
defaultMessage: 'Re-run feature tour button',
|
||||
}),
|
||||
},
|
||||
},
|
||||
],
|
||||
[docLinks, resetTour]
|
||||
);
|
||||
|
||||
return (
|
||||
<EuiPopover
|
||||
button={button}
|
||||
|
@ -38,99 +103,31 @@ export const HelpPopover = ({ button, isOpen, closePopover, resetTour }: HelpPop
|
|||
anchorPosition="downRight"
|
||||
buffer={4}
|
||||
ownFocus={false}
|
||||
panelPaddingSize="none"
|
||||
data-test-subj="consoleHelpPopover"
|
||||
>
|
||||
<EuiTitle size="xs">
|
||||
<h4>
|
||||
{i18n.translate('console.helpPopover.title', {
|
||||
defaultMessage: 'Elastic Console',
|
||||
})}
|
||||
</h4>
|
||||
</EuiTitle>
|
||||
<EuiPanel paddingSize="m" hasShadow={false} hasBorder={false}>
|
||||
<EuiTitle size="xs">
|
||||
<h4>
|
||||
{i18n.translate('console.helpPopover.title', {
|
||||
defaultMessage: 'Elastic Console',
|
||||
})}
|
||||
</h4>
|
||||
</EuiTitle>
|
||||
|
||||
<EuiSpacer size="s" />
|
||||
<EuiSpacer size="s" />
|
||||
|
||||
<EuiText style={{ width: 300 }} color="subdued" size="s">
|
||||
<p>
|
||||
{i18n.translate('console.helpPopover.description', {
|
||||
defaultMessage:
|
||||
'Console is an interactive UI for calling Elasticsearch and Kibana APIs and viewing their responses. Search your data, manage settings, and more, using Query DSL and REST API syntax.',
|
||||
})}
|
||||
</p>
|
||||
</EuiText>
|
||||
<EuiText style={{ width: 300 }} color="subdued" size="s">
|
||||
<p>
|
||||
{i18n.translate('console.helpPopover.description', {
|
||||
defaultMessage:
|
||||
'Console is an interactive UI for calling Elasticsearch and Kibana APIs and viewing their responses. Search your data, manage settings, and more, using Query DSL and REST API syntax.',
|
||||
})}
|
||||
</p>
|
||||
</EuiText>
|
||||
</EuiPanel>
|
||||
|
||||
<EuiSpacer />
|
||||
|
||||
<EuiFlexGroup gutterSize="m" direction="column">
|
||||
<EuiFlexItem>
|
||||
<EuiFlexGroup justifyContent="spaceBetween" alignItems="center">
|
||||
<EuiFlexItem grow={false}>
|
||||
<p>
|
||||
{i18n.translate('console.helpPopover.aboutConsoleLabel', {
|
||||
defaultMessage: 'About Console',
|
||||
})}
|
||||
</p>
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem grow={false}>
|
||||
<EuiButtonIcon
|
||||
iconType="popout"
|
||||
href={docLinks.console.guide}
|
||||
target="_blank"
|
||||
color="text"
|
||||
aria-label={i18n.translate('console.helpPopover.aboutConsoleButtonAriaLabel', {
|
||||
defaultMessage: 'About Console link',
|
||||
})}
|
||||
/>
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
</EuiFlexItem>
|
||||
|
||||
<EuiFlexItem>
|
||||
<EuiFlexGroup justifyContent="spaceBetween" alignItems="center">
|
||||
<EuiFlexItem grow={false}>
|
||||
<p>
|
||||
{i18n.translate('console.helpPopover.aboutQueryDSLLabel', {
|
||||
defaultMessage: 'About Query DSL',
|
||||
})}
|
||||
</p>
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem grow={false}>
|
||||
<EuiButtonIcon
|
||||
iconType="popout"
|
||||
href={docLinks.query.queryDsl}
|
||||
target="_blank"
|
||||
color="text"
|
||||
aria-label={i18n.translate('console.helpPopover.aboutQueryDSLButtonAriaLabel', {
|
||||
defaultMessage: 'About QueryDSL link',
|
||||
})}
|
||||
/>
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
</EuiFlexItem>
|
||||
|
||||
<EuiFlexItem>
|
||||
<EuiFlexGroup justifyContent="spaceBetween" alignItems="center">
|
||||
<EuiFlexItem grow={false}>
|
||||
<p>
|
||||
{i18n.translate('console.helpPopover.rerunTourLabel', {
|
||||
defaultMessage: 'Re-run feature tour',
|
||||
})}
|
||||
</p>
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem grow={false}>
|
||||
<EuiButtonIcon
|
||||
iconType="refresh"
|
||||
onClick={resetTour}
|
||||
color="text"
|
||||
aria-label={i18n.translate('console.helpPopover.rerunTourButtonAriaLabel', {
|
||||
defaultMessage: 'Re-run feature tour button',
|
||||
})}
|
||||
data-test-subj="consoleRerunTourButton"
|
||||
/>
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
<EuiListGroup listItems={listItems} color="primary" size="s" />
|
||||
</EuiPopover>
|
||||
);
|
||||
};
|
||||
|
|
|
@ -62,17 +62,23 @@ export class MonacoEditorActionsProvider {
|
|||
private setEditorActionsCss: (css: CSSProperties) => void,
|
||||
private isDevMode: boolean
|
||||
) {
|
||||
this.editor.focus();
|
||||
this.parsedRequestsProvider = getParsedRequestsProvider(this.editor.getModel());
|
||||
this.highlightedLines = this.editor.createDecorationsCollection();
|
||||
|
||||
const debouncedHighlightRequests = debounce(
|
||||
() => this.highlightRequests(),
|
||||
async () => {
|
||||
if (editor.hasTextFocus()) {
|
||||
await this.highlightRequests();
|
||||
} else {
|
||||
this.clearEditorDecorations();
|
||||
}
|
||||
},
|
||||
DEBOUNCE_HIGHLIGHT_WAIT_MS,
|
||||
{
|
||||
leading: true,
|
||||
}
|
||||
);
|
||||
debouncedHighlightRequests();
|
||||
|
||||
const debouncedTriggerSuggestions = debounce(
|
||||
() => {
|
||||
|
@ -110,6 +116,15 @@ export class MonacoEditorActionsProvider {
|
|||
});
|
||||
}
|
||||
|
||||
private clearEditorDecorations() {
|
||||
// remove the highlighted lines
|
||||
this.highlightedLines.clear();
|
||||
// hide action buttons
|
||||
this.setEditorActionsCss({
|
||||
visibility: 'hidden',
|
||||
});
|
||||
}
|
||||
|
||||
private updateEditorActions(lineNumber?: number) {
|
||||
// if no request is currently selected, hide the actions buttons
|
||||
if (!lineNumber) {
|
||||
|
|
|
@ -30,30 +30,52 @@ export class MonacoEditorOutputActionsProvider {
|
|||
private setEditorActionsCss: (css: CSSProperties) => void
|
||||
) {
|
||||
this.highlightedLines = this.editor.createDecorationsCollection();
|
||||
this.editor.focus();
|
||||
|
||||
const debouncedHighlightRequests = debounce(
|
||||
() => this.highlightRequests(),
|
||||
async () => {
|
||||
if (editor.hasTextFocus()) {
|
||||
await this.highlightRequests();
|
||||
} else {
|
||||
this.clearEditorDecorations();
|
||||
}
|
||||
},
|
||||
DEBOUNCE_HIGHLIGHT_WAIT_MS,
|
||||
{
|
||||
leading: true,
|
||||
}
|
||||
);
|
||||
debouncedHighlightRequests();
|
||||
|
||||
// init all listeners
|
||||
editor.onDidChangeCursorPosition(async (event) => {
|
||||
editor.onDidChangeCursorPosition(async () => {
|
||||
await debouncedHighlightRequests();
|
||||
});
|
||||
editor.onDidScrollChange(async (event) => {
|
||||
editor.onDidScrollChange(async () => {
|
||||
await debouncedHighlightRequests();
|
||||
});
|
||||
editor.onDidChangeCursorSelection(async (event) => {
|
||||
editor.onDidChangeCursorSelection(async () => {
|
||||
await debouncedHighlightRequests();
|
||||
});
|
||||
editor.onDidContentSizeChange(async (event) => {
|
||||
editor.onDidContentSizeChange(async () => {
|
||||
await debouncedHighlightRequests();
|
||||
});
|
||||
|
||||
editor.onDidBlurEditorText(() => {
|
||||
// Since the actions buttons are placed outside of the editor, we need to delay
|
||||
// the clearing of the editor decorations to ensure that the actions buttons
|
||||
// are not hidden.
|
||||
setTimeout(() => {
|
||||
this.clearEditorDecorations();
|
||||
}, 100);
|
||||
});
|
||||
}
|
||||
|
||||
private clearEditorDecorations() {
|
||||
// remove the highlighted lines
|
||||
this.highlightedLines.clear();
|
||||
// hide action buttons
|
||||
this.setEditorActionsCss({
|
||||
visibility: 'hidden',
|
||||
});
|
||||
}
|
||||
|
||||
private updateEditorActions(lineNumber?: number) {
|
||||
|
|
|
@ -66,7 +66,9 @@ const CheckeableCardLabel = ({ historyItem }: { historyItem: HistoryProps }) =>
|
|||
<EuiFlexGroup>
|
||||
<EuiFlexItem>
|
||||
<EuiText size="s">
|
||||
<b>{historyItem.endpoint}</b>
|
||||
<b>
|
||||
{historyItem.method} {historyItem.endpoint}
|
||||
</b>
|
||||
</EuiText>
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem grow={false}>
|
||||
|
|
|
@ -47,6 +47,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) {
|
|||
it('should be able to copy the response of a request', async () => {
|
||||
await sendRequest('GET /_search?pretty');
|
||||
|
||||
await PageObjects.console.focusOutputEditor();
|
||||
await PageObjects.console.clickCopyOutput();
|
||||
|
||||
const resultToast = await toasts.getElementByIndex(1);
|
||||
|
|
|
@ -84,7 +84,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) {
|
|||
|
||||
await retry.try(async () => {
|
||||
const history = await PageObjects.console.getHistoryEntries();
|
||||
expect(history).to.eql(['/_search?pretty\na few seconds ago']);
|
||||
expect(history).to.eql(['GET /_search?pretty\na few seconds ago']);
|
||||
});
|
||||
|
||||
await PageObjects.console.clickClearHistory();
|
||||
|
|
|
@ -51,6 +51,13 @@ export class ConsolePageObject extends FtrService {
|
|||
await textArea.clearValueWithKeyboard();
|
||||
}
|
||||
|
||||
public async focusOutputEditor() {
|
||||
const outputEditor = await this.testSubjects.find('consoleMonacoOutput');
|
||||
// Simply clicking on the output editor doesn't focus it, so we need to click
|
||||
// on the margin view overlays
|
||||
await (await outputEditor.findByClassName('margin-view-overlays')).click();
|
||||
}
|
||||
|
||||
public async getOutputText() {
|
||||
const outputPanel = await this.testSubjects.find('consoleMonacoOutput');
|
||||
const outputViewDiv = await outputPanel.findByClassName('monaco-scrollable-element');
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue