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);
   }