Просмотр исходного кода

Explore split view

* button to bring a up a duplicate explore area to compare
* side by side rendering of two explore components
* right component has close button
* left component has page title
David Kaltschmidt 7 лет назад
Родитель
Сommit
f5e351af8b

+ 46 - 8
public/app/containers/Explore/Explore.tsx

@@ -80,6 +80,7 @@ export class Explore extends React.Component<any, IExploreState> {
       showingGraph: true,
       showingTable: true,
       tableResult: null,
+      ...props.initialState,
     };
   }
 
@@ -126,10 +127,24 @@ export class Explore extends React.Component<any, IExploreState> {
     this.setState({ range }, () => this.handleSubmit());
   };
 
+  handleClickCloseSplit = () => {
+    const { onChangeSplit } = this.props;
+    if (onChangeSplit) {
+      onChangeSplit(false);
+    }
+  };
+
   handleClickGraphButton = () => {
     this.setState(state => ({ showingGraph: !state.showingGraph }));
   };
 
+  handleClickSplit = () => {
+    const { onChangeSplit } = this.props;
+    if (onChangeSplit) {
+      onChangeSplit(true, this.state);
+    }
+  };
+
   handleClickTableButton = () => {
     this.setState(state => ({ showingTable: !state.showingTable }));
   };
@@ -211,6 +226,7 @@ export class Explore extends React.Component<any, IExploreState> {
   };
 
   render() {
+    const { position, split } = this.props;
     const {
       datasource,
       datasourceError,
@@ -230,16 +246,32 @@ export class Explore extends React.Component<any, IExploreState> {
     const graphHeight = showingBoth ? '200px' : '400px';
     const graphButtonActive = showingBoth || showingGraph ? 'active' : '';
     const tableButtonActive = showingBoth || showingTable ? 'active' : '';
+    const exploreClass = split ? 'explore explore-split' : 'explore';
     return (
-      <div className="explore">
+      <div className={exploreClass}>
         <div className="navbar">
-          <div>
-            <a className="navbar-page-btn">
-              <i className="fa fa-rocket" />
-              Explore
-            </a>
-          </div>
+          {position === 'left' ? (
+            <div>
+              <a className="navbar-page-btn">
+                <i className="fa fa-rocket" />
+                Explore
+              </a>
+            </div>
+          ) : (
+            <div className="navbar-buttons explore-first-button">
+              <button className="btn navbar-button" onClick={this.handleClickCloseSplit}>
+                Close Split
+              </button>
+            </div>
+          )}
           <div className="navbar__spacer" />
+          {position === 'left' && !split ? (
+            <div className="navbar-buttons">
+              <button className="btn navbar-button" onClick={this.handleClickSplit}>
+                Split
+              </button>
+            </div>
+          ) : null}
           <div className="navbar-buttons">
             <button className={`btn navbar-button ${graphButtonActive}`} onClick={this.handleClickGraphButton}>
               Graph
@@ -278,7 +310,13 @@ export class Explore extends React.Component<any, IExploreState> {
             {queryError ? <div className="text-warning m-a-2">{queryError}</div> : null}
             <main className="m-t-2">
               {showingGraph ? (
-                <Graph data={graphResult} id="explore-1" options={requestOptions} height={graphHeight} />
+                <Graph
+                  data={graphResult}
+                  id={`explore-graph-${position}`}
+                  options={requestOptions}
+                  height={graphHeight}
+                  split={split}
+                />
               ) : null}
               {showingTable ? <Table data={tableResult} className="m-t-3" /> : null}
             </main>

+ 1 - 0
public/app/containers/Explore/Graph.tsx

@@ -75,6 +75,7 @@ class Graph extends Component<any, any> {
     if (
       prevProps.data !== this.props.data ||
       prevProps.options !== this.props.options ||
+      prevProps.split !== this.props.split ||
       prevProps.height !== this.props.height
     ) {
       this.draw();

+ 33 - 0
public/app/containers/Explore/Wrapper.tsx

@@ -0,0 +1,33 @@
+import React, { PureComponent } from 'react';
+
+import Explore from './Explore';
+
+export default class Wrapper extends PureComponent<any, any> {
+  state = {
+    initialState: null,
+    split: false,
+  };
+
+  handleChangeSplit = (split, initialState) => {
+    this.setState({ split, initialState });
+  };
+
+  render() {
+    // State overrides for props from first Explore
+    const { initialState, split } = this.state;
+    return (
+      <div className="explore-wrapper">
+        <Explore {...this.props} position="left" onChangeSplit={this.handleChangeSplit} split={split} />
+        {split ? (
+          <Explore
+            {...this.props}
+            initialState={initialState}
+            onChangeSplit={this.handleChangeSplit}
+            position="right"
+            split={split}
+          />
+        ) : null}
+      </div>
+    );
+  }
+}

+ 1 - 2
public/app/routes/routes.ts

@@ -3,7 +3,6 @@ import './ReactContainer';
 
 import ServerStats from 'app/containers/ServerStats/ServerStats';
 import AlertRuleList from 'app/containers/AlertRuleList/AlertRuleList';
-// import Explore from 'app/containers/Explore/Explore';
 import FolderSettings from 'app/containers/ManageDashboards/FolderSettings';
 import FolderPermissions from 'app/containers/ManageDashboards/FolderPermissions';
 
@@ -114,7 +113,7 @@ export function setupAngularRoutes($routeProvider, $locationProvider) {
     .when('/explore/:initial?', {
       template: '<react-container />',
       resolve: {
-        component: () => import(/* webpackChunkName: "explore" */ 'app/containers/Explore/Explore'),
+        component: () => import(/* webpackChunkName: "explore" */ 'app/containers/Explore/Wrapper'),
       },
     })
     .when('/org', {

+ 40 - 8
public/sass/pages/_explore.scss

@@ -1,8 +1,22 @@
 .explore {
-  .explore-container {
+  width: 100%;
+
+  &-container {
     padding: 2rem;
   }
 
+  &-wrapper {
+    display: flex;
+
+    > .explore-split {
+      width: 50%;
+    }
+  }
+
+  .explore-first-button {
+    margin-left: 15px;
+  }
+
   .explore-graph {
     width: 100%;
     height: 100%;
@@ -12,13 +26,27 @@
     padding: 10px 10px 5px 10px;
   }
 
-  .navbar-page-btn .fa {
-    position: relative;
-    top: -1px;
-    font-size: 19px;
-    line-height: 8px;
-    opacity: 0.75;
-    margin-right: 8px;
+  .navbar {
+    flex-wrap: wrap;
+    height: auto;
+  }
+
+  .navbar-page-btn {
+    margin-right: 1rem;
+
+    .fa {
+      position: relative;
+      top: -1px;
+      font-size: 19px;
+      line-height: 8px;
+      opacity: 0.75;
+      margin-right: 8px;
+    }
+  }
+
+  .navbar-button.active {
+    color: #0083b3;
+    background-color: white;
   }
 
   .elapsed-time {
@@ -52,6 +80,10 @@
   }
 }
 
+.explore + .explore {
+  border-left: 1px dotted #aaa;
+}
+
 .query-row {
   display: flex;