Repository: lens
Updated Branches:
  refs/heads/master 714aae99d -> 01a561c63


LENS-1182: Lens UI Should set database and refresh cubes pane on db switch


Project: http://git-wip-us.apache.org/repos/asf/lens/repo
Commit: http://git-wip-us.apache.org/repos/asf/lens/commit/01a561c6
Tree: http://git-wip-us.apache.org/repos/asf/lens/tree/01a561c6
Diff: http://git-wip-us.apache.org/repos/asf/lens/diff/01a561c6

Branch: refs/heads/master
Commit: 01a561c63aa2d20db36dfe0f22cda798cdf5278e
Parents: 714aae9
Author: Rajat Khandelwal <pro...@apache.org>
Authored: Fri Jun 17 12:09:45 2016 +0530
Committer: Rajat Khandelwal <rajatgupt...@gmail.com>
Committed: Fri Jun 17 12:09:45 2016 +0530

----------------------------------------------------------------------
 lens-ui/app/actions/AdhocQueryActions.js      |  76 +++++++-----
 lens-ui/app/adapters/AdhocQueryAdapter.js     |  10 ++
 lens-ui/app/app.js                            |  10 +-
 lens-ui/app/components/AdhocQueryComponent.js |   2 +-
 lens-ui/app/components/CubeSchemaComponent.js | 128 +++++++++++++--------
 lens-ui/app/components/CubeTreeComponent.js   |  16 +--
 lens-ui/app/components/DatabaseComponent.js   |  66 ++++++-----
 lens-ui/app/components/QueryBoxComponent.js   |   2 +-
 lens-ui/app/components/SidebarComponent.js    |   4 +-
 lens-ui/app/components/TableTreeComponent.js  |  66 +++++++----
 lens-ui/app/constants/AdhocQueryConstants.js  |   3 +
 lens-ui/app/stores/CubeStore.js               |  39 ++++---
 lens-ui/app/stores/DatabaseStore.js           |  10 +-
 lens-ui/server.js                             |   2 +-
 14 files changed, 270 insertions(+), 164 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/lens/blob/01a561c6/lens-ui/app/actions/AdhocQueryActions.js
----------------------------------------------------------------------
diff --git a/lens-ui/app/actions/AdhocQueryActions.js 
b/lens-ui/app/actions/AdhocQueryActions.js
index 2a4b47b..38f2794 100644
--- a/lens-ui/app/actions/AdhocQueryActions.js
+++ b/lens-ui/app/actions/AdhocQueryActions.js
@@ -64,6 +64,42 @@ function _saveQuery (secretToken, user, query, options) {
       });
     }).catch(e => { console.error(e); });
 }
+function _getTables (secretToken, database) {
+  AdhocQueryAdapter.getTables(secretToken, database)
+    .then(function (tables) {
+      AppDispatcher.dispatch({
+        actionType: AdhocQueryConstants.RECEIVE_TABLES,
+        payload: { tables: tables, database: database }
+      });
+    }, function (error) {
+      // propagating the error message, couldn't fetch cubes
+      AppDispatcher.dispatch({
+        actionType: AdhocQueryConstants.RECEIVE_TABLES_FAILED,
+        payload: {
+          responseCode: error.status,
+          responseMessage: error.statusText
+        }
+      });
+    });
+}
+function _getCubes (secretToken, database) {
+  AdhocQueryAdapter.getCubes(secretToken)
+    .then(function (cubes) {
+      AppDispatcher.dispatch({
+        actionType: AdhocQueryConstants.RECEIVE_CUBES,
+        payload: { cubes: cubes, database: database }
+      });
+    }, function (error) {
+      // propagating the error message, couldn't fetch cubes
+      AppDispatcher.dispatch({
+        actionType: AdhocQueryConstants.RECEIVE_CUBES_FAILED,
+        payload: {
+          responseCode: error.status,
+          responseMessage: error.statusText
+        }
+      });
+    });
+}
 
 let AdhocQueryActions = {
   getDatabases (secretToken) {
@@ -83,18 +119,18 @@ let AdhocQueryActions = {
         });
       });
   },
