react-panel: Move all query inspector logic into QueryInspector component and start with the "Mock response"

This commit is contained in:
Johannes Schill
2018-11-27 10:52:47 +01:00
parent 857bd3d8ad
commit 23ae1c7184
3 changed files with 187 additions and 132 deletions

View File

@@ -13,7 +13,6 @@ import { QueryInspector } from './QueryInspector';
import { getDatasourceSrv } from 'app/features/plugins/datasource_srv';
import { getBackendSrv, BackendSrv } from 'app/core/services/backend_srv';
import { DataSourceSelectItem } from 'app/types';
import appEvents from 'app/core/app_events';
import Remarkable from 'remarkable';
@@ -27,15 +26,9 @@ interface Help {
helpHtml: any;
}
interface DsQuery {
isLoading: boolean;
response: {};
}
interface State {
currentDatasource: DataSourceSelectItem;
help: Help;
dsQuery: DsQuery;
}
interface LoadingPlaceholderProps {
@@ -60,13 +53,7 @@ export class QueriesTab extends PureComponent<Props, State> {
isLoading: false,
helpHtml: null,
},
dsQuery: {
isLoading: false,
response: {},
},
};
appEvents.on('ds-request-response', this.onDataSourceResponse);
panel.events.on('refresh', this.onPanelRefresh);
}
componentDidMount() {
@@ -89,84 +76,11 @@ export class QueriesTab extends PureComponent<Props, State> {
}
componentWillUnmount() {
const { panel } = this.props;
appEvents.off('ds-request-response', this.onDataSourceResponse);
panel.events.off('refresh', this.onPanelRefresh);
if (this.component) {
this.component.destroy();
}
}
onPanelRefresh = () => {
this.setState(prevState => ({
...prevState,
dsQuery: {
isLoading: true,
response: {},
},
}));
};
onDataSourceResponse = (response: any = {}) => {
// ignore if closed
// if (!this.isOpen) {
// return;
// }
// if (this.isMocking) {
// this.handleMocking(data);
// return;
// }
// this.isLoading = false;
// data = _.cloneDeep(data);
response = { ...response }; // clone
if (response.headers) {
delete response.headers;
}
if (response.config) {
response.request = response.config;
delete response.config;
delete response.request.transformRequest;
delete response.request.transformResponse;
delete response.request.paramSerializer;
delete response.request.jsonpCallbackParam;
delete response.request.headers;
delete response.request.requestId;
delete response.request.inspect;
delete response.request.retry;
delete response.request.timeout;
}
if (response.data) {
response.response = response.data;
// if (response.status === 200) {
// // if we are in error state, assume we automatically opened
// // and auto close it again
// if (this.hasError) {
// this.hasError = false;
// this.isOpen = false;
// }
// }
delete response.data;
delete response.status;
delete response.statusText;
delete response.$$config;
}
this.setState(prevState => ({
...prevState,
dsQuery: {
isLoading: false,
response: response,
},
}));
};
onChangeDataSource = datasource => {
const { panel } = this.props;
const { currentDatasource } = this.state;
@@ -291,18 +205,9 @@ export class QueriesTab extends PureComponent<Props, State> {
});
};
loadQueryInspector = () => {
const { panel } = this.props;
panel.refresh();
};
renderQueryInspector = () => {
const { response, isLoading } = this.state.dsQuery;
return isLoading ? (
<LoadingPlaceholder text="Loading query inspector..." />
) : (
<QueryInspector response={response} />
);
const { panel } = this.props;
return <QueryInspector panel={panel} LoadingPlaceholder={LoadingPlaceholder} />;
};
renderHelp = () => {
@@ -331,7 +236,6 @@ export class QueriesTab extends PureComponent<Props, State> {
const queryInspector = {
title: 'Query Inspector',
onClick: this.loadQueryInspector,
render: this.renderQueryInspector,
};

View File

@@ -3,12 +3,21 @@ import { JSONFormatter } from 'app/core/components/JSONFormatter/JSONFormatter';
import appEvents from 'app/core/app_events';
import { CopyToClipboard } from 'app/core/components/CopyToClipboard/CopyToClipboard';
interface DsQuery {
isLoading: boolean;
response: {};
}
interface Props {
response: any;
panel: any;
LoadingPlaceholder: any;
}
interface State {
allNodesExpanded: boolean;
isMocking: boolean;
mockedResponse: string;
dsQuery: DsQuery;
}
export class QueryInspector extends PureComponent<Props, State> {
@@ -17,12 +26,112 @@ export class QueryInspector extends PureComponent<Props, State> {
constructor(props) {
super(props);
this.state = {
allNodesExpanded: null,
isMocking: false,
mockedResponse: '',
dsQuery: {
isLoading: false,
response: {},
},
};
}
componentDidMount() {
const { panel } = this.props;
panel.events.on('refresh', this.onPanelRefresh);
appEvents.on('ds-request-response', this.onDataSourceResponse);
panel.refresh();
}
componentWillUnmount() {
const { panel } = this.props;
appEvents.off('ds-request-response', this.onDataSourceResponse);
panel.events.off('refresh', this.onPanelRefresh);
}
handleMocking(response) {
const { mockedResponse } = this.state;
let mockedData;
try {
mockedData = JSON.parse(mockedResponse);
} catch (err) {
appEvents.emit('alert-error', ['R: Failed to parse mocked response']);
return;
}
response.data = mockedData;
}
onPanelRefresh = () => {
this.setState(prevState => ({
...prevState,
dsQuery: {
isLoading: true,
response: {},
},
}));
};
onDataSourceResponse = (response: any = {}) => {
// ignore if closed
// if (!this.isOpen) {
// return;
// }
if (this.state.isMocking) {
this.handleMocking(response);
return;
}
// this.isLoading = false;
// data = _.cloneDeep(data);
response = { ...response }; // clone
if (response.headers) {
delete response.headers;
}
if (response.config) {
response.request = response.config;
delete response.config;
delete response.request.transformRequest;
delete response.request.transformResponse;
delete response.request.paramSerializer;
delete response.request.jsonpCallbackParam;
delete response.request.headers;
delete response.request.requestId;
delete response.request.inspect;
delete response.request.retry;
delete response.request.timeout;
}
if (response.data) {
response.response = response.data;
// if (response.status === 200) {
// // if we are in error state, assume we automatically opened
// // and auto close it again
// if (this.hasError) {
// this.hasError = false;
// this.isOpen = false;
// }
// }
delete response.data;
delete response.status;
delete response.statusText;
delete response.$$config;
}
this.setState(prevState => ({
...prevState,
dsQuery: {
isLoading: false,
response: response,
},
}));
};
setFormattedJson = formattedJson => {
this.formattedJson = formattedJson;
};
@@ -42,56 +151,92 @@ export class QueryInspector extends PureComponent<Props, State> {
}));
};
onToggleMocking = () => {
this.setState(prevState => ({
...prevState,
isMocking: !this.state.isMocking,
}));
};
getNrOfOpenNodes = () => {
if (this.state.allNodesExpanded === null) {
return 3;
return 3; // 3 is default, ie when state is null
} else if (this.state.allNodesExpanded) {
return 20;
}
return 1;
};
setMockedResponse = evt => {
const mockedResponse = evt.target.value;
this.setState(prevState => ({
...prevState,
mockedResponse,
}));
};
render() {
const { response } = this.props;
const { allNodesExpanded } = this.state;
const { response, isLoading } = this.state.dsQuery;
const { LoadingPlaceholder } = this.props;
const { allNodesExpanded, isMocking } = this.state;
const openNodes = this.getNrOfOpenNodes();
if (isLoading) {
return <LoadingPlaceholder text="Loading query inspector..." />;
}
return (
<>
{/* <div className="query-troubleshooter__header">
<a className="pointer" ng-click="ctrl.toggleMocking()">Mock Response</a>
<a className="pointer" ng-click="ctrl.toggleExpand()" ng-hide="ctrl.allNodesExpanded">
<i className="fa fa-plus-square-o"></i> Expand All
</a>
<a className="pointer ng-hide" ng-click="ctrl.toggleExpand()" ng-show="ctrl.allNodesExpanded">
<i className="fa fa-minus-square-o"></i> Collapse All
</a>
<a className="pointer ng-isolate-scope" clipboard-button="ctrl.getClipboardText()"><i className="fa fa-clipboard"></i> Copy to Clipboard</a>
*/}
<div>
<button className="btn btn-transparent btn-p-x-0 m-r-1" onClick={this.onToggleMocking}>
Mock response
</button>
<button className="btn btn-transparent btn-p-x-0 m-r-1" onClick={this.onToggleExpand}>
{allNodesExpanded ? (
<>
<i className="fa fa-minus-square-o" /> Collapse All
</>
) : (
<>
<i className="fa fa-plus-square-o" /> Expand All
</>
)}
</button>
</div> */}
{/* <button onClick={this.copyToClipboard}>Copy</button>
<button ref={this.copyButtonRef}>Copy2</button> */}
<button className="btn btn-transparent" onClick={this.onToggleExpand}>
{allNodesExpanded ? (
<CopyToClipboard
className="btn btn-transparent btn-p-x-0"
text={this.getTextForClipboard}
onSuccess={this.onClipboardSuccess}
>
<>
<i className="fa fa-minus-square-o" /> Collapse All
<i className="fa fa-clipboard" /> Copy to Clipboard
</>
) : (
<>
<i className="fa fa-plus-square-o" /> Expand All
</>
)}
</button>
</CopyToClipboard>
</div>
<CopyToClipboard
className="btn btn-transparent"
text={this.getTextForClipboard}
onSuccess={this.onClipboardSuccess}
>
<>
<i className="fa fa-clipboard" /> Copy to Clipboard
</>
</CopyToClipboard>
<JSONFormatter json={response} open={openNodes} onDidRender={this.setFormattedJson} />
{!isMocking && <JSONFormatter json={response} open={openNodes} onDidRender={this.setFormattedJson} />}
{isMocking && (
<div className="query-troubleshooter__body">
<div className="gf-form p-l-1 gf-form--v-stretch">
<textarea
className="gf-form-input"
style={{ width: '95%' }}
rows={10}
onInput={this.setMockedResponse}
placeholder="JSON"
/>
{/* <textarea
className="gf-form-input"
style={{width: '95%'}}
rows={10}
ng-model="ctrl.mockedResponse"
placeholder="JSON"></textarea> */}
</div>
</div>
)}
</>
);
}

View File

@@ -172,6 +172,12 @@
padding-right: 20px;
}
// No horizontal padding
.btn-p-x-0 {
padding-left: 0;
padding-right: 0;
}
// External services
// Usage:
// <div class="btn btn-service btn-service--facebook">Button text</div>