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:
parent
e378555971
commit
0faf8c24ee
|
@ -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,
|
||||
|
|
|
@ -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>
|
||||
`;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
});
|
||||
|
|
|
@ -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>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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>
|
||||
`;
|
||||
|
|
|
@ -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();
|
||||
});
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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,
|
||||
});
|
|
@ -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>
|
||||
);
|
|
@ -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)} />;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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)} />;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 };
|
||||
|
|
|
@ -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',
|
||||
|
|
|
@ -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'];
|
||||
}
|
||||
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue