You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@lens.apache.org by am...@apache.org on 2016/09/17 05:30:49 UTC

lens git commit: LENS-1303 : Query lists on UI will use time filters

Repository: lens
Updated Branches:
  refs/heads/master 7947acda7 -> b438aa2f2


LENS-1303 : Query lists on UI will use time filters


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

Branch: refs/heads/master
Commit: b438aa2f22992fc0e29f6ec10527959da0cefdf4
Parents: 7947acd
Author: Rajat Khandelwal <pr...@apache.org>
Authored: Sat Sep 17 10:57:37 2016 +0530
Committer: Amareshwari Sriramadasu <am...@apache.org>
Committed: Sat Sep 17 10:57:37 2016 +0530

----------------------------------------------------------------------
 lens-ui/app/actions/AdhocQueryActions.js        |  37 ++++-
 lens-ui/app/adapters/AdhocQueryAdapter.js       |  23 +++
 lens-ui/app/components/CubeSchemaComponent.js   |   2 +-
 .../app/components/QueryOperationsComponent.js  |  12 +-
 lens-ui/app/components/QueryPreviewComponent.js |   4 +
 lens-ui/app/components/QueryResultsComponent.js | 153 +++++++++++++------
 lens-ui/app/constants/AdhocQueryConstants.js    |   3 +
 lens-ui/app/stores/AdhocQueryStore.js           |  68 +++++----
 8 files changed, 216 insertions(+), 86 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/lens/blob/b438aa2f/lens-ui/app/actions/AdhocQueryActions.js
----------------------------------------------------------------------
diff --git a/lens-ui/app/actions/AdhocQueryActions.js b/lens-ui/app/actions/AdhocQueryActions.js
index 38f2794..421f7ea 100644
--- a/lens-ui/app/actions/AdhocQueryActions.js
+++ b/lens-ui/app/actions/AdhocQueryActions.js
@@ -288,7 +288,42 @@ let AdhocQueryActions = {
         });
       });
   },
-
+  getQueryHandles (secretToken, email, options) {
+    AdhocQueryAdapter.getQueryHandles(secretToken, email, options)
+      .then(function (handles) {
+        AppDispatcher.dispatch({
+          actionType: AdhocQueryConstants.RECEIVE_QUERY_HANDLES,
+          payload: { handles: handles }
+        });
+      }, function (error) {
+        AppDispatcher.dispatch({
+          actionType: AdhocQueryConstants.RECEIVE_QUERY_HANDLES_FAILED,
+          payload: {
+            responseCode: error.status,
+            responseMessage: error.statusText
+          }
+        });
+      });
+  },
+  getQueriesDetails (secretToken, handles) {
+    if (handles && handles.length) {
+      AdhocQueryAdapter.getQueriesDetails(secretToken, handles)
+        .then(function (queries) {
+          AppDispatcher.dispatch({
+            actionType: AdhocQueryConstants.RECEIVE_QUERIES,
+            payload: {queries: queries}
+          });
+        }, function (error) {
+          AppDispatcher.dispatch({
+            actionType: AdhocQueryConstants.RECEIVE_QUERIES_FAILED,
+            payload: {
+              responseCode: error.status,
+              responseMessage: error.statusText
+            }
+          });
+        });
+    }
+  },
   getQuery (secretToken, handle) {
     AdhocQueryAdapter.getQuery(secretToken, handle)
       .then(function (query) {

http://git-wip-us.apache.org/repos/asf/lens/blob/b438aa2f/lens-ui/app/adapters/AdhocQueryAdapter.js
----------------------------------------------------------------------
diff --git a/lens-ui/app/adapters/AdhocQueryAdapter.js b/lens-ui/app/adapters/AdhocQueryAdapter.js
index a54274f..9e3cc45 100644
--- a/lens-ui/app/adapters/AdhocQueryAdapter.js
+++ b/lens-ui/app/adapters/AdhocQueryAdapter.js
@@ -150,6 +150,29 @@ let AdhocQueryAdapter = {
         }));
       });
   },