-
-  getCubes (secretToken) {
-    AdhocQueryAdapter.getCubes(secretToken)
-      .then(function (cubes) {
+  setDatabase (secretToken, database) {
+    AdhocQueryAdapter.setDatabase(secretToken, database)
+      .then(function (success) {
         AppDispatcher.dispatch({
-          actionType: AdhocQueryConstants.RECEIVE_CUBES,
-          payload: { cubes: cubes }
+          actionType: AdhocQueryConstants.SELECT_DATABASE,
+          payload: { database: database }
         });
+        _getTables(secretToken, database);
+        _getCubes(secretToken, database);
       }, function (error) {
-        // propagating the error message, couldn't fetch cubes
         AppDispatcher.dispatch({
-          actionType: AdhocQueryConstants.RECEIVE_CUBES_FAILED,
+          actionType: AdhocQueryConstants.SELECT_DATABASE_FAILED,
           payload: {
             responseCode: error.status,
             responseMessage: error.statusText
@@ -102,6 +138,7 @@ let AdhocQueryActions = {
         });
       });
   },
+  getCubes: _getCubes,
 
   getSavedQueries (secretToken, user, options) {
     AdhocQueryAdapter.getSavedQueries(secretToken, user, options)
@@ -216,12 +253,12 @@ let AdhocQueryActions = {
     });
   },
 
-  getCubeDetails (secretToken, cubeName) {
+  getCubeDetails (secretToken, databaseName, cubeName) {
     AdhocQueryAdapter.getCubeDetails(secretToken, cubeName)
       .then(function (cubeDetails) {
         AppDispatcher.dispatch({
           actionType: AdhocQueryConstants.RECEIVE_CUBE_DETAILS,
-          payload: { cubeDetails: cubeDetails }
+          payload: {database: databaseName, cubeDetails: cubeDetails }
         });
       }, function (error) {
         AppDispatcher.dispatch({
@@ -300,24 +337,7 @@ let AdhocQueryActions = {
       });
   },
 
-  getTables (secretToken, database) {
-    AdhocQueryAdapter.getTables(secretToken, database)
-      .then(function (tables) {
-        AppDispatcher.dispatch({
-          actionType: AdhocQueryConstants.RECEIVE_TABLES,
-          payload: { tables: tables, database: database }
-        });
-      }, function (error) {
-        // propagating the error message, couldn't fetch cubes
-        AppDispatcher.dispatch({
-          actionType: AdhocQueryConstants.RECEIVE_TABLES_FAILED,
-          payload: {
-            responseCode: error.status,
-            responseMessage: error.statusText
-          }
-        });
-      });
-  },
+  getTables: _getTables,
 
   getTableDetails (secretToken, tableName, database) {
     AdhocQueryAdapter.getTableDetails(secretToken, tableName, database)

http://git-wip-us.apache.org/repos/asf/lens/blob/01a561c6/lens-ui/app/adapters/AdhocQueryAdapter.js
----------------------------------------------------------------------
diff --git a/lens-ui/app/adapters/AdhocQueryAdapter.js 
b/lens-ui/app/adapters/AdhocQueryAdapter.js
index 445d6f2..9d4b416 100644
--- a/lens-ui/app/adapters/AdhocQueryAdapter.js
+++ b/lens-ui/app/adapters/AdhocQueryAdapter.js
@@ -25,6 +25,7 @@ import Config from 'config.json';
 let baseUrl = Config.baseURL;
 let urls = {
   getDatabases: 'metastore/databases',
+  setDatabases: 'metastore/databases/current',
   getCubes: 'metastore/cubes',
   query: 'queryapi/queries', // POST on this to execute, GET to fetch all
   getTables: 'metastore/nativetables',
@@ -39,6 +40,15 @@ let AdhocQueryAdapter = {
     let url = baseUrl + urls.getDatabases;
     return BaseAdapter.get(url + '?sessionid=' + secretToken);
   },
+  setDatabase (secretToken, database) {
+    let url = baseUrl + urls.setDatabases;
+    return BaseAdapter.put(url + '?sessionid=' + secretToken, database, {
+      headers: {
+        'Content-Type': 'application/json',
+        'Accept': 'application/json'
+      }
+    });
+  },
 
   getCubes (secretToken) {
     let url = baseUrl + urls.getCubes;

http://git-wip-us.apache.org/repos/asf/lens/blob/01a561c6/lens-ui/app/app.js
----------------------------------------------------------------------
diff --git a/lens-ui/app/app.js b/lens-ui/app/app.js
index 73cb511..07d9acf 100644
--- a/lens-ui/app/app.js
+++ b/lens-ui/app/app.js
@@ -30,6 +30,7 @@ import About from './components/AboutComponent';
 import App from './components/AppComponent';
 import AdhocQuery from './components/AdhocQueryComponent';
 import QueryResults from './components/QueryResultsComponent';
+import DatabaseComponent from './components/DatabaseComponent';
 import CubeSchema from './components/CubeSchemaComponent';
 import QueryDetailResult from './components/QueryDetailResultComponent';
 import TableSchema from './components/TableSchemaComponent';
@@ -43,10 +44,11 @@ let routes = (
       <Route name='results' handler={QueryResults}/>
       <Route name='savedqueries' handler={SavedQueries}/>
       <Route name='result' path='/results/:handle' 
handler={QueryDetailResult}/>
-      <Route name='cubeschema' path='schema/cube/:cubeName' 
handler={CubeSchema}/>
-      <Route name='tableschema' path='schema/table/:tableName'
-        handler={TableSchema}/>
-
+    </Route>
+    <Route name='schema' path='schema/:databaseName/' handler={AdhocQuery} >
+      <Route name='cubeschema' path='cube/:cubeName' handler={CubeSchema}/>
+      <Route name='tableschema' path='table/:tableName'
+             handler={TableSchema}/>
     </Route>
     <Route name='about' handler={About} />
     <DefaultRoute handler={AdhocQuery} />

http://git-wip-us.apache.org/repos/asf/lens/blob/01a561c6/lens-ui/app/components/AdhocQueryComponent.js
----------------------------------------------------------------------
diff --git a/lens-ui/app/components/AdhocQueryComponent.js 
b/lens-ui/app/components/AdhocQueryComponent.js
index 32fab33..aae823c 100644
--- a/lens-ui/app/components/AdhocQueryComponent.js
+++ b/lens-ui/app/components/AdhocQueryComponent.js
@@ -29,7 +29,7 @@ class AdhocQuery extends React.Component {
     return (
       <section className='row'>
         <div className='col-md-4'>
-          <Sidebar />
+          <Sidebar {...this.props}/>
         </div>
 
         <div className='col-md-8'>

http://git-wip-us.apache.org/repos/asf/lens/blob/01a561c6/lens-ui/app/components/CubeSchemaComponent.js
----------------------------------------------------------------------
diff --git a/lens-ui/app/components/CubeSchemaComponent.js 
b/lens-ui/app/components/CubeSchemaComponent.js
index f56d9c2..dbb4cbc 100644
--- a/lens-ui/app/components/CubeSchemaComponent.js
+++ b/lens-ui/app/components/CubeSchemaComponent.js
@@ -24,37 +24,53 @@ import UserStore from '../stores/UserStore';
 import AdhocQueryActions from '../actions/AdhocQueryActions';
 import Loader from '../components/LoaderComponent';
 
-function getCubes () {
-  return CubeStore.getCubes();
+function getCubes (database) {
+  return CubeStore.getCubes(database);
 }
 
 function constructMeasureTable (cubeName, measures) {
   let table = measures.map((measure) => {
-    return (
-      <tr key={cubeName + '|' + measure.name}>
-        <td>{ measure.name }</td>
-        <td>{ measure._type }</td>
-        <td>{ measure.default_aggr }</td>
-        <td>{ measure.display_string }</td>
+    if (typeof(measure) == "string") {
+      return (
+        <tr key={cubeName + '|' + measure}>
+          <td>{ measure }</td>
+        </tr>
+      );
+    } else {
+      return (
+        <tr key={cubeName + '|' + measure.name}>
+          <td>{ measure.name }</td>
+          <td>{ measure._type }</td>
+          <td>{ measure.default_aggr }</td>
+          <td>{ measure.display_string }</td>
+        </tr>
+      );
+    }
+  });
+
+  let header = (
+    <tr>
+      <th>Name</th>
+    </tr>
+  );
+  if (typeof(measures[0]) != "string") {
+    header = (
+      <tr>
+        <th>Name</th>
+        <th>Type</th>
+        <th>Default Aggr</th>
+        <th>Description</th>
       </tr>
+
     );
-  });
+  }
 
   return (
     <div className='table-responsive'>
       <table className='table table-striped table-condensed'>
         <caption className='bg-primary text-center'>Measures</caption>
-        <thead>
-          <tr>
-            <th>Name</th>
-            <th>Type</th>
-            <th>Default Aggr</th>
-            <th>Description</th>
-          </tr>
-        </thead>
-        <tbody>
-          {table}
-        </tbody>
+        <thead>{header}</thead>
+        <tbody>{table}</tbody>
       </table>
     </div>
   );
@@ -62,35 +78,48 @@ function constructMeasureTable (cubeName, measures) {
 
 function constructDimensionTable (cubeName, dimensions) {
   let table = dimensions.map((dimension) => {
-    return (
-      <tr key={cubeName + '|' + dimension.name}>
-        <td>{ dimension.name }</td>
-        <td>{ dimension._type }</td>
-        <td>{ dimension.ref_spec && dimension.ref_spec.chain_ref_column &&
+    if (typeof(dimension) =="string") {
+      return (
+        <tr key={cubeName + '|' + dimension}>
+          <td>{ dimension}</td>
+        </tr>
+      );
+    } else {
+      return (
+        <tr key={cubeName + '|' + dimension.name}>
+          <td>{ dimension.name }</td>
+          <td>{ dimension._type }</td>
+          <td>{ dimension.ref_spec && dimension.ref_spec.chain_ref_column &&
           dimension.ref_spec.chain_ref_column.dest_table }</td>
-        <td>{ dimension.ref_spec && dimension.ref_spec.chain_ref_column &&
+          <td>{ dimension.ref_spec && dimension.ref_spec.chain_ref_column &&
           dimension.ref_spec.chain_ref_column.ref_col }</td>
-        <td>{ dimension.description }</td>
+          <td>{ dimension.description }</td>
+        </tr>
+      );
+    }
+  });
+  let header = (
+    <tr>
+      <th>Name</th>
+    </tr>
+  );
+  if (typeof(dimensions[0]) != "string") {
+    header =  (
+      <tr>
+        <th>Name</th>
+        <th>Type</th>
+        <th>Destination Table</th>
+        <th>Column</th>
+        <th>Description</th>
       </tr>
     );
-  });
-
+  }
   return (
     <div className='table-responsive'>
       <table className='table table-striped'>
         <caption className='bg-primary text-center'>Dimensions</caption>
-        <thead>
-          <tr>
-            <th>Name</th>
-            <th>Type</th>
-            <th>Destination Table</th>
-            <th>Column</th>
-            <th>Description</th>
-          </tr>
-        </thead>
-        <tbody>
-          {table}
-        </tbody>
+        <thead>{header}</thead>
+        <tbody>{table}</tbody>
       </table>
     </div>
   );
@@ -100,14 +129,11 @@ function constructDimensionTable (cubeName, dimensions) {
 class CubeSchema extends React.Component {
   constructor (props) {
     super(props);
-    this.state = {cube: {}};
+    this.state = {cube: {}, database: props.params.databaseName};
     this._onChange = this._onChange.bind(this);
 
-    // firing the action for the first time component is rendered
-    // it won't have a cube in the state.
-    let cubeName = props.params.cubeName;
     AdhocQueryActions
-      .getCubeDetails(UserStore.getUserDetails().secretToken, cubeName);
+      .getCubeDetails(UserStore.getUserDetails().secretToken, 
props.params.databaseName, props.params.cubeName);
   }
 
   componentDidMount () {
@@ -121,18 +147,18 @@ class CubeSchema extends React.Component {
   componentWillReceiveProps (props) {
     // TODO are props updated automatically, unlike state?
     let cubeName = props.params.cubeName;
-    let cube = getCubes()[cubeName];
+    let cube = getCubes(props.params.databaseName)[cubeName];
 
     if (cube.isLoaded) {
-      this.setState({ cube: getCubes()[cubeName] });
+      this.setState({ cube: cube, database: props.params.database });
       return;
     }
 
     AdhocQueryActions
-      .getCubeDetails(UserStore.getUserDetails().secretToken, cubeName);
+      .getCubeDetails(UserStore.getUserDetails().secretToken, 
props.params.databaseName, cubeName);
 
     // empty the previous state
-    this.setState({ cube: {} });
+    this.setState({ cube: {}, database: props.params.databaseName });
   }
 
   render () {
@@ -184,7 +210,7 @@ class CubeSchema extends React.Component {
   }
 
   _onChange () {
-    this.setState({cube: getCubes()[this.props.params.cubeName]});
+    this.setState({cube: 
getCubes(this.props.params.databaseName)[this.props.params.cubeName]});
   }
 }
 

http://git-wip-us.apache.org/repos/asf/lens/blob/01a561c6/lens-ui/app/components/CubeTreeComponent.js
----------------------------------------------------------------------
diff --git a/lens-ui/app/components/CubeTreeComponent.js 
b/lens-ui/app/components/CubeTreeComponent.js
index e288476..702fa36 100644
--- a/lens-ui/app/components/CubeTreeComponent.js
+++ b/lens-ui/app/components/CubeTreeComponent.js
@@ -24,6 +24,7 @@ import { Link } from 'react-router';
 import 'react-treeview/react-treeview.css';
 import ClassNames from 'classnames';
 
+import DatabaseStore from '../stores/DatabaseStore';
 import CubeStore from '../stores/CubeStore';
 import AdhocQueryActions from '../actions/AdhocQueryActions';
 import UserStore from '../stores/UserStore';
@@ -32,7 +33,7 @@ import '../styles/css/tree.css';
 
 function getCubeData () {
   return {
-    cubes: CubeStore.getCubes()
+    cubes: CubeStore.getCubes(DatabaseStore.currentDatabase())
   };
 }
 
@@ -44,17 +45,12 @@ class CubeTree extends React.Component {
     // comes with React.createClass, using constructor is the new
     // idiomatic way
     // 
https://facebook.github.io/react/blog/2015/01/27/react-v0.13.0-beta-1.html
-    this.state = { cubes: [], loading: true, isCollapsed: false };
+    this.state = {database: props.database, cubes: [], loading: true, 
isCollapsed: false };
 
     // no autobinding with ES6 so doing it manually, see link below
     // 
https://facebook.github.io/react/blog/2015/01/27/react-v0.13.0-beta-1.html#autobinding
     this._onChange = this._onChange.bind(this);
     this.toggle = this.toggle.bind(this);
-
-    // need to fire an action to fetch the cubes from server
-    // can't ask the store as it won't have any at the startup
-    // TODO optimize this, don't fire it everytime.
-    AdhocQueryActions.getCubes(UserStore.getUserDetails().secretToken);
   }
 
   componentDidMount () {
@@ -77,16 +73,16 @@ class CubeTree extends React.Component {
     var cubeTree = Object.keys(this.state.cubes).map((cubeName, i) => {
       let cube = cubeHash[cubeName];
 
-      let label = <Link to='cubeschema' params={{cubeName: cubeName}}>
+      let label = <Link to='cubeschema' params={{databaseName: 
this.state.database, cubeName: cubeName}}>
           <span className='node'>{cube.name}</span>
         </Link>;
 
-      let measureLabel = <Link to='cubeschema' params={{cubeName: cubeName}}
+      let measureLabel = <Link to='cubeschema' params={{databaseName: 
this.state.database, cubeName: cubeName}}
         query={{type: 'measures'}}>
           <span className='quiet'>Measures</span>
         </Link>;
 
-      let dimensionLabel = <Link to='cubeschema' params={{cubeName: cubeName}}
+      let dimensionLabel = <Link to='cubeschema' params={{databaseName: 
this.state.database, cubeName: cubeName}}
         query={{type: 'dimensions'}}>
           <span className='quiet'>Dimensions</span>
         </Link>;

http://git-wip-us.apache.org/repos/asf/lens/blob/01a561c6/lens-ui/app/components/DatabaseComponent.js
----------------------------------------------------------------------
diff --git a/lens-ui/app/components/DatabaseComponent.js 
b/lens-ui/app/components/DatabaseComponent.js
index 09c9e7b..e99be00 100644
--- a/lens-ui/app/components/DatabaseComponent.js
+++ b/lens-ui/app/components/DatabaseComponent.js
@@ -24,6 +24,7 @@ import DatabaseStore from '../stores/DatabaseStore';
 import AdhocQueryActions from '../actions/AdhocQueryActions';
 import UserStore from '../stores/UserStore';
 import Loader from '../components/LoaderComponent';
+import CubeTree from './CubeTreeComponent';
 import TableTree from './TableTreeComponent';
 
 function getDatabases () {
@@ -37,13 +38,16 @@ class DatabaseComponent extends React.Component {
       databases: [],
       loading: true,
       isCollapsed: false,
-      selectedDatabase: ''
+      selectedDatabase: props.params.databaseName,
     };
     this._onChange = this._onChange.bind(this);
     this.toggle = this.toggle.bind(this);
     this.setDatabase = this.setDatabase.bind(this);
 
     AdhocQueryActions.getDatabases(UserStore.getUserDetails().secretToken);
+    if (this.state.selectedDatabase) {
+      this.setDatabase(this.state.selectedDatabase);
+    }
   }
 
   componentDidMount () {
@@ -74,39 +78,40 @@ class DatabaseComponent extends React.Component {
         <select className='form-control' id='db' onChange={this.setDatabase}>
           <option value=''>Select</option>
           {this.state.databases.map(database => {
-            return <option key={database} value={database}>{database}</option>;
+            return <option key={database} value={database}  selected={database 
== this.state.selectedDatabase}>{database}</option>;
           })}
         </select>
       </div>);
 
+
     if (this.state.loading) {
-      databaseComponent = <Loader size='4px' margin='2px' />;
+      databaseComponent = <Loader size='4px' margin='2px'/>;
     } else if (!this.state.databases.length) {
       databaseComponent = (<div className='alert-danger'
-          style={{padding: '8px 5px'}}>
-          <strong>Sorry, we couldn&#39;t find any databases.</strong>
-        </div>);
+                                style={{padding: '8px 5px'}}>
+        <strong>Sorry, we couldn&#39;t find any databases.</strong>
+      </div>);
     }
 
-    return (
-      <div className='panel panel-default'>
-        <div className='panel-heading'>
-          <h3 className='panel-title'>
-            Tables
-            <span className={collapseClass} onClick={this.toggle}></span>
-          </h3>
-        </div>
-        <div className={panelBodyClassName}>
-          {databaseComponent}
-
-          { this.state.selectedDatabase &&
-            <div>
-              <hr style={{marginTop: '10px', marginBottom: '10px'}}/>
-              <TableTree key={this.state.selectedDatabase}
-                database={this.state.selectedDatabase} />
-            </div>
-          }
-        </div>
+    return (<div>
+        {databaseComponent}
+        {
+          this.state.selectedDatabase &&
+          <div>
+            <hr style={{marginTop: '10px', marginBottom: '10px'}}/>
+            <CubeTree key={this.state.selectedDatabase}
+                      database={this.state.selectedDatabase}/>
+          </div>
+        }
+        {
+          this.state.selectedDatabase &&
+          <div>
+            <hr style={{marginTop: '10px', marginBottom: '10px'}}/>
+            <TableTree key={this.state.selectedDatabase}
+                       database={this.state.selectedDatabase}/>
+          </div>
+        }
+
       </div>
     );
   }
@@ -119,8 +124,15 @@ class DatabaseComponent extends React.Component {
     this.setState({ isCollapsed: !this.state.isCollapsed });
   }
 
-  setDatabase (event) {
-    this.setState({selectedDatabase: event.target.value});
+  setDatabase(event) {
+    var dbName = null;
+    if (typeof(event) == "string") {
+      dbName = event;
+    } else {
+      dbName = event.target.value;
+    }
+    AdhocQueryActions.setDatabase(UserStore.getUserDetails().secretToken, 
dbName);
+    this.setState({databases: getDatabases(), selectedDatabase: dbName, 
loading: false});
   }
 }
 

http://git-wip-us.apache.org/repos/asf/lens/blob/01a561c6/lens-ui/app/components/QueryBoxComponent.js
----------------------------------------------------------------------
diff --git a/lens-ui/app/components/QueryBoxComponent.js 
b/lens-ui/app/components/QueryBoxComponent.js
index ec6a06b..30eb643 100644
--- a/lens-ui/app/components/QueryBoxComponent.js
+++ b/lens-ui/app/components/QueryBoxComponent.js
@@ -393,7 +393,7 @@ class QueryBox extends React.Component {
 
   _onChangeCubeStore () {
     // cubes
-    let cubes = CubeStore.getCubes(); // hashmap
+    let cubes = CubeStore.getCubes(DatabaseStore.currentDatabase()); // hashmap
     Object.keys(cubes).forEach((cubeName) => {
       let cube = cubes[cubeName];
       codeMirrorHints[cubeName] = [];

http://git-wip-us.apache.org/repos/asf/lens/blob/01a561c6/lens-ui/app/components/SidebarComponent.js
----------------------------------------------------------------------
diff --git a/lens-ui/app/components/SidebarComponent.js 
b/lens-ui/app/components/SidebarComponent.js
index 37a2c59..7db1789 100644
--- a/lens-ui/app/components/SidebarComponent.js
+++ b/lens-ui/app/components/SidebarComponent.js
@@ -19,7 +19,6 @@
 
 import React from 'react';
 
-import CubeTree from './CubeTreeComponent';
 import Database from './DatabaseComponent';
 import QueryOperations from './QueryOperationsComponent';
 
@@ -28,8 +27,7 @@ class Sidebar extends React.Component {
     return (
       <section>
         <QueryOperations />
-        <CubeTree />
-        <Database />
+        <Database  {...this.props}/>
       </section>
     );
   }

http://git-wip-us.apache.org/repos/asf/lens/blob/01a561c6/lens-ui/app/components/TableTreeComponent.js
----------------------------------------------------------------------
diff --git a/lens-ui/app/components/TableTreeComponent.js 
b/lens-ui/app/components/TableTreeComponent.js
index 2e62399..9a8351e 100644
--- a/lens-ui/app/components/TableTreeComponent.js
+++ b/lens-ui/app/components/TableTreeComponent.js
@@ -21,6 +21,7 @@ import React from 'react';
 import TreeView from 'react-treeview';
 import { Link } from 'react-router';
 import 'react-treeview/react-treeview.css';
+import ClassNames from 'classnames';
 
 import TableStore from '../stores/TableStore';
 import AdhocQueryActions from '../actions/AdhocQueryActions';
@@ -65,7 +66,8 @@ function getTables (page, filterString, database) {
 
   return {
     totalPages: Math.ceil(allTables.length / pageSize),
-    tables: pageTables
+    tables: pageTables,
+    database: database,
   };
 }
 
@@ -77,7 +79,8 @@ class TableTree extends React.Component {
       totalPages: 0,
       page: 0,
       loading: true,
-      isCollapsed: false
+      isCollapsed: false,
+      database: props.database
     };
     this._onChange = this._onChange.bind(this);
     this.prevPage = this.prevPage.bind(this);
@@ -115,17 +118,15 @@ class TableTree extends React.Component {
     TableStore.removeChangeListener(this._onChange);
   }
 
-  render () {
-    let tableTree = '';
-
+  render() {
     // construct tree
-    tableTree = this.state.tables.map(table => {
-      let label = (<Link to='tableschema' params={{tableName: table.name}}
-        title={table.name} query={{database: this.props.database}}>
-          {table.name}</Link>);
+    let tableTreeInternal = this.state.tables.map(table => {
+      let label = (<Link to='tableschema' params={{databaseName: 
this.state.database, tableName: table.name}}
+                         title={table.name} query={{database: 
this.props.database}}>
+        {table.name}</Link>);
       return (
         <TreeView key={table.name} nodeLabel={label}
-          defaultCollapsed={!table.isLoaded}>
+                  defaultCollapsed={!table.isLoaded}>
 
           {table.isLoaded ? table.columns.map(col => {
             return (
@@ -141,11 +142,11 @@ class TableTree extends React.Component {
 
     // show a loader when tree is loading
     if (this.state.loading) {
-      tableTree = <Loader size='4px' margin='2px' />;
+      tableTreeInternal = <Loader size='4px' margin='2px'/>;
     } else if (!this.state.tables.length) {
-      tableTree = (<div className='alert-danger' style={{padding: '8px 5px'}}>
-          <strong>Sorry, we couldn&#39;t find any.</strong>
-        </div>);
+      tableTreeInternal = (<div className='alert-danger' style={{padding: '8px 
5px'}}>
+        <strong>Sorry, we couldn&#39;t find any.</strong>
+      </div>);
     }
 
     let pagination = this.state.tables.length ?
@@ -162,20 +163,43 @@ class TableTree extends React.Component {
           </div>
         </div>
       ) : null;
-
-    return (
+    let tableTree = (
       <div>
         { !this.state.loading &&
-          <div className='form-group'>
-            <input type='search' className='form-control'
-              placeholder='Type to filter tables'
-              onChange={this._filter.bind(this)}/>
-          </div>
+        <div className='form-group'>
+          <input type='search' className='form-control'
+                 placeholder='Type to filter tables'
+                 onChange={this._filter.bind(this)}/>
+        </div>
         }
 
         {pagination}
 
         <div ref='tableTree' style={{maxHeight: '350px', overflowY: 'auto'}}>
+          {tableTreeInternal}
+        </div>
+      </div>
+    );
+    let collapseClass = ClassNames({
+      'pull-right': true,
+      'glyphicon': true,
+      'glyphicon-chevron-up': !this.state.isCollapsed,
+      'glyphicon-chevron-down': this.state.isCollapsed
+    });
+
+    let panelBodyClassName = ClassNames({
+      'panel-body': true,
+      'hide': this.state.isCollapsed
+    });
+    return (
+      <div className='panel panel-default'>
+        <div className='panel-heading'>
+          <h3 className='panel-title'>
+            Tables
+            <span className={collapseClass} onClick={this.toggle}></span>
+          </h3>
+        </div>
+        <div className={panelBodyClassName} style={{maxHeight: '350px', 
overflowY: 'auto'}}>
           {tableTree}
         </div>
       </div>

http://git-wip-us.apache.org/repos/asf/lens/blob/01a561c6/lens-ui/app/constants/AdhocQueryConstants.js
----------------------------------------------------------------------
diff --git a/lens-ui/app/constants/AdhocQueryConstants.js 
b/lens-ui/app/constants/AdhocQueryConstants.js
index ea8cbd0..7eceb6f 100644
--- a/lens-ui/app/constants/AdhocQueryConstants.js
+++ b/lens-ui/app/constants/AdhocQueryConstants.js
@@ -47,6 +47,9 @@ const AdhocQueryConstants = KeyMirror({
   RECEIVE_DATABASES: null,
   RECEIVE_DATABASES_FAILED: null,
 
+  SELECT_DATABASE: null,
+  SELECT_DATABASE_FAILED: null,
+
   RECEIVE_QUERY_PARAMS_META: null,
 
   SAVE_QUERY_SUCCESS: null,

http://git-wip-us.apache.org/repos/asf/lens/blob/01a561c6/lens-ui/app/stores/CubeStore.js
----------------------------------------------------------------------
diff --git a/lens-ui/app/stores/CubeStore.js b/lens-ui/app/stores/CubeStore.js
index d4825a9..4441e54 100644
--- a/lens-ui/app/stores/CubeStore.js
+++ b/lens-ui/app/stores/CubeStore.js
@@ -24,34 +24,43 @@ import { EventEmitter } from 'events';
 
 // private methods
 function receiveCubes (payload) {
-  payload.cubes && payload.cubes.stringList &&
+  let currentDatabase = payload.database;
+  cubes[currentDatabase] = cubes[currentDatabase] || {};
+  payload.database && payload.cubes && payload.cubes.stringList &&
     payload.cubes.stringList.elements &&
     payload.cubes.stringList.elements.forEach(cube => {
-      if (!cubes[cube]) {
-        cubes[cube] = { name: cube, isLoaded: false };
+      if (!cubes[currentDatabase][cube]) {
+        cubes[currentDatabase][cube] = { name: cube, isLoaded: false };
       }
     });
 }
 
 function receiveCubeDetails (payload) {
+  cubes[payload.database] = cubes[payload.database] || {};
   let cubeDetails = payload.cubeDetails && payload.cubeDetails.x_cube;
-
-  let dimensions = cubeDetails.dim_attributes &&
-    cubeDetails.dim_attributes.dim_attribute;
-  let measures = cubeDetails.measures &&
-    cubeDetails.measures.measure;
-
-  cubes[cubeDetails.name].measures = measures;
-  cubes[cubeDetails.name].dimensions = dimensions;
-  cubes[cubeDetails.name].isLoaded = true;
+  let dimensions = null;
+  let measures = null;
+  if (cubeDetails.type == 'x_base_cube') {
+    dimensions = cubeDetails.dim_attributes &&
+      cubeDetails.dim_attributes.dim_attribute;
+    measures = cubeDetails.measures &&
+      cubeDetails.measures.measure;
+  } else if (cubeDetails.type == 'x_derived_cube') {
+    dimensions = cubeDetails.dim_attr_names && 
cubeDetails.dim_attr_names.attr_name;
+    measures = cubeDetails.measure_names && 
cubeDetails.measure_names.measure_name;
+  }
+  cubes[payload.database][cubeDetails.name] = 
cubes[payload.database][cubeDetails.name] || { name: cubeDetails.name, 
isLoaded: false };
+  cubes[payload.database][cubeDetails.name].measures = measures;
+  cubes[payload.database][cubeDetails.name].dimensions = dimensions;
+  cubes[payload.database][cubeDetails.name].isLoaded = true;
 }
 
 let CHANGE_EVENT = 'change';
 var cubes = {};
-
+var currentDatabase = null;
 let CubeStore = assign({}, EventEmitter.prototype, {
-  getCubes () {
-    return cubes;
+  getCubes (currentDatabase) {
+    return cubes[currentDatabase];
   },
 
   emitChange () {

http://git-wip-us.apache.org/repos/asf/lens/blob/01a561c6/lens-ui/app/stores/DatabaseStore.js
----------------------------------------------------------------------
diff --git a/lens-ui/app/stores/DatabaseStore.js 
b/lens-ui/app/stores/DatabaseStore.js
index b13246e..a18e986 100644
--- a/lens-ui/app/stores/DatabaseStore.js
+++ b/lens-ui/app/stores/DatabaseStore.js
@@ -32,12 +32,14 @@ function receiveDatabases (payload) {
 
 let CHANGE_EVENT = 'change';
 var databases = [];
-
+var currentDatabase = null;
 let DatabaseStore = assign({}, EventEmitter.prototype, {
   getDatabases () {
     return databases;
   },
-
+  currentDatabase() {
+    return currentDatabase;
+  },
   emitChange () {
     this.emit(CHANGE_EVENT);
   },
@@ -57,6 +59,10 @@ AppDispatcher.register((action) => {
       receiveDatabases(action.payload);
       DatabaseStore.emitChange();
       break;
+    case AdhocQueryConstants.SELECT_DATABASE:
+      currentDatabase = action.payload.database;
+      DatabaseStore.emitChange();
+      break;
   }
 });
 

http://git-wip-us.apache.org/repos/asf/lens/blob/01a561c6/lens-ui/server.js
----------------------------------------------------------------------
diff --git a/lens-ui/server.js b/lens-ui/server.js
index 736d862..12b94e7 100644
--- a/lens-ui/server.js
+++ b/lens-ui/server.js
@@ -33,7 +33,7 @@ app.use(logger('dev'));
 app.use(cookieParser());
 
 process.env['NODE_TLS_REJECT_UNAUTHORIZED'] = '0';
-
+process.env['lensserver'] = process.env['lensserver'] || 
'http://0.0.0.0:9999/lensapi/';
 if (!process.env['lensserver']) {
   throw new Error('Specify LENS Server address in `lensserver` argument');
 }

Reply via email to