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 <pro...@apache.org> Authored: Sat Sep 17 10:57:37 2016 +0530 Committer: Amareshwari Sriramadasu <amareshw...@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; }