Browse Source

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

Johannes Schill 7 years ago
parent
commit
23ae1c7184

+ 2 - 98
public/app/features/dashboard/dashgrid/QueriesTab.tsx

@@ -13,7 +13,6 @@ import { QueryInspector } from './QueryInspector';
 import { getDatasourceSrv } from 'app/features/plugins/datasource_srv';
 import { getDatasourceSrv } from 'app/features/plugins/datasource_srv';
 import { getBackendSrv, BackendSrv } from 'app/core/services/backend_srv';
 import { getBackendSrv, BackendSrv } from 'app/core/services/backend_srv';
 import { DataSourceSelectItem } from 'app/types';
 import { DataSourceSelectItem } from 'app/types';
-import appEvents from 'app/core/app_events';
 
 
 import Remarkable from 'remarkable';
 import Remarkable from 'remarkable';
 
 
@@ -27,15 +26,9 @@ interface Help {
   helpHtml: any;
   helpHtml: any;
 }
 }
 
 
-interface DsQuery {
-  isLoading: boolean;
-  response: {};
-}
-
 interface State {
 interface State {
   currentDatasource: DataSourceSelectItem;
   currentDatasource: DataSourceSelectItem;
   help: Help;
   help: Help;
-  dsQuery: DsQuery;
 }
 }
 
 
 interface LoadingPlaceholderProps {
 interface LoadingPlaceholderProps {
@@ -60,13 +53,7 @@ export class QueriesTab extends PureComponent<Props, State> {
         isLoading: false,
         isLoading: false,
         helpHtml: null,
         helpHtml: null,
       },
       },
-      dsQuery: {
-        isLoading: false,
-        response: {},
-      },
     };
     };
-    appEvents.on('ds-request-response', this.onDataSourceResponse);
-    panel.events.on('refresh', this.onPanelRefresh);
   }
   }
 
 
   componentDidMount() {
   componentDidMount() {
@@ -89,84 +76,11 @@ export class QueriesTab extends PureComponent<Props, State> {
   }
   }
 
 
   componentWillUnmount() {
   componentWillUnmount() {
-    const { panel } = this.props;
-    appEvents.off('ds-request-response', this.onDataSourceResponse);
-    panel.events.off('refresh', this.onPanelRefresh);
-
     if (this.component) {
     if (this.component) {
       this.component.destroy();
       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 => {
   onChangeDataSource = datasource => {
     const { panel } = this.props;
     const { panel } = this.props;
     const { currentDatasource } = this.state;
     const { currentDatasource } = this.state;
@@ -291,18 +205,9 @@ export class QueriesTab extends PureComponent<Props, State> {
     });
     });
   };
   };
 
 
-  loadQueryInspector = () => {
-    const { panel } = this.props;
-    panel.refresh();
-  };
-
   renderQueryInspector = () => {
   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 = () => {
   renderHelp = () => {
@@ -331,7 +236,6 @@ export class QueriesTab extends PureComponent<Props, State> {
 
 
     const queryInspector = {
     const queryInspector = {
       title: 'Query Inspector',
       title: 'Query Inspector',
-      onClick: this.loadQueryInspector,
       render: this.renderQueryInspector,
       render: this.renderQueryInspector,
     };
     };
 
 

+ 181 - 36
public/app/features/dashboard/dashgrid/QueryInspector.tsx

@@ -3,12 +3,21 @@ import { JSONFormatter } from 'app/core/components/JSONFormatter/JSONFormatter';
 import appEvents from 'app/core/app_events';
 import appEvents from 'app/core/app_events';
 import { CopyToClipboard } from 'app/core/components/CopyToClipboard/CopyToClipboard';
 import { CopyToClipboard } from 'app/core/components/CopyToClipboard/CopyToClipboard';
 
 
+interface DsQuery {
+  isLoading: boolean;
+  response: {};
+}
+
 interface Props {
 interface Props {
-  response: any;
+  panel: any;
+  LoadingPlaceholder: any;
 }
 }
 
 
 interface State {
 interface State {
   allNodesExpanded: boolean;
   allNodesExpanded: boolean;
+  isMocking: boolean;
+  mockedResponse: string;
+  dsQuery: DsQuery;
 }
 }
 
 
 export class QueryInspector extends PureComponent<Props, State> {
 export class QueryInspector extends PureComponent<Props, State> {
@@ -17,12 +26,112 @@ export class QueryInspector extends PureComponent<Props, State> {
 
 
   constructor(props) {
   constructor(props) {
     super(props);
     super(props);
-
     this.state = {
     this.state = {
       allNodesExpanded: null,
       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 => {
   setFormattedJson = formattedJson => {
     this.formattedJson = 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 = () => {
   getNrOfOpenNodes = () => {
     if (this.state.allNodesExpanded === null) {
     if (this.state.allNodesExpanded === null) {
-      return 3;
+      return 3; // 3 is default, ie when state is null
     } else if (this.state.allNodesExpanded) {
     } else if (this.state.allNodesExpanded) {
       return 20;
       return 20;
     }
     }
     return 1;
     return 1;
   };
   };
 
 
+  setMockedResponse = evt => {
+    const mockedResponse = evt.target.value;
+    this.setState(prevState => ({
+      ...prevState,
+      mockedResponse,
+    }));
+  };
+
   render() {
   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();
     const openNodes = this.getNrOfOpenNodes();
+
+    if (isLoading) {
+      return <LoadingPlaceholder text="Loading query inspector..." />;
+    }
+
     return (
     return (
       <>
       <>
         {/* <div className="query-troubleshooter__header">
         {/* <div className="query-troubleshooter__header">
         <a className="pointer" ng-click="ctrl.toggleMocking()">Mock Response</a>
         <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 onClick={this.copyToClipboard}>Copy</button>
-        <button ref={this.copyButtonRef}>Copy2</button> */}
-        <button className="btn btn-transparent" onClick={this.onToggleExpand}>
-          {allNodesExpanded ? (
-            <>
-              <i className="fa fa-minus-square-o" /> Collapse All
-            </>
-          ) : (
+        */}
+        <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>
+
+          <CopyToClipboard
+            className="btn btn-transparent btn-p-x-0"
+            text={this.getTextForClipboard}
+            onSuccess={this.onClipboardSuccess}
+          >
             <>
             <>
-              <i className="fa fa-plus-square-o" /> Expand All
+              <i className="fa fa-clipboard" /> Copy to Clipboard
             </>
             </>
-          )}
-        </button>
-
-        <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} />
+          </CopyToClipboard>
+        </div>
+
+        {!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>
+        )}
       </>
       </>
     );
     );
   }
   }

+ 6 - 0
public/sass/components/_buttons.scss

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