Use monacco editor in the inspector request panel (#82272)

* Use monacco editor in the inspector request panel

Closes: #81921

* insRequestCodeViewer -> insRequestCodeViewer

* remove uiSettings from props

* fix functional tests

Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com>
This commit is contained in:
Alexey Antonov 2020-11-06 11:34:57 +03:00 committed by GitHub
parent e378555971
commit 0faf8c24ee
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
17 changed files with 403 additions and 451 deletions

View file

@ -70,7 +70,7 @@ export class InspectorPublicPlugin implements Plugin<Setup, Start> {
public async setup(core: CoreSetup) {
this.views = new InspectorViewRegistry();
this.views.register(getDataViewDescription(core.uiSettings));
this.views.register(getDataViewDescription());
this.views.register(getRequestsViewDescription());
return {
@ -101,7 +101,14 @@ export class InspectorPublicPlugin implements Plugin<Setup, Start> {
}
return core.overlays.openFlyout(
toMountPoint(<InspectorPanel views={views} adapters={adapters} title={options.title} />),
toMountPoint(
<InspectorPanel
views={views}
adapters={adapters}
title={options.title}
dependencies={{ uiSettings: core.uiSettings }}
/>
),
{
'data-test-subj': 'inspectorPanel',
closeButtonAriaLabel: closeButtonLabel,

View file

@ -10,6 +10,11 @@ exports[`InspectorPanel should render as expected 1`] = `
},
}
}
dependencies={
Object {
"uiSettings": Object {},
}
}
intl={
Object {
"defaultFormats": Object {},
@ -135,216 +140,228 @@ exports[`InspectorPanel should render as expected 1`] = `
]
}
>
<EuiFlyoutHeader
hasBorder={true}
<Provider
services={
Object {
"uiSettings": Object {},
}
}
>
<div
className="euiFlyoutHeader euiFlyoutHeader--hasBorder"
<EuiFlyoutHeader
hasBorder={true}
>
<EuiFlexGroup
alignItems="center"
justifyContent="spaceBetween"
<div
className="euiFlyoutHeader euiFlyoutHeader--hasBorder"
>
<div
className="euiFlexGroup euiFlexGroup--gutterLarge euiFlexGroup--alignItemsCenter euiFlexGroup--justifyContentSpaceBetween euiFlexGroup--directionRow euiFlexGroup--responsive"
<EuiFlexGroup
alignItems="center"
justifyContent="spaceBetween"
>
<EuiFlexItem
grow={true}
<div
className="euiFlexGroup euiFlexGroup--gutterLarge euiFlexGroup--alignItemsCenter euiFlexGroup--justifyContentSpaceBetween euiFlexGroup--directionRow euiFlexGroup--responsive"
>
<div
className="euiFlexItem"
<EuiFlexItem
grow={true}
>
<EuiTitle
size="s"
<div
className="euiFlexItem"
>
<h1
className="euiTitle euiTitle--small"
<EuiTitle
size="s"
>
Inspector
</h1>
</EuiTitle>
</div>
</EuiFlexItem>
<EuiFlexItem
grow={false}
>
<div
className="euiFlexItem euiFlexItem--flexGrowZero"
<h1
className="euiTitle euiTitle--small"
>
Inspector
</h1>
</EuiTitle>
</div>
</EuiFlexItem>
<EuiFlexItem
grow={false}
>
<InspectorViewChooser
onViewSelected={[Function]}
selectedView={
Object {
"component": [Function],
"order": 200,
"title": "View 1",
}
}
views={
Array [
<div
className="euiFlexItem euiFlexItem--flexGrowZero"
>
<InspectorViewChooser
onViewSelected={[Function]}
selectedView={
Object {
"component": [Function],
"order": 200,
"title": "View 1",
},
Object {
"component": [Function],
"order": 100,
"shouldShow": [Function],
"title": "Foo View",
},
Object {
"component": [Function],
"order": 200,
"shouldShow": [Function],
"title": "Never",
},
]
}
>
<EuiPopover
anchorPosition="downRight"
button={
<EuiButtonEmpty
data-test-subj="inspectorViewChooser"
iconSide="right"
iconType="arrowDown"
onClick={[Function]}
size="s"
>
<FormattedMessage
defaultMessage="View: {viewName}"
id="inspector.view"
values={
Object {
"viewName": "View 1",
}
}
/>
</EuiButtonEmpty>
}
}
views={
Array [
Object {
"component": [Function],
"order": 200,
"title": "View 1",
},
Object {
"component": [Function],
"order": 100,
"shouldShow": [Function],
"title": "Foo View",
},
Object {
"component": [Function],
"order": 200,
"shouldShow": [Function],
"title": "Never",
},
]
}
closePopover={[Function]}
display="inlineBlock"
hasArrow={true}
id="inspectorViewChooser"
isOpen={false}
ownFocus={true}
panelPaddingSize="none"
repositionOnScroll={true}
>
<EuiOutsideClickDetector
isDisabled={true}
onOutsideClick={[Function]}
<EuiPopover
anchorPosition="downRight"
button={
<EuiButtonEmpty
data-test-subj="inspectorViewChooser"
iconSide="right"
iconType="arrowDown"
onClick={[Function]}
size="s"
>
<FormattedMessage
defaultMessage="View: {viewName}"
id="inspector.view"
values={
Object {
"viewName": "View 1",
}
}
/>
</EuiButtonEmpty>
}
closePopover={[Function]}
display="inlineBlock"
hasArrow={true}
id="inspectorViewChooser"
isOpen={false}
ownFocus={true}
panelPaddingSize="none"
repositionOnScroll={true}
>
<div
className="euiPopover euiPopover--anchorDownRight"
id="inspectorViewChooser"
onKeyDown={[Function]}
onMouseDown={[Function]}
onMouseUp={[Function]}
onTouchEnd={[Function]}
onTouchStart={[Function]}
<EuiOutsideClickDetector
isDisabled={true}
onOutsideClick={[Function]}
>
<div
className="euiPopover__anchor"
className="euiPopover euiPopover--anchorDownRight"
id="inspectorViewChooser"
onKeyDown={[Function]}
onMouseDown={[Function]}
onMouseUp={[Function]}
onTouchEnd={[Function]}
onTouchStart={[Function]}
>
<EuiButtonEmpty
data-test-subj="inspectorViewChooser"
iconSide="right"
iconType="arrowDown"
onClick={[Function]}
size="s"
<div
className="euiPopover__anchor"
>
<button
className="euiButtonEmpty euiButtonEmpty--primary euiButtonEmpty--small"
<EuiButtonEmpty
data-test-subj="inspectorViewChooser"
iconSide="right"
iconType="arrowDown"
onClick={[Function]}
type="button"
size="s"
>
<EuiButtonContent
className="euiButtonEmpty__content"
iconSide="right"
iconType="arrowDown"
textProps={
Object {
"className": "euiButtonEmpty__text",
}
}
<button
className="euiButtonEmpty euiButtonEmpty--primary euiButtonEmpty--small"
data-test-subj="inspectorViewChooser"
onClick={[Function]}
type="button"
>
<span
className="euiButtonContent euiButtonContent--iconRight euiButtonEmpty__content"
<EuiButtonContent
className="euiButtonEmpty__content"
iconSide="right"
iconType="arrowDown"
textProps={
Object {
"className": "euiButtonEmpty__text",
}
}
>
<EuiIcon
className="euiButtonContent__icon"
size="m"
type="arrowDown"
>
<span
className="euiButtonContent__icon"
data-euiicon-type="arrowDown"
size="m"
/>
</EuiIcon>
<span
className="euiButtonEmpty__text"
className="euiButtonContent euiButtonContent--iconRight euiButtonEmpty__content"
>
<FormattedMessage
defaultMessage="View: {viewName}"
id="inspector.view"
values={
Object {
"viewName": "View 1",
}
}
<EuiIcon
className="euiButtonContent__icon"
size="m"
type="arrowDown"
>
View: View 1
</FormattedMessage>
<span
className="euiButtonContent__icon"
data-euiicon-type="arrowDown"
size="m"
/>
</EuiIcon>
<span
className="euiButtonEmpty__text"
>
<FormattedMessage
defaultMessage="View: {viewName}"
id="inspector.view"
values={
Object {
"viewName": "View 1",
}
}
>
View: View 1
</FormattedMessage>
</span>
</span>
</span>
</EuiButtonContent>
</button>
</EuiButtonEmpty>
</EuiButtonContent>
</button>
</EuiButtonEmpty>
</div>
</div>
</div>
</EuiOutsideClickDetector>
</EuiPopover>
</InspectorViewChooser>
</div>
</EuiFlexItem>
</div>
</EuiFlexGroup>
</div>
</EuiFlyoutHeader>
<EuiFlyoutBody
className="insInspectorPanel__flyoutBody"
>
<div
className="euiFlyoutBody insInspectorPanel__flyoutBody"
</EuiOutsideClickDetector>
</EuiPopover>
</InspectorViewChooser>
</div>
</EuiFlexItem>
</div>
</EuiFlexGroup>
</div>
</EuiFlyoutHeader>
<EuiFlyoutBody
className="insInspectorPanel__flyoutBody"
>
<div
className="euiFlyoutBody__overflow"
className="euiFlyoutBody insInspectorPanel__flyoutBody"
>
<div
className="euiFlyoutBody__overflowContent"
className="euiFlyoutBody__overflow"
>
<component
adapters={
Object {
"bardapter": Object {},
"foodapter": Object {
"foo": [Function],
},
}
}
title="Inspector"
<div
className="euiFlyoutBody__overflowContent"
>
<h1>
View 1
</h1>
</component>
<Suspense
fallback={<EuiLoadingSpinner />}
>
<component
adapters={
Object {
"bardapter": Object {},
"foodapter": Object {
"foo": [Function],
},
}
}
title="Inspector"
>
<h1>
View 1
</h1>
</component>
</Suspense>
</div>
</div>
</div>
</div>
</EuiFlyoutBody>
</EuiFlyoutBody>
</Provider>
</InspectorPanel>
`;

View file

@ -1,11 +1,15 @@
.insInspectorPanel__flyoutBody {
// TODO: EUI to allow for custom classNames to inner elements
// Or supply this as default
> div {
.euiFlyoutBody__overflowContent {
height: 100%;
display: flex;
flex-wrap: nowrap;
flex-direction: column;
> div {
>div {
flex-grow: 0;
}
.insRequestCodeViewer {
flex-grow: 1;
}
}

View file

@ -22,10 +22,12 @@ import { mountWithIntl } from 'test_utils/enzyme_helpers';
import { InspectorPanel } from './inspector_panel';
import { InspectorViewDescription } from '../types';
import { Adapters } from '../../common';
import type { IUiSettingsClient } from 'kibana/public';
describe('InspectorPanel', () => {
let adapters: Adapters;
let views: InspectorViewDescription[];
const uiSettings: IUiSettingsClient = {} as IUiSettingsClient;
beforeEach(() => {
adapters = {
@ -62,12 +64,16 @@ describe('InspectorPanel', () => {
});
it('should render as expected', () => {
const component = mountWithIntl(<InspectorPanel adapters={adapters} views={views} />);
const component = mountWithIntl(
<InspectorPanel adapters={adapters} views={views} dependencies={{ uiSettings }} />
);
expect(component).toMatchSnapshot();
});
it('should not allow updating adapters', () => {
const component = mountWithIntl(<InspectorPanel adapters={adapters} views={views} />);
const component = mountWithIntl(
<InspectorPanel adapters={adapters} views={views} dependencies={{ uiSettings }} />
);
adapters.notAllowed = {};
expect(() => component.setProps({ adapters })).toThrow();
});

View file

@ -19,12 +19,21 @@
import './inspector_panel.scss';
import { i18n } from '@kbn/i18n';
import React, { Component } from 'react';
import React, { Component, Suspense } from 'react';
import PropTypes from 'prop-types';
import { EuiFlexGroup, EuiFlexItem, EuiFlyoutHeader, EuiTitle, EuiFlyoutBody } from '@elastic/eui';
import {
EuiFlexGroup,
EuiFlexItem,
EuiFlyoutHeader,
EuiTitle,
EuiFlyoutBody,
EuiLoadingSpinner,
} from '@elastic/eui';
import { IUiSettingsClient } from 'kibana/public';
import { InspectorViewDescription } from '../types';
import { Adapters } from '../../common';
import { InspectorViewChooser } from './inspector_view_chooser';
import { KibanaContextProvider } from '../../../kibana_react/public';
function hasAdaptersChanged(oldAdapters: Adapters, newAdapters: Adapters) {
return (
@ -41,6 +50,9 @@ interface InspectorPanelProps {
adapters: Adapters;
title?: string;
views: InspectorViewDescription[];
dependencies: {
uiSettings: IUiSettingsClient;
};
}
interface InspectorPanelState {
@ -95,19 +107,21 @@ export class InspectorPanel extends Component<InspectorPanelProps, InspectorPane
renderSelectedPanel() {
return (
<this.state.selectedView.component
adapters={this.props.adapters}
title={this.props.title || ''}
/>
<Suspense fallback={<EuiLoadingSpinner />}>
<this.state.selectedView.component
adapters={this.props.adapters}
title={this.props.title || ''}
/>
</Suspense>
);
}
render() {
const { views, title } = this.props;
const { views, title, dependencies } = this.props;
const { selectedView } = this.state;
return (
<React.Fragment>
<KibanaContextProvider services={dependencies}>
<EuiFlyoutHeader hasBorder>
<EuiFlexGroup justifyContent="spaceBetween" alignItems="center">
<EuiFlexItem grow={true}>
@ -127,7 +141,7 @@ export class InspectorPanel extends Component<InspectorPanelProps, InspectorPane
<EuiFlyoutBody className="insInspectorPanel__flyoutBody">
{this.renderSelectedPanel()}
</EuiFlyoutBody>
</React.Fragment>
</KibanaContextProvider>
);
}
}

View file

@ -1,7 +1,7 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`Inspector Data View component should render empty state 1`] = `
<component
<EnhancedType
adapters={
Object {
"data": DataAdapter {
@ -235,8 +235,24 @@ exports[`Inspector Data View component should render empty state 1`] = `
"timeZone": null,
}
}
kibana={
Object {
"notifications": Object {
"toasts": Object {
"danger": [Function],
"show": [Function],
"success": [Function],
"warning": [Function],
},
},
"overlays": Object {
"openFlyout": [Function],
"openModal": [Function],
},
"services": Object {},
}
}
title="Test Data"
uiSettings={Object {}}
>
<EuiEmptyPrompt
body={
@ -311,23 +327,15 @@ exports[`Inspector Data View component should render empty state 1`] = `
</div>
</EuiEmptyPrompt>
</DataViewComponent>
</component>
</EnhancedType>
`;
exports[`Inspector Data View component should render loading state 1`] = `
<component
adapters={
Object {
"data": DataAdapter {
"_events": Object {
"change": [Function],
},
"_eventsCount": 1,
"_maxListeners": undefined,
"tabular": undefined,
"tabularOptions": undefined,
},
}
<Suspense
fallback={
<div>
loading
</div>
}
intl={
Object {
@ -431,204 +439,9 @@ exports[`Inspector Data View component should render loading state 1`] = `
"timeZone": null,
}
}
title="Test Data"
>
<DataViewComponent
adapters={
Object {
"data": DataAdapter {
"_events": Object {
"change": [Function],
},
"_eventsCount": 1,
"_maxListeners": undefined,
"tabular": undefined,
"tabularOptions": undefined,
},
}
}
intl={
Object {
"defaultFormats": Object {},
"defaultLocale": "en",
"formatDate": [Function],
"formatHTMLMessage": [Function],
"formatMessage": [Function],
"formatNumber": [Function],
"formatPlural": [Function],
"formatRelative": [Function],
"formatTime": [Function],
"formats": Object {
"date": Object {
"full": Object {
"day": "numeric",
"month": "long",
"weekday": "long",
"year": "numeric",
},
"long": Object {
"day": "numeric",
"month": "long",
"year": "numeric",
},
"medium": Object {
"day": "numeric",
"month": "short",
"year": "numeric",
},
"short": Object {
"day": "numeric",
"month": "numeric",
"year": "2-digit",
},
},
"number": Object {
"currency": Object {
"style": "currency",
},
"percent": Object {
"style": "percent",
},
},
"relative": Object {
"days": Object {
"units": "day",
},
"hours": Object {
"units": "hour",
},
"minutes": Object {
"units": "minute",
},
"months": Object {
"units": "month",
},
"seconds": Object {
"units": "second",
},
"years": Object {
"units": "year",
},
},
"time": Object {
"full": Object {
"hour": "numeric",
"minute": "numeric",
"second": "numeric",
"timeZoneName": "short",
},
"long": Object {
"hour": "numeric",
"minute": "numeric",
"second": "numeric",
"timeZoneName": "short",
},
"medium": Object {
"hour": "numeric",
"minute": "numeric",
"second": "numeric",
},
"short": Object {
"hour": "numeric",
"minute": "numeric",
},
},
},
"formatters": Object {
"getDateTimeFormat": [Function],
"getMessageFormat": [Function],
"getNumberFormat": [Function],
"getPluralFormat": [Function],
"getRelativeFormat": [Function],
},
"locale": "en",
"messages": Object {},
"now": [Function],
"onError": [Function],
"textComponent": Symbol(react.fragment),
"timeZone": null,
}
}
title="Test Data"
uiSettings={Object {}}
>
<EuiFlexGroup
alignItems="center"
justifyContent="center"
style={
Object {
"height": "100%",
}
}
>
<div
className="euiFlexGroup euiFlexGroup--gutterLarge euiFlexGroup--alignItemsCenter euiFlexGroup--justifyContentCenter euiFlexGroup--directionRow euiFlexGroup--responsive"
style={
Object {
"height": "100%",
}
}
>
<EuiFlexItem
grow={false}
>
<div
className="euiFlexItem euiFlexItem--flexGrowZero"
>
<EuiPanel
className="eui-textCenter"
>
<div
className="euiPanel euiPanel--paddingMedium eui-textCenter"
>
<EuiLoadingChart
size="m"
>
<span
className="euiLoadingChart euiLoadingChart--medium"
>
<span
className="euiLoadingChart__bar"
/>
<span
className="euiLoadingChart__bar"
/>
<span
className="euiLoadingChart__bar"
/>
<span
className="euiLoadingChart__bar"
/>
</span>
</EuiLoadingChart>
<EuiSpacer
size="s"
>
<div
className="euiSpacer euiSpacer--s"
/>
</EuiSpacer>
<EuiText>
<div
className="euiText euiText--medium"
>
<p>
<FormattedMessage
defaultMessage="Gathering data"
id="inspector.data.gatheringDataLabel"
values={Object {}}
>
Gathering data
</FormattedMessage>
</p>
</div>
</EuiText>
</div>
</EuiPanel>
</div>
</EuiFlexItem>
</div>
</EuiFlexGroup>
</DataViewComponent>
</component>
<div>
loading
</div>
</Suspense>
`;

View file

@ -17,11 +17,10 @@
* under the License.
*/
import React from 'react';
import React, { Suspense } from 'react';
import { getDataViewDescription } from '../index';
import { DataAdapter } from '../../../../common/adapters/data';
import { mountWithIntl } from 'test_utils/enzyme_helpers';
import { IUiSettingsClient } from '../../../../../../core/public';
jest.mock('../lib/export_csv', () => ({
exportAsCsv: jest.fn(),
@ -31,9 +30,7 @@ describe('Inspector Data View', () => {
let DataView: any;
beforeEach(() => {
const uiSettings = {} as IUiSettingsClient;
DataView = getDataViewDescription(uiSettings);
DataView = getDataViewDescription();
});
it('should only show if data adapter is present', () => {
@ -51,7 +48,12 @@ describe('Inspector Data View', () => {
});
it('should render loading state', () => {
const component = mountWithIntl(<DataView.component title="Test Data" adapters={adapters} />); // eslint-disable-line react/jsx-pascal-case
const DataViewComponent = DataView.component;
const component = mountWithIntl(
<Suspense fallback={<div>loading</div>}>
<DataViewComponent title="Test Data" adapters={adapters} />
</Suspense>
);
expect(component).toMatchSnapshot();
});

View file

@ -38,6 +38,7 @@ import {
TabularCallback,
} from '../../../../common/adapters/data/types';
import { IUiSettingsClient } from '../../../../../../core/public';
import { withKibana, KibanaReactContextValue } from '../../../../../kibana_react/public';
interface DataViewComponentState {
tabularData: TabularData | null;
@ -47,20 +48,23 @@ interface DataViewComponentState {
}
interface DataViewComponentProps extends InspectorViewProps {
uiSettings: IUiSettingsClient;
kibana: KibanaReactContextValue<{ uiSettings: IUiSettingsClient }>;
}
export class DataViewComponent extends Component<DataViewComponentProps, DataViewComponentState> {
class DataViewComponent extends Component<DataViewComponentProps, DataViewComponentState> {
static propTypes = {
uiSettings: PropTypes.object.isRequired,
adapters: PropTypes.object.isRequired,
title: PropTypes.string.isRequired,
kibana: PropTypes.object,
};
state = {} as DataViewComponentState;
_isMounted = false;
static getDerivedStateFromProps(nextProps: InspectorViewProps, state: DataViewComponentState) {
static getDerivedStateFromProps(
nextProps: DataViewComponentProps,
state: DataViewComponentState
) {
if (state && nextProps.adapters === state.adapters) {
return null;
}
@ -172,8 +176,12 @@ export class DataViewComponent extends Component<DataViewComponentProps, DataVie
data={this.state.tabularData}
isFormatted={this.state.tabularOptions.returnsFormattedValues}
exportTitle={this.props.title}
uiSettings={this.props.uiSettings}
uiSettings={this.props.kibana.services.uiSettings}
/>
);
}
}
// default export required for React.Lazy
// eslint-disable-next-line import/no-default-export
export default withKibana(DataViewComponent);

View file

@ -16,17 +16,15 @@
* specific language governing permissions and limitations
* under the License.
*/
import React from 'react';
import { lazy } from 'react';
import { i18n } from '@kbn/i18n';
import { DataViewComponent } from './components/data_view';
import { InspectorViewDescription, InspectorViewProps } from '../../types';
import { InspectorViewDescription } from '../../types';
import { Adapters } from '../../../common';
import { IUiSettingsClient } from '../../../../../core/public';
export const getDataViewDescription = (
uiSettings: IUiSettingsClient
): InspectorViewDescription => ({
const DataViewComponent = lazy(() => import('./components/data_view'));
export const getDataViewDescription = (): InspectorViewDescription => ({
title: i18n.translate('inspector.data.dataTitle', {
defaultMessage: 'Data',
}),
@ -37,7 +35,5 @@ export const getDataViewDescription = (
shouldShow(adapters: Adapters) {
return Boolean(adapters.data);
},
component: (props: InspectorViewProps) => (
<DataViewComponent {...props} uiSettings={uiSettings} />
),
component: DataViewComponent,
});

View file

@ -0,0 +1,82 @@
/*
* Licensed to Elasticsearch B.V. under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch B.V. licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
import React from 'react';
import { i18n } from '@kbn/i18n';
import { EuiFlexItem, EuiFlexGroup, EuiCopy, EuiButtonEmpty, EuiSpacer } from '@elastic/eui';
import { CodeEditor } from '../../../../../../kibana_react/public';
interface RequestCodeViewerProps {
json: string;
}
const copyToClipboardLabel = i18n.translate('inspector.requests.copyToClipboardLabel', {
defaultMessage: 'Copy to clipboard',
});
/**
* @internal
*/
export const RequestCodeViewer = ({ json }: RequestCodeViewerProps) => (
<EuiFlexGroup
direction="column"
gutterSize="s"
wrap={false}
responsive={false}
className="insRequestCodeViewer"
>
<EuiFlexItem grow={false}>
<EuiSpacer size="s" />
<div className="eui-textRight">
<EuiCopy textToCopy={json}>
{(copy) => (
<EuiButtonEmpty
size="xs"
flush="right"
iconType="copyClipboard"
onClick={copy}
data-test-subj="inspectorRequestCopyClipboardButton"
>
{copyToClipboardLabel}
</EuiButtonEmpty>
)}
</EuiCopy>
</div>
</EuiFlexItem>
<EuiFlexItem grow={true}>
<CodeEditor
languageId="json"
value={json}
onChange={() => {}}
options={{
readOnly: true,
lineNumbers: 'off',
fontSize: 12,
minimap: {
enabled: false,
},
scrollBeyondLastLine: false,
wordWrap: 'on',
wrappingIndent: 'indent',
automaticLayout: true,
}}
/>
</EuiFlexItem>
</EuiFlexGroup>
);

View file

@ -19,9 +19,9 @@
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import { EuiCodeBlock } from '@elastic/eui';
import { Request } from '../../../../../common/adapters/request/types';
import { RequestDetailsProps } from '../types';
import { RequestCodeViewer } from './req_code_viewer';
export class RequestDetailsRequest extends Component<RequestDetailsProps> {
static propTypes = {
@ -37,15 +37,6 @@ export class RequestDetailsRequest extends Component<RequestDetailsProps> {
return null;
}
return (
<EuiCodeBlock
language="json"
paddingSize="s"
isCopyable
data-test-subj="inspectorRequestBody"
>
{JSON.stringify(json, null, 2)}
</EuiCodeBlock>
);
return <RequestCodeViewer json={JSON.stringify(json, null, 2)} />;
}
}

View file

@ -19,9 +19,9 @@
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import { EuiCodeBlock } from '@elastic/eui';
import { Request } from '../../../../../common/adapters/request/types';
import { RequestDetailsProps } from '../types';
import { RequestCodeViewer } from './req_code_viewer';
export class RequestDetailsResponse extends Component<RequestDetailsProps> {
static propTypes = {
@ -40,15 +40,6 @@ export class RequestDetailsResponse extends Component<RequestDetailsProps> {
return null;
}
return (
<EuiCodeBlock
language="json"
paddingSize="s"
isCopyable
data-test-subj="inspectorResponseBody"
>
{JSON.stringify(responseJSON, null, 2)}
</EuiCodeBlock>
);
return <RequestCodeViewer json={JSON.stringify(responseJSON, null, 2)} />;
}
}

View file

@ -175,3 +175,7 @@ export class RequestsViewComponent extends Component<InspectorViewProps, Request
);
}
}
// default export required for React.Lazy
// eslint-disable-next-line import/no-default-export
export { RequestsViewComponent as default };

View file

@ -18,10 +18,12 @@
*/
import { i18n } from '@kbn/i18n';
import { RequestsViewComponent } from './components/requests_view';
import { lazy } from 'react';
import { InspectorViewDescription } from '../../types';
import { Adapters } from '../../../common';
const RequestsViewComponent = lazy(() => import('./components/requests_view'));
export const getRequestsViewDescription = (): InspectorViewDescription => ({
title: i18n.translate('inspector.requests.requestsTitle', {
defaultMessage: 'Requests',

View file

@ -50,12 +50,14 @@ export function TileMapPageProvider({ getService, getPageObjects }: FtrProviderC
await testSubjects.click('inspectorViewChooser');
await testSubjects.click('inspectorViewChooserRequests');
await testSubjects.click('inspectorRequestDetailRequest');
return await testSubjects.getVisibleText('inspectorRequestBody');
return await inspector.getCodeEditorValue();
}
public async getMapBounds(): Promise<object> {
const request = await this.getVisualizationRequest();
const requestObject = JSON.parse(request);
return requestObject.aggs.filter_agg.filter.geo_bounding_box['geo.coordinates'];
}

View file

@ -23,6 +23,7 @@ import { FtrProviderContext } from '../ftr_provider_context';
export function InspectorProvider({ getService }: FtrProviderContext) {
const log = getService('log');
const retry = getService('retry');
const browser = getService('browser');
const renderable = getService('renderable');
const flyout = getService('flyout');
const testSubjects = getService('testSubjects');
@ -245,6 +246,18 @@ export function InspectorProvider({ getService }: FtrProviderContext) {
public getOpenRequestDetailResponseButton() {
return testSubjects.find('inspectorRequestDetailResponse');
}
public async getCodeEditorValue() {
let request: string = '';
await retry.try(async () => {
request = await browser.execute(
() => (window as any).monaco.editor.getModels()[0].getValue() as string
);
});
return request;
}
}
return new Inspector();

View file

@ -26,7 +26,7 @@ export default function ({ getPageObjects, getService }) {
await inspector.open();
await inspector.openInspectorRequestsView();
await testSubjects.click('inspectorRequestDetailResponse');
const responseBody = await testSubjects.getVisibleText('inspectorResponseBody');
const responseBody = await inspector.getCodeEditorValue();
await inspector.close();
return JSON.parse(responseBody);
}