You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@lens.apache.org by sh...@apache.org on 2015/12/30 08:10:26 UTC
[07/50] [abbrv] lens git commit: LENS-864: LENS - 864
LENS-864: LENS - 864
Project: http://git-wip-us.apache.org/repos/asf/lens/repo
Commit: http://git-wip-us.apache.org/repos/asf/lens/commit/2870be7c
Tree: http://git-wip-us.apache.org/repos/asf/lens/tree/2870be7c
Diff: http://git-wip-us.apache.org/repos/asf/lens/diff/2870be7c
Branch: refs/heads/LENS-581
Commit: 2870be7c8c2dbef92c237878c5faba048d3a139d
Parents: 7b5f4a0
Author: Ankeet Maini <an...@gmail.com>
Authored: Wed Nov 18 17:58:45 2015 +0530
Committer: Rajat Khandelwal <ra...@gmail.com>
Committed: Wed Nov 18 17:58:45 2015 +0530
----------------------------------------------------------------------
lens-ui/app/components/QueryBoxComponent.js | 122 +++++++------
.../app/components/QueryParamRowComponent.js | 176 +++++++++----------
lens-ui/app/components/QueryParamsComponent.js | 72 +++++---
.../components/SavedQueryPreviewComponent.js | 26 +--
4 files changed, 219 insertions(+), 177 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/lens/blob/2870be7c/lens-ui/app/components/QueryBoxComponent.js
----------------------------------------------------------------------
diff --git a/lens-ui/app/components/QueryBoxComponent.js b/lens-ui/app/components/QueryBoxComponent.js
index 6f4eeb7..ec6a06b 100644
--- a/lens-ui/app/components/QueryBoxComponent.js
+++ b/lens-ui/app/components/QueryBoxComponent.js
@@ -21,6 +21,7 @@ import React from 'react';
import ClassNames from 'classnames';
import CodeMirror from 'codemirror';
import assign from 'object-assign';
+import _ from 'lodash';
import 'codemirror/lib/codemirror.css';
import 'codemirror/addon/edit/matchbrackets.js';
import 'codemirror/addon/hint/sql-hint.js';
@@ -74,6 +75,20 @@ function setCode (code) {
}
}
+function getEmptyState () {
+ return {
+ clientMessage: null, // to give user instant ack
+ isRunQueryDisabled: true,
+ serverMessage: null, // type (success or error), text as keys
+ isCollapsed: false,
+ params: null,
+ isModeEdit: false,
+ savedQueryId: null,
+ runImmediately: false,
+ description: ''
+ };
+}
+
// used to populate the query box when user wants to edit a query
// TODO improve this.
// this takes in the query handle and writes the query
@@ -114,16 +129,7 @@ class QueryBox extends React.Component {
this.saveOrUpdate = this.saveOrUpdate.bind(this);
this.runSavedQuery = this.runSavedQuery.bind(this);
- this.state = {
- clientMessage: null, // to give user instant ack
- isRunQueryDisabled: true,
- serverMessage: null, // type (success or error), text as keys
- isCollapsed: false,
- params: null,
- isModeEdit: false,
- savedQueryId: null,
- runImmediately: false
- };
+ this.state = getEmptyState();
}
componentDidMount () {
@@ -184,6 +190,7 @@ class QueryBox extends React.Component {
this.setState({
params: savedQuery.parameters,
savedQueryId: savedQuery.id,
+ description: savedQuery.description,
isModeEdit: true
});
}
@@ -257,7 +264,7 @@ class QueryBox extends React.Component {
{ this.state.params && !!this.state.params.length &&
<QueryParams params={this.state.params} close={this.closeParamBox}
- saveParams={this.saveParams}/>
+ saveParams={this.saveParams} description={this.state.description}/>
}
{ this.state.serverMessage &&
@@ -304,17 +311,40 @@ class QueryBox extends React.Component {
updateQuery (params) {
let query = this._getSavedQueryDetails(params);
if (!query) return;
+
+ var options = {
+ parameters: query.parameters,
+ description: query.description,
+ name: query.name
+ };
+
AdhocQueryActions
- .updateSavedQuery(query.secretToken, query.user, query.query, query.params, this.state.savedQueryId);
- this.setState({ clientMessage: clientMessages.updateQuery });
+ .updateSavedQuery(query.secretToken, query.user, query.query,
+ options, this.state.savedQueryId);
+
+ this.setState({
+ clientMessage: clientMessages.updateQuery,
+ runImmediately: params && params.runImmediately
+ });
}
saveQuery (params) {
let query = this._getSavedQueryDetails(params);
if (!query) return;
+
+ var options = {
+ parameters: query.parameters,
+ description: query.description,
+ name: query.name
+ };
+
AdhocQueryActions
- .saveQuery(query.secretToken, query.user, query.query, query.params);
- this.setState({ clientMessage: clientMessages.saveQuery });
+ .saveQuery(query.secretToken, query.user, query.query, options);
+
+ this.setState({
+ clientMessage: clientMessages.saveQuery,
+ runImmediately: params && params.runImmediately
+ });
}
// internal which is called during save saved query & edit saved query
@@ -329,14 +359,13 @@ class QueryBox extends React.Component {
let user = UserStore.getUserDetails().email;
let query = codeMirror.getValue();
- params = assign({}, params);
- params.name = queryName;
-
return {
secretToken: secretToken,
user: user,
query: query,
- params: params
+ parameters: params && params.parameters,
+ description: params && params.description,
+ name: queryName
};
}
@@ -419,42 +448,47 @@ class QueryBox extends React.Component {
_onChangeSavedQueryStore (hash) {
if (!hash) return;
+ var newState = _.assign({}, this.state);
+
switch (hash.type) {
case 'failure':
- this.state.clientMessage = null;
- this.state.serverMessage = hash.message;
+ newState.clientMessage = null;
+ newState.serverMessage = hash.message;
break;
case 'success':
- this.state.clientMessage = null;
- this.state.serverMessage = hash.message;
- // make the mode of QueryBox back to normal, if it's in Edit
- if (this.state.isModeEdit) {
- this.state.isModeEdit = false;
- }
-
// trigger to fetch the edited from server again
let token = UserStore.getUserDetails().secretToken;
if (hash.id) AdhocQueryActions.getSavedQueryById(token, hash.id);
// means the query was saved successfully.
// run immediately?
- if (this.state.runImmediately && hash.id) {
+ if (newState.runImmediately && hash.id) {
this.runSavedQuery(hash.id);
- this.state.runImmediately = false;
+ newState.runImmediately = false;
}
- // make params null
- this.state.params = null;
-
+ // empty the state, clean the slate
+ setCode('');
+ this.refs.queryName.getDOMNode().value = '';
+ newState = getEmptyState();
+ newState.serverMessage = hash.message;
break;
case 'params':
- this.state.params = hash.params;
+ newState.params = hash.params.map(param => {
+ return {
+ name: param.name,
+ dataType: param.dataType || 'STRING',
+ collectionType: param.collectionType || 'SINGLE',
+ defaultValue: param.defaultValue || null,
+ displayName: param.displayName || param.name
+ };
+ });
break;
}
- this.setState(this.state);
+ this.setState(newState);
}
runSavedQuery (id) {
@@ -472,29 +506,17 @@ class QueryBox extends React.Component {
}
closeParamBox () {
- this.setState({params: null, clientMessage: null});
+ this.cancel();
}
- saveParams (params) { // contains parameters, description et all
- this.state.params = assign(this.state.params, params.parameters);
- this.state.runImmediately = params.runImmediately;
-
- // edit or save new, only state variable will tell
+ saveParams (params) {
!this.state.isModeEdit ? this.saveQuery(params) : this.updateQuery(params);
}
cancel () {
setCode('');
this.refs.queryName.getDOMNode().value = '';
- this.setState({
- clientMessage: null, // to give user instant ack
- isRunQueryDisabled: true,
- serverMessage: null, // type (success or error), text as keys
- isCollapsed: false,
- params: null,
- isModeEdit: false,
- savedQueryId: null
- });
+ this.setState(getEmptyState());
}
}
http://git-wip-us.apache.org/repos/asf/lens/blob/2870be7c/lens-ui/app/components/QueryParamRowComponent.js
----------------------------------------------------------------------
diff --git a/lens-ui/app/components/QueryParamRowComponent.js b/lens-ui/app/components/QueryParamRowComponent.js
index fb5f5da..89c8a8e 100644
--- a/lens-ui/app/components/QueryParamRowComponent.js
+++ b/lens-ui/app/components/QueryParamRowComponent.js
@@ -20,73 +20,53 @@
import React from 'react';
import { Multiselect } from 'react-widgets';
import assign from 'object-assign';
+import _ from 'lodash';
import 'react-widgets/dist/css/core.css';
import 'react-widgets/dist/css/react-widgets.css';
-// returns true/false if the default value is correct
-// and also returns the value
-function validate (val, dataType) {
- // if (dataType === 'NUMBER' && !window.isNaN(val)) return [true, val];
- // if (dataType === 'BOOLEAN' && (val === 'true' || val === 'false')) {
- // return [true, val];
- // }
- // if (dataType === 'STRING' && typeof val === 'string') return [true, val];
-
- return [true, val];
-}
-
class QueryParamRow extends React.Component {
constructor (props) {
super(props);
- // state being decided by mode of use of this component
- // `entryMode` is used by the SavedQueryPreviewComponent,
- // to just add values and run the saved query.
- if (props.entryMode) {
- this.state = assign({}, props.param);
- } else {
- this.state = assign({}, props.param, {
- dataType: 'STRING',
- collectionType: 'SINGLE',
- displayName: props.param.name
- });
- }
-
- this.changeDisplayName = this.changeDisplayName.bind(this);
- this.changeDataType = this.changeDataType.bind(this);
- this.changeCollectionType = this.changeCollectionType.bind(this);
- this.changeDefaultValue = this.changeDefaultValue.bind(this);
- this.addDefaultValue = this.addDefaultValue.bind(this);
- this.preventEnter = this.preventEnter.bind(this);
- }
+ this.state = {
+ paramChange: assign({}, props.param)
+ };
- componentWillReceiveProps (props) {
- this.setState(assign({}, props.param));
+ this._handleChange = this._handleChange.bind(this);
+ this.getDefaultValueInput = this.getDefaultValueInput.bind(this);
}
- componentWillUpdate (props, state) {
- this.props.updateParam({
- name: props.param.name,
- param: state
- });
+ shouldComponentUpdate (newProps, newState) {
+ return !_.isEqual(this.state, newState);
}
render () {
let param = this.props.param;
+ let collectionType = this.state.paramChange.collectionType;
+ let dataType = this.state.paramChange.dataType;
+
+ let collectionTypeBox = (<select className='form-control' required
+ defaultValue='SINGLE' onChange={this._handleChange('ChangeCollectionType')}>
+ <option value='SINGLE'>Single</option>
+ <option value='MULTIPLE'>Multiple</option>
+ </select>);
+
+ let valueBox = this.getDefaultValueInput(collectionType, dataType);
+
return (
<tr>
<td>{param.name}</td>
<td>
{ this.props.entryMode ? param.displayName :
<input type='text' className='form-control' required defaultValue={param.name}
- placeholder='display name' onChange={this.changeDisplayName}/>
+ placeholder='display name' onChange={this._handleChange('ChangeDisplayName')}/>
}
</td>
<td>
{ this.props.entryMode ? param.dataType :
- <select className='form-control' defaultValue='STRING'
- onChange={this.changeDataType}>
+ <select className='form-control' defaultValue={dataType || 'STRING'}
+ onChange={this._handleChange('ChangeDataType')}>
<option value='STRING'>String</option>
<option value='NUMBER'>Number</option>
<option value='BOOLEAN'>Boolean</option>
@@ -95,78 +75,88 @@ class QueryParamRow extends React.Component {
</td>
<td>
{ this.props.entryMode ? param.collectionType :
- <select className='form-control' required defaultValue='SINGLE'
- onChange={this.changeCollectionType}>
- <option value='SINGLE'>Single</option>
- <option value='MULTIPLE'>Multiple</option>
- </select>
+ {collectionTypeBox}
}
</td>
<td>
- { !this.props.entryMode && (this.state.collectionType === 'SINGLE' ?
- <input type='text' className='form-control' required value={this.state.defaultValue}
- placeholder='default value' onChange={this.changeDefaultValue}/> :
- <Multiselect messages={{createNew: 'Enter to add'}}
- onCreate={this.addDefaultValue}
- defaultValue={this.state.defaultValue} onKeyDown={this.preventEnter}
- />
- )}
-
- { this.props.entryMode && (param.collectionType === 'SINGLE' ?
- <input type='text' className='form-control' required value={this.state.defaultValue}
- placeholder='default value' onChange={this.changeDefaultValue}/> :
- <Multiselect messages={{createNew: 'Enter to add'}}
- onCreate={this.addDefaultValue}
- defaultValue={this.state.defaultValue} onKeyDown={this.preventEnter}
- />
- )}
+ {valueBox}
</td>
</tr>
);
}
- // these methods change the default values
- // called by normal input
- changeDefaultValue (e) {
- let val = validate(e.target.value, this.state.dataType);
-
- if (val[0]) this.setState({defaultValue: val[1]});
+ _handleChange (elementType) {
+ return (arg) => {
+ let paramChange;
+ let state = _.assign({}, this.state.paramChange);
+ let val;
+ switch (elementType) {
+ case 'ChangeMultiselect':
+ paramChange = _.assign({}, state, {defaultValue: arg});
+ break;
+
+ case 'ChangeDefaultTextValue':
+ paramChange = _.assign({}, state, {defaultValue: arg.target.value});
+ break;
+
+ case 'AddItemInMultiSelect':
+ this.state.paramChange.defaultValue.push(arg);
+ paramChange = _.assign({}, this.state.paramChange, {
+ //defaultValue: [...this.state.paramChange.defaultValue, item]
+ });
+ break;
+
+ case 'ChangeDataType':
+ val = this.state.paramChange.collectionType === 'SINGLE' ? null : [];
+ paramChange = _.assign({}, state, {
+ dataType: arg.target.value,
+ defaultValue: val,
+ });
+ break;
+
+ case 'ChangeCollectionType':
+ val = arg.target.value === 'MULTIPLE' ? [] : null;
+ paramChange = _.assign({}, state, {
+ collectionType: arg.target.value,
+ defaultValue: val
+ });
+ break;
+
+ case 'ChangeDisplayName':
+ paramChange = _.assign({}, state, {displayName: arg.target.value});
+ break;
+ }
+
+ this.setState({paramChange});
+ this.props.saveParamChanges(paramChange);
+ };
}
- // called my multiselect
- addDefaultValue (item) {
- let val = validate(item, this.state.dataType);
-
- if (val[0]) {
- this.state.defaultValue.push(val[1]);
- this.setState(this.state);
- }
- }
preventEnter (e) {
if (e.keyCode == 13) e.preventDefault();
}
- changeDataType (e) {
- let val = this.state.collectionType === 'SINGLE' ? null : [];
- this.setState({dataType: e.target.value, defaultValue: val});
- }
-
- changeCollectionType (e) {
- let val = e.target.value === 'MULTIPLE' ? [] : null;
- this.setState({defaultValue: val});
- this.setState({collectionType: e.target.value});
- }
-
- changeDisplayName (e) {
- this.setState({displayName: e.target.value});
+ getDefaultValueInput (collectionType, dataType) {
+ let valueBox = null;
+ if (collectionType === 'SINGLE') {
+ valueBox = <input type='text' className='form-control' required value={this.state.paramChange.defaultValue}
+ placeholder='default value' onChange={this._handleChange('ChangeDefaultTextValue')}/>;
+ } else if (collectionType === 'MULTIPLE') {
+ valueBox = <Multiselect messages={{createNew: 'Enter to add'}}
+ onCreate={this._handleChange('AddItemInMultiSelect')} data={this.state.paramChange.defaultValue}
+ onChange={this._handleChange('ChangeMultiselect')}
+ value={this.state.paramChange.defaultValue} onKeyDown={this.preventEnter}
+ />;
+ }
+ return valueBox;
}
}
QueryParamRow.propTypes = {
param: React.PropTypes.object.isRequired,
- updateParam: React.PropTypes.func.isRequired,
+ saveParamChanges: React.PropTypes.func.isRequired,
entryMode: React.PropTypes.boolean
};
http://git-wip-us.apache.org/repos/asf/lens/blob/2870be7c/lens-ui/app/components/QueryParamsComponent.js
----------------------------------------------------------------------
diff --git a/lens-ui/app/components/QueryParamsComponent.js b/lens-ui/app/components/QueryParamsComponent.js
index a49e338..c3325c8 100644
--- a/lens-ui/app/components/QueryParamsComponent.js
+++ b/lens-ui/app/components/QueryParamsComponent.js
@@ -26,28 +26,35 @@ import QueryParamRow from './QueryParamRowComponent';
class QueryParams extends React.Component {
constructor (props) {
super(props);
- this.state = {description: '', childrenParams: {}, runImmediately: false};
+ this.state = {
+ paramChanges: [],
+ runImmediately: false,
+ description: props.description
+ };
this.close = this.close.bind(this);
this.save = this.save.bind(this);
- this.update = this.update.bind(this);
this.handleChange = this.handleChange.bind(this);
this.handleCheck = this.handleCheck.bind(this);
- this._getChildrenParams = this._getChildrenParams.bind(this);
+ this.saveParamChanges = this.saveParamChanges.bind(this);
}
componentWillReceiveProps (props) {
- if (!_.isEqual(props.params, this.props.params)) {
- this.state.childrenParams = {};
- }
+ this.setState({description: props.description, paramChanges: []});
}
render () {
- let params = this.props.params && this.props.params.map((param, index) => {
- return <QueryParamRow key={param.name} param={param} updateParam={this.update}/>;
- });
-
- if (!params) return null;
+ let propParams = this.props.params;
+ if (!propParams) return null;
+
+ let changedParams = this.state.paramChanges;
+ let params = this.mergeParamChanges(propParams, changedParams)
+ .map(param => {
+ return (
+ <QueryParamRow key={param.name} param={param}
+ saveParamChanges={this.saveParamChanges} />
+ );
+ });
return (
<form onSubmit={this.save} style={{padding: '10px', boxShadow: '2px 2px 2px 2px grey',
@@ -72,7 +79,7 @@ class QueryParams extends React.Component {
<div className='form-group'>
<label className='sr-only' htmlFor='queryDescription'>Description</label>
<input type='text' className='form-control' style={{fontWeight: 'normal'}}
- onChange={this.handleChange} id='queryDescription'
+ onChange={this.handleChange} id='queryDescription' value={this.state.description}
placeholder='(Optional description) e.g. This awesome query does magic along with its job.'
/>
</div>
@@ -93,7 +100,8 @@ class QueryParams extends React.Component {
save (e) {
e.preventDefault();
- var parameters = this._getChildrenParams();
+ // merges the initial props and the delta changes done by child components
+ var parameters = this.mergeParamChanges(this.props.params, this.state.paramChanges);
this.props.saveParams({
parameters: parameters,
description: this.state.description,
@@ -101,23 +109,39 @@ class QueryParams extends React.Component {
});
}
- _getChildrenParams () {
- return Object.keys(this.state.childrenParams).map(name => {
- return this.state.childrenParams[name];
- });
- }
-
handleChange (e) {
- this.setState({description: e.target.value});
+ this.setState({ description: e.target.value });
}
handleCheck (e) {
- this.setState({runImmediately: e.target.checked});
+ this.setState({ runImmediately: e.target.checked });
+ }
+
+ mergeParamChanges (original = [], changes = []) {
+ return original.map(originalParam => {
+ let change = changes.filter(changedParam => {
+ return changedParam.name === originalParam.name;
+ });
+ return _.assign({}, originalParam, change[0]);
+ });
}
- // called by the child component {name, param}
- update (param) {
- this.state.childrenParams[param.name] = param.param;
+ saveParamChanges (changedParam) {
+ // getting the param from the paramChanges state.
+ var param = this.state.paramChanges.filter(param => {
+ return param.name === changedParam.name;
+ })[0];
+
+ // apply the changedParam over the above param.
+ var newParam = _.assign({}, param, changedParam);
+
+ // getting all the other changes except the current as
+ // we want to over-write it
+ var newChangedParams = this.state.paramChanges.filter(param => {
+ return param.name !== newParam.name;
+ });
+
+ this.setState({paramChanges: [...newChangedParams, newParam]});
}
}
http://git-wip-us.apache.org/repos/asf/lens/blob/2870be7c/lens-ui/app/components/SavedQueryPreviewComponent.js
----------------------------------------------------------------------
diff --git a/lens-ui/app/components/SavedQueryPreviewComponent.js b/lens-ui/app/components/SavedQueryPreviewComponent.js
index 4f9459a..eea1e47 100644
--- a/lens-ui/app/components/SavedQueryPreviewComponent.js
+++ b/lens-ui/app/components/SavedQueryPreviewComponent.js
@@ -20,6 +20,7 @@
import React from 'react';
import { Link } from 'react-router';
import CodeMirror from 'codemirror';
+import _ from 'lodash';
import 'codemirror/mode/sql/sql.js';
import 'codemirror/addon/runmode/runmode.js';
@@ -30,13 +31,16 @@ import UserStore from '../stores/UserStore';
class SavedQueryPreview extends React.Component {
constructor (props) {
super(props);
- this.state = { showDetail: false, queryParams: {} };
+ this.state = {
+ showDetail: false,
+ queryParams: props.query.parameters.reduce((prev, curr) => {
+ prev[curr.name] = curr;
+ return prev;
+ }, {})
+ };
this.toggleQueryDetails = this.toggleQueryDetails.bind(this);
this.runSavedQuery = this.runSavedQuery.bind(this);
this.update = this.update.bind(this);
- this.props.query && this.props.query.parameters.forEach(param => {
- this.state.queryParams[param.name] = param;
- });
}
render () {
@@ -58,7 +62,7 @@ class SavedQueryPreview extends React.Component {
let params = query && query.parameters.map(param => {
return <QueryParamRowComponent param={param} entryMode={true}
- updateParam={this.update}/>;
+ saveParamChanges={this.update}/>;
});
let paramsTable = !params.length ? null :
@@ -114,15 +118,17 @@ class SavedQueryPreview extends React.Component {
}
update (param) {
- this.state.queryParams[param.name] = param.param;
+ this.setState({
+ queryParams: _.assign({}, this.state.queryParams, {[param.name]: param})
+ });
}
runSavedQuery () {
let secretToken = UserStore.getUserDetails().secretToken;
- let parameters = Object.keys(this.state.queryParams).map(name => {
- let object = {};
- object[name] = this.state.queryParams[name].defaultValue;
- return object;
+ let parameters = Object.keys(this.state.queryParams).map(paramName => {
+ return {
+ [paramName]: this.state.queryParams[paramName].defaultValue
+ };
});
AdhocQueryActions.runSavedQuery(secretToken, this.props.query.id, parameters);
}