+  getQueryHandles (secretToken, email, options) {
+    let queryOptions = {};
+    queryOptions.sessionid = secretToken;
+    queryOptions.user = email;
+    var state;
+    if (options && options.state) {
+      state = options.state.toUpperCase();
+    }
+    let handlesUrl = baseUrl + urls.query + '?sessionid=' + secretToken + '&user=' +
+      email;
+    if (state) handlesUrl += '&state=' + state;
+    if (options.fromDate) handlesUrl += "&fromDate="+options.fromDate;
+    if (options.toDate) handlesUrl += "&toDate="+options.toDate;
+    return BaseAdapter.get(handlesUrl);
+  },
+  getQueriesDetails (secretToken, handles) {
+    let url = baseUrl + urls.query + '?sessionid=' + secretToken;
+    return Promise.all(handles.map((handle) => {
+      let queryUrl = baseUrl + urls.query + '/' + handle +
+        '?sessionid=' + secretToken + '&queryHandle=' + handle;
+      return BaseAdapter.get(queryUrl);
+    }));
+  },
 
   getQueryResult (secretToken, handle, queryMode) {
     // on page refresh, the store won't have queryMode so fetch query

http://git-wip-us.apache.org/repos/asf/lens/blob/b438aa2f/lens-ui/app/components/CubeSchemaComponent.js
----------------------------------------------------------------------
diff --git a/lens-ui/app/components/CubeSchemaComponent.js b/lens-ui/app/components/CubeSchemaComponent.js
index 9c23b9f..6a2b7af 100644
--- a/lens-ui/app/components/CubeSchemaComponent.js
+++ b/lens-ui/app/components/CubeSchemaComponent.js
@@ -182,7 +182,7 @@ function constructExpressionTable(cubeName, expressions) {
   return (
     <div className='table-responsive'>
       <table className='table table-striped'>
-        <caption className='bg-primary text-center'>Join Chains</caption>
+        <caption className='bg-primary text-center'>Expressions</caption>
         <thead>{header}</thead>
         <tbody>{table}</tbody>
       </table>

http://git-wip-us.apache.org/repos/asf/lens/blob/b438aa2f/lens-ui/app/components/QueryOperationsComponent.js
----------------------------------------------------------------------
diff --git a/lens-ui/app/components/QueryOperationsComponent.js b/lens-ui/app/components/QueryOperationsComponent.js
index e4cc1e7..fc43e9d 100644
--- a/lens-ui/app/components/QueryOperationsComponent.js
+++ b/lens-ui/app/components/QueryOperationsComponent.js
@@ -56,24 +56,24 @@ class QueryOperations extends React.Component {
         <div className={panelBodyClassName}>
           <ul style={{listStyle: 'none', paddingLeft: '0px',
             marginBottom: '0px'}}>
-            <li><Link to='results'>All</Link></li>
+            <li><Link to='results' query={{fromDate: 'now.day-2days'}}>All</Link></li>
             <li>
-              <Link to='results' query={{category: 'running'}}>
+              <Link to='results' query={{state: 'running'}}>
                 Running
               </Link>
             </li>
             <li>
-              <Link to='results' query={{category: 'successful'}}>
-                Completed
+              <Link to='results' query={{state: 'successful', fromDate: 'now.day-2days'}}>
+                Successful
               </Link>
             </li>
             <li>
-              <Link to='results' query={{category: 'queued'}}>
+              <Link to='results' query={{state: 'queued'}}>
                 Queued
               </Link>
             </li>
             <li>
-              <Link to='results' query={{category: 'failed'}}>
+              <Link to='results' query={{state: 'failed', fromDate: 'now.day-2days'}}>
                 Failed
               </Link>
             </li>

http://git-wip-us.apache.org/repos/asf/lens/blob/b438aa2f/lens-ui/app/components/QueryPreviewComponent.js
----------------------------------------------------------------------
diff --git a/lens-ui/app/components/QueryPreviewComponent.js b/lens-ui/app/components/QueryPreviewComponent.js
index a29f2d8..3681399 100644
--- a/lens-ui/app/components/QueryPreviewComponent.js
+++ b/lens-ui/app/components/QueryPreviewComponent.js
@@ -108,6 +108,10 @@ class QueryPreview extends React.Component {
             paddingBottom: '0px'}} key={'preview' + handle}>
               <div className='row'>
                 <div className='col-lg-4 col-sm-4'>
+                  <span className='text-muted'>Handle </span>
+                  <strong>{ query.queryHandle.handleId || 'Unknown'}</strong>
+                </div>
+                <div className='col-lg-4 col-sm-4'>
                   <span className='text-muted'>Name </span>
                   <strong>{ query.queryName || 'Not specified'}</strong>
                 </div>

http://git-wip-us.apache.org/repos/asf/lens/blob/b438aa2f/lens-ui/app/components/QueryResultsComponent.js
----------------------------------------------------------------------
diff --git a/lens-ui/app/components/QueryResultsComponent.js b/lens-ui/app/components/QueryResultsComponent.js
index 01f0e30..eed200b 100644
--- a/lens-ui/app/components/QueryResultsComponent.js
+++ b/lens-ui/app/components/QueryResultsComponent.js
@@ -1,21 +1,21 @@
 /**
-* Licensed to the Apache Software Foundation (ASF) under one
-* or more contributor license agreements. See the NOTICE file
-* distributed with this work for additional information
-* regarding copyright ownership. The ASF licenses this file
-* to you under the Apache License, Version 2.0 (the
-* "License"); you may not use this file except in compliance
-* with the License. You may obtain a copy of the License at
-*
-* http://www.apache.org/licenses/LICENSE-2.0
-*
-* Unless required by applicable law or agreed to in writing,
-* software distributed under the License is distributed on an
-* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-* KIND, either express or implied. See the License for the
-* specific language governing permissions and limitations
-* under the License.
-*/
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
 
 import React from 'react';
 
@@ -25,58 +25,68 @@ import UserStore from '../stores/UserStore';
 import AdhocQueryActions from '../actions/AdhocQueryActions';
 import QueryPreview from './QueryPreviewComponent';
 
-// this method fetches the results based on props.query.category
-function getResults (props) {
-  let email = UserStore.getUserDetails().email;
-  let secretToken = UserStore.getUserDetails().secretToken;
-
-  if (props.query.category) {
-    // fetch either running or completed results
-    AdhocQueryActions
-      .getQueries(secretToken, email, { state: props.query.category });
-  } else {
-    // fetch all
-    AdhocQueryActions.getQueries(secretToken, email);
-  }
+// this method fetches the results based on props.query.state
+function getResults(query) {
+  AdhocQueryActions
+    .getQueryHandles(UserStore.getUserDetails().secretToken, UserStore.getUserDetails().email, query);
 }
 
-function getQueries () {
-  return AdhocQueryStore.getQueries();
+function getQueryHandles() {
+  return AdhocQueryStore.getQueryHandles();
 }
 
 class QueryResults extends React.Component {
-  constructor (props) {
+  constructor(props) {
     super(props);
-    this.state = { queries: {}, queriesReceived: false };
+    this.state = {queries: {}, queriesReceived: false};
     this._onChange = this._onChange.bind(this);
-
-    getResults(props);
+    this.adjustRange = this.adjustRange.bind(this);
+    getResults(props.query);
   }
 
-  componentDidMount () {
+  componentDidMount() {
     AdhocQueryStore.addChangeListener(this._onChange);
   }
 
-  componentWillUnmount () {
+  componentWillUnmount() {
     AdhocQueryStore.removeChangeListener(this._onChange);
   }
 
-  componentWillReceiveProps (props) {
-    getResults(props);
+  componentWillReceiveProps(props) {
+    getResults(props.query);
     this.setState({queries: {}, queriesReceived: false});
   }
+  fetchDetailsAndSetTimeout(handles) {
+    AdhocQueryActions.getQueriesDetails(UserStore.getUserDetails().secretToken, handles);
+  }
+  adjustRange(event) {
+    event.preventDefault();
+    let query = JSON.parse(JSON.stringify(this.props.query));
+    if (this.refs.fromDate.getDOMNode().value) {
+      query.fromDate = this.refs.fromDate.getDOMNode().value;
+    } else {
+      delete query['fromDate'];
+    }
+    if (this.refs.toDate.getDOMNode().value) {
+      query.toDate = this.refs.toDate.getDOMNode().value;
+    } else {
+      delete query['toDate'];
+    }
+    var { router } = this.context;
+    router.transitionTo('results', {}, query);
+  }
 
-  render () {
+  render() {
     let queries = '';
 
     let queryMap = this.state.queries;
+    let queriesToRefresh = []
     queries = Object.keys(queryMap)
-      .sort(function (a, b) {
-        return queryMap[b].submissionTime - queryMap[a].submissionTime;
-      })
       .map((queryHandle) => {
         let query = queryMap[queryHandle];
-
+        if (query.status.status == "RUNNING" || query.status.status == "QUEUED") {
+          queriesToRefresh.push(query.queryHandle.handleId);
+        }
         return (
           <QueryPreview key={query.queryHandle.handleId} {...query} />
         );
@@ -91,18 +101,28 @@ class QueryResults extends React.Component {
     let queriesLength = Object.keys(this.state.queries).length;
 
     if (!queriesLength && !this.state.queriesReceived) {
-      queries = <Loader size='8px' margin='2px' />;
+      queries = <Loader size='8px' margin='2px'/>;
     } else if (!queriesLength && this.state.queriesReceived) {
       queries = <div className='alert alert-danger'>
         <strong>Sorry</strong>, there were no queries to be shown.
       </div>;
     }
-
+    if (queriesToRefresh && queriesToRefresh.length) {
+      // refresh in 5 seconds
+      setTimeout(this.fetchDetailsAndSetTimeout, 5000, queriesToRefresh);
+    }
     return (
       <section>
         <div style={{border: '1px solid #dddddd', borderRadius: '4px',
           padding: '0px 8px 8px 8px'}}>
           <h3 style={{margin: '8px 10px'}}>Results</h3>
+          <form className='form-range' onSubmit={this.adjustRange}>
+            <input ref='fromDate' required={false} defaultValue={this.props.query.fromDate} id='fromDate'
+                   placeholder='now-30years' autoFocus/>
+            <input ref='toDate' required={false} defaultValue={this.props.query.toDate} id='toDate' placeholder='now'
+                   autoFocus/>
+            <button className='btn btn-primary' type='submit'>Fetch</button>
+          </form>
           <hr style={{marginTop: '6px'}}/>
           <div>
             {queries}
@@ -112,9 +132,44 @@ class QueryResults extends React.Component {
     );
   }
 
-  _onChange () {
-    this.setState({queries: getQueries(), queriesReceived: true});
+  _onChange() {
+    let handles = getQueryHandles();
+    let queries = handles.map((handle) => (
+      AdhocQueryStore.getQueryDetails(handle) || {
+        "queryHandle": {
+          "handleId": handle
+        },
+        "userQuery": handle,
+        //"submittedUser": undefined,
+        //"priority": "VERY_LOW",
+        //"isPersistent": true,
+        //"selectedDriverName": "hive/prod",
+        //"driverQuery": "cube select ...",
+        "status": {
+          "progress": -1.0,
+          "status": "UNKNOWN"
+          //"isResultSetAvailable": false,
+          //"errorMessage": "Query execution failed!"
+        },
+        //"queryConf": {},
+        //"submissionTime": 1468403280197,
+        //"launchTime": 1468403284328,
+        //"driverStartTime": 1468403280581,
+        //"driverFinishTime": 1468403350769,
+        //"finishTime": 1468403373582,
+        //"closedTime": 0,
+        "queryName": "Loading..."
+      }
+    ));
+    this.setState({queries: queries, queriesReceived: true});
+    AdhocQueryActions.getQueriesDetails(UserStore.getUserDetails().secretToken,
+      handles.filter(handle=>(!(AdhocQueryStore.getQueryDetails(handle)))));
   }
 }
 
+QueryResults.contextTypes = {
+  router: React.PropTypes.func
+};
+
+
 export default QueryResults;

http://git-wip-us.apache.org/repos/asf/lens/blob/b438aa2f/lens-ui/app/constants/AdhocQueryConstants.js
----------------------------------------------------------------------
diff --git a/lens-ui/app/constants/AdhocQueryConstants.js b/lens-ui/app/constants/AdhocQueryConstants.js
index 7eceb6f..2ba42d3 100644
--- a/lens-ui/app/constants/AdhocQueryConstants.js
+++ b/lens-ui/app/constants/AdhocQueryConstants.js
@@ -32,6 +32,9 @@ const AdhocQueryConstants = KeyMirror({
   RECEIVE_QUERIES: null,
   RECEIVE_QUERIES_FAILED: null,
 
+  RECEIVE_QUERY_HANDLES: null,
+  RECEIVE_QUERY_HANDLES_FAILED: null,
+
   RECEIVE_QUERY_RESULT: null,
   RECEIVE_QUERY_RESULT_FAILED: null,
 

http://git-wip-us.apache.org/repos/asf/lens/blob/b438aa2f/lens-ui/app/stores/AdhocQueryStore.js
----------------------------------------------------------------------
diff --git a/lens-ui/app/stores/AdhocQueryStore.js b/lens-ui/app/stores/AdhocQueryStore.js
index d8891c2..99aa2f1 100644
--- a/lens-ui/app/stores/AdhocQueryStore.js
+++ b/lens-ui/app/stores/AdhocQueryStore.js
@@ -1,21 +1,21 @@
 /**
-* Licensed to the Apache Software Foundation (ASF) under one
-* or more contributor license agreements. See the NOTICE file
-* distributed with this work for additional information
-* regarding copyright ownership. The ASF licenses this file
-* to you under the Apache License, Version 2.0 (the
-* "License"); you may not use this file except in compliance
-* with the License. You may obtain a copy of the License at
-*
-* http://www.apache.org/licenses/LICENSE-2.0
-*
-* Unless required by applicable law or agreed to in writing,
-* software distributed under the License is distributed on an
-* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-* KIND, either express or implied. See the License for the
-* specific language governing permissions and limitations
-* under the License.
-*/
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
 
 import assign from 'object-assign';
 import { EventEmitter } from 'events';
@@ -33,7 +33,7 @@ var adhocDetails = {
   dbName: Config.dbName
 };
 
-function receiveQueryHandle (payload) {
+function receiveQueryHandle(payload) {
   if (typeof payload.queryHandle === 'string') {
     adhocDetails.queryHandle = payload.queryHandle;
     return;
@@ -44,23 +44,22 @@ function receiveQueryHandle (payload) {
   adhocDetails.queryHandle = id;
 }
 
-function receiveQueries (payload) {
-  let queries = payload.queries;
-  let queryObjects = {};
-
-  queries.forEach((query) => {
-    queryObjects[query.lensQuery.queryHandle.handleId] = query.lensQuery;
+function receiveQueries(payload) {
+  adhocDetails.queries = adhocDetails.queries || {};
+  payload.queries.forEach((query) => {
+    adhocDetails.queries[query.lensQuery.queryHandle.handleId] = query.lensQuery;
   });
-
-  adhocDetails.queries = queryObjects;
+}
+function receiveQueryHandles(payload) {
+  adhocDetails.handles = payload.handles.map(handle=>handle.queryHandle.handleId);
 }
 
-function receiveQuery (payload) {
+function receiveQuery(payload) {
   let query = payload.query;
   adhocDetails.queries[query.queryHandle.handleId] = query;
 }
 
-function receiveQueryResult (payload) {
+function receiveQueryResult(payload) {
   let queryResult = {};
   queryResult.type = payload && payload.type;
 
@@ -83,7 +82,12 @@ let AdhocQueryStore = assign({}, EventEmitter.prototype, {
   getQueries () {
     return adhocDetails.queries;
   },
-
+  getQueryHandles () {
+    return adhocDetails.handles;
+  },
+  getQueryDetails (handle) {
+    return adhocDetails.queries[handle];
+  },
   getQueryResult (handle) {
     return adhocDetails.queryResults[handle];
   },
@@ -121,6 +125,11 @@ AppDispatcher.register((action) => {
       AdhocQueryStore.emitChange();
       break;
 
+    case AdhocQueryConstants.RECEIVE_QUERY_HANDLES:
+      receiveQueryHandles(action.payload);
+      AdhocQueryStore.emitChange();
+      break;
+
     case AdhocQueryConstants.RECEIVE_QUERY_RESULT:
       receiveQueryResult(action.payload);
       AdhocQueryStore.emitChange();
@@ -132,6 +141,7 @@ AppDispatcher.register((action) => {
       break;
 
     case AdhocQueryConstants.RECEIVE_QUERY_HANDLE_FAILED:
+    case AdhocQueryConstants.RECEIVE_QUERY_HANDLES_FAILED:
       AdhocQueryStore.emitChange(action.payload);
       break;
   }