You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@lens.apache.org by pr...@apache.org on 2016/06/17 06:39:57 UTC
lens git commit: LENS-1182: Lens UI Should set database and refresh
cubes pane on db switch
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 <pr...@apache.org>
Authored: Fri Jun 17 12:09:45 2016 +0530
Committer: Rajat Khandelwal <ra...@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't find any databases.</strong>
- </div>);
+ style={{padding: '8px 5px'}}>
+ <strong>Sorry, we couldn'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't find any.</strong>
- </div>);
+ tableTreeInternal = (<div className='alert-danger' style={{padding: '8px 5px'}}>
+ <strong>Sorry, we couldn'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');
}