Repository: ambari
Updated Branches:
  refs/heads/branch-2.5 40e60bde8 -> f5b464999


AMBARI-19522. Hive View 2.0: Saving worksheet as saved query (pallavkul)


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

Branch: refs/heads/branch-2.5
Commit: f5b464999dad6674bb7b5b328d75b226dd27f317
Parents: 40e60bd
Author: pallavkul <[email protected]>
Authored: Mon Jan 16 14:21:43 2017 +0530
Committer: pallavkul <[email protected]>
Committed: Mon Jan 16 14:23:33 2017 +0530

----------------------------------------------------------------------
 .../src/main/resources/ui/app/adapters/job.js   |  6 ++
 .../resources/ui/app/adapters/saved-query.js    | 26 ++++++
 .../resources/ui/app/components/query-editor.js |  2 +
 .../ui/app/components/query-result-table.js     | 28 +++++-
 .../resources/ui/app/components/save-hdfs.js    | 52 +++++++++++
 .../main/resources/ui/app/models/saved-query.js | 29 ++++++
 .../main/resources/ui/app/models/worksheet.js   |  3 +-
 .../src/main/resources/ui/app/routes/queries.js |  4 -
 .../resources/ui/app/routes/queries/query.js    | 93 +++++++++++++++++---
 .../resources/ui/app/routes/savedqueries.js     | 79 +++++++++++++++++
 .../src/main/resources/ui/app/services/jobs.js  | 26 ++++++
 .../src/main/resources/ui/app/services/query.js | 12 +++
 .../resources/ui/app/services/saved-queries.js  | 52 +++++++++++
 .../src/main/resources/ui/app/styles/app.scss   |  2 +-
 .../templates/components/query-result-table.hbs | 29 ++++++
 .../ui/app/templates/components/save-hdfs.hbs   | 37 ++++++++
 .../ui/app/templates/queries/query.hbs          | 88 +++++++++++++-----
 .../resources/ui/app/templates/savedqueries.hbs | 52 +++++++++++
 18 files changed, 577 insertions(+), 43 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/f5b46499/contrib/views/hive20/src/main/resources/ui/app/adapters/job.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive20/src/main/resources/ui/app/adapters/job.js 
b/contrib/views/hive20/src/main/resources/ui/app/adapters/job.js
index 8ccd7ad..e2f342e 100644
--- a/contrib/views/hive20/src/main/resources/ui/app/adapters/job.js
+++ b/contrib/views/hive20/src/main/resources/ui/app/adapters/job.js
@@ -27,5 +27,11 @@ export default ApplicationAdapter.extend({
   getQuery(job) {
     let queryUrl = this.buildURL() + "/file" + encodeURI(job.get('queryFile'));
     console.log(queryUrl);
+  },
+
+  saveToHDFS(jobId, path){
+    let resultUrl = this.urlForFindRecord(jobId, 
'job').replace('/resources','')  + 
"/results/csv/saveToHDFS?commence=true&file=" + path + ".csv";
+    return this.ajax(resultUrl, 'GET');
   }
+
 });

http://git-wip-us.apache.org/repos/asf/ambari/blob/f5b46499/contrib/views/hive20/src/main/resources/ui/app/adapters/saved-query.js
----------------------------------------------------------------------
diff --git 
a/contrib/views/hive20/src/main/resources/ui/app/adapters/saved-query.js 
b/contrib/views/hive20/src/main/resources/ui/app/adapters/saved-query.js
new file mode 100644
index 0000000..5ee757b
--- /dev/null
+++ b/contrib/views/hive20/src/main/resources/ui/app/adapters/saved-query.js
@@ -0,0 +1,26 @@
+/**
+ * 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 Ember from 'ember';
+import ApplicationAdapter from './application';
+
+export default ApplicationAdapter.extend({
+  buildURL(){
+    return this._super(...arguments).replace('/resources','') + 
'/savedQueries/';
+  }
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/f5b46499/contrib/views/hive20/src/main/resources/ui/app/components/query-editor.js
----------------------------------------------------------------------
diff --git 
a/contrib/views/hive20/src/main/resources/ui/app/components/query-editor.js 
b/contrib/views/hive20/src/main/resources/ui/app/components/query-editor.js
index b42c495..27d43d5 100644
--- a/contrib/views/hive20/src/main/resources/ui/app/components/query-editor.js
+++ b/contrib/views/hive20/src/main/resources/ui/app/components/query-editor.js
@@ -21,6 +21,7 @@ import Ember from 'ember';
 export default Ember.Component.extend({
 
   tagName: "query-editor",
+  readOnly: false,
 
   _initializeEditor: function() {
 
@@ -41,6 +42,7 @@ export default Ember.Component.extend({
       lineNumbers: true,
       matchBrackets : true,
       autofocus: true,
+      readOnly: self.get('readOnly'),
       extraKeys: {'Ctrl-Space': 'autocomplete'}
     }));
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/f5b46499/contrib/views/hive20/src/main/resources/ui/app/components/query-result-table.js
----------------------------------------------------------------------
diff --git 
a/contrib/views/hive20/src/main/resources/ui/app/components/query-result-table.js
 
b/contrib/views/hive20/src/main/resources/ui/app/components/query-result-table.js
index 17df66d..429dfb3 100644
--- 
a/contrib/views/hive20/src/main/resources/ui/app/components/query-result-table.js
+++ 
b/contrib/views/hive20/src/main/resources/ui/app/components/query-result-table.js
@@ -24,6 +24,8 @@ export default Ember.Component.extend({
 
   classNames: ['query-result-table', 'clearfix'],
 
+  jobId: null,
+
   queryResult: {'schema' :[], 'rows' :[]},
 
   columns: Ember.computed('queryResult', function() {
@@ -63,14 +65,17 @@ export default Ember.Component.extend({
     return new Table(this.get('columns'), this.get('rows'));
   }),
 
+  showSaveHdfsModal:false,
+
+  showDownloadCsvModal:false,
+
   actions: {
     onScrolledToBottom() {
-      //this.send('goNextPage');
-      console.log('hook for INFINITE scroll');
+      //console.log('hook for INFINITE scroll');
     },
 
     onColumnClick(column) {
-      console.log('I am in onColumnClick');
+      //console.log('I am in onColumnClick');
     },
     goNextPage(){
       this.sendAction('goNextPage');
@@ -80,6 +85,23 @@ export default Ember.Component.extend({
     },
     expandQueryResultPanel(){
       this.sendAction('expandQueryResultPanel');
+    },
+
+    openSaveHdfsModal(){
+      this.set('showSaveHdfsModal',true)
+    },
+
+    closeSaveHdfsModal(){
+      this.set('showSaveHdfsModal',false)
+    },
+
+    saveToHDFS(jobId, pathName){
+      console.log('saveToHDFS with jobId == ', jobId );
+      console.log('saveToHDFS with pathName == ', pathName );
+
+      this.sendAction('saveToHDFS', jobId,  pathName);
+
+
     }
 
   }

http://git-wip-us.apache.org/repos/asf/ambari/blob/f5b46499/contrib/views/hive20/src/main/resources/ui/app/components/save-hdfs.js
----------------------------------------------------------------------
diff --git 
a/contrib/views/hive20/src/main/resources/ui/app/components/save-hdfs.js 
b/contrib/views/hive20/src/main/resources/ui/app/components/save-hdfs.js
new file mode 100644
index 0000000..05b3b33
--- /dev/null
+++ b/contrib/views/hive20/src/main/resources/ui/app/components/save-hdfs.js
@@ -0,0 +1,52 @@
+/**
+ * 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 Ember from 'ember';
+
+export default Ember.Component.extend({
+
+  label: null,
+  confirmText: 'Confirm',
+  rejectText: 'Reject',
+
+  jobId: 0,
+
+  savePathName: Ember.computed('jobId', function() {
+    return 'Worksheet_' + this.get('jobId');
+  }),
+
+  labelIcon: null,
+  confirmIcon: null,
+  rejectIcon: null,
+
+  closable: true,
+  titleClass: 'primary',
+  confirmClass: 'primary',
+  rejectClass: 'default',
+
+  actions: {
+    confirm() {
+      let pathName = $("input.path-name").val();
+      this.sendAction('confirm', this.get('jobId'), pathName);
+    },
+
+    reject() {
+      this.sendAction('reject');
+    }
+  }
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/f5b46499/contrib/views/hive20/src/main/resources/ui/app/models/saved-query.js
----------------------------------------------------------------------
diff --git 
a/contrib/views/hive20/src/main/resources/ui/app/models/saved-query.js 
b/contrib/views/hive20/src/main/resources/ui/app/models/saved-query.js
new file mode 100644
index 0000000..44536af
--- /dev/null
+++ b/contrib/views/hive20/src/main/resources/ui/app/models/saved-query.js
@@ -0,0 +1,29 @@
+/**
+ * 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 DS from 'ember-data';
+
+var Model = DS.Model.extend({
+  dataBase: DS.attr('string'),
+  title: DS.attr('string'),
+  queryFile: DS.attr('string'),
+  owner: DS.attr('string'),
+  shortQuery: DS.attr('string')
+});
+
+export default Model;

http://git-wip-us.apache.org/repos/asf/ambari/blob/f5b46499/contrib/views/hive20/src/main/resources/ui/app/models/worksheet.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive20/src/main/resources/ui/app/models/worksheet.js 
b/contrib/views/hive20/src/main/resources/ui/app/models/worksheet.js
index d254ed1..59395e6 100644
--- a/contrib/views/hive20/src/main/resources/ui/app/models/worksheet.js
+++ b/contrib/views/hive20/src/main/resources/ui/app/models/worksheet.js
@@ -32,5 +32,6 @@ export default DS.Model.extend({
   currentJobData: DS.attr({defaultValue: null}),
   hidePreviousButton: DS.attr('boolean', { defaultValue: true}),
   selectedTablesModels: DS.attr(),
-  selectedMultiDb: DS.attr()
+  selectedMultiDb: DS.attr(),
+  queryFile: DS.attr('string', {defaultValue: ""})
 });

http://git-wip-us.apache.org/repos/asf/ambari/blob/f5b46499/contrib/views/hive20/src/main/resources/ui/app/routes/queries.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive20/src/main/resources/ui/app/routes/queries.js 
b/contrib/views/hive20/src/main/resources/ui/app/routes/queries.js
index 2346345..d9f0360 100644
--- a/contrib/views/hive20/src/main/resources/ui/app/routes/queries.js
+++ b/contrib/views/hive20/src/main/resources/ui/app/routes/queries.js
@@ -69,10 +69,6 @@ export default Ember.Route.extend({
       this.set('controller.worksheets', this.store.peekAll('worksheet'));
 
       this.transitionTo('queries.query', localWs.title);
-    },
-
-    saveWorksheet(){
-      // Here we will save the worksheet with some title.
     }
 
   }

http://git-wip-us.apache.org/repos/asf/ambari/blob/f5b46499/contrib/views/hive20/src/main/resources/ui/app/routes/queries/query.js
----------------------------------------------------------------------
diff --git 
a/contrib/views/hive20/src/main/resources/ui/app/routes/queries/query.js 
b/contrib/views/hive20/src/main/resources/ui/app/routes/queries/query.js
index 5eac78a..d4c82fa 100644
--- a/contrib/views/hive20/src/main/resources/ui/app/routes/queries/query.js
+++ b/contrib/views/hive20/src/main/resources/ui/app/routes/queries/query.js
@@ -21,6 +21,8 @@ import Ember from 'ember';
 export default Ember.Route.extend({
 
   query: Ember.inject.service(),
+  jobs: Ember.inject.service(),
+  savedQueries: Ember.inject.service(),
 
   beforeModel(){
     let existingWorksheets = this.store.peekAll('worksheet');
@@ -30,9 +32,7 @@ export default Ember.Route.extend({
   },
 
   afterModel(model) {
-
     let dbmodel = this.store.findAll('database');
-
     if (dbmodel.get('length') > 0) {
       this.selectDatabase(dbmodel);
     }
@@ -48,6 +48,10 @@ export default Ember.Route.extend({
 
     this._super(...arguments);
 
+    controller.set('showWorksheetModal',false);
+    controller.set('worksheetModalSuccess',false);
+    controller.set('worksheetModalFail',false);
+
     let self = this;
     let alldatabases = this.store.findAll('database');
 
@@ -61,7 +65,8 @@ export default Ember.Route.extend({
     selectedTablesModels.pushObject(
       {
         'dbname': selecteDBName ,
-        'tables': this.store.query('table', {databaseId: selecteDBName})
+        'tables': this.store.query('table', {databaseId: selecteDBName}),
+        'isSelected': true
       }
     )
 
@@ -74,6 +79,7 @@ export default Ember.Route.extend({
     controller.set('isQueryRunning', false);
     controller.set('currentQuery', model.get('query'));
     controller.set('queryResult', model.get('queryResult'));
+    controller.set('currentJobId', null);
 
   },
 
@@ -86,11 +92,12 @@ export default Ember.Route.extend({
       let selectedTablesModels =[];
       let selectedMultiDb = [];
 
-      selectedDBs.forEach(function(db){
+      selectedDBs.forEach(function(db, index){
         selectedTablesModels.pushObject(
           {
             'dbname': db ,
-            'tables':self.store.query('table', {databaseId: db})
+            'tables':self.store.query('table', {databaseId: db}),
+            'isSelected': (index === 0) ? true :false
           }
         )
         selectedMultiDb.pushObject(db);
@@ -103,23 +110,26 @@ export default Ember.Route.extend({
       this.get('controller').set('selectedMultiDb', selectedMultiDb );
       this.get('controller.model').set('selectedMultiDb', selectedMultiDb );
 
-
     },
 
     showTables(db){
+      let self = this;
       //should we do this by writing a seperate component.
       $('#' + db).toggle();
       this.get('controller.model').set('selectedDb', db);
     },
 
     executeQuery(isFirstCall){
+
       let self = this;
+      this.get('controller').set('currentJobId', null);
       let queryInput = this.get('controller').get('currentQuery');
       this.get('controller.model').set('query', queryInput);
 
       let dbid = this.get('controller.model').get('selectedDb');
       let worksheetTitle = this.get('controller.model').get('title');
 
+      self.get('controller.model').set('jobData', []);
       self.get('controller').set('isQueryRunning', true);
 
       //Making the result set emply every time query runs.
@@ -145,18 +155,21 @@ export default Ember.Route.extend({
         "confFile":null,
         "globalSettings":""};
 
-
       this.get('query').createJob(payload).then(function(data) {
         // applying a timeout otherwise it goes for status code 409, although 
that condition is also handled in the code.
         setTimeout(function(){
           self.get('controller.model').set('currentJobData', data);
+          self.get('controller.model').set('queryFile', data.job.queryFile);
+
+          self.get('controller').set('currentJobId', data.job.id);
+
           self.send('getJob', data);
-        }, 2000);
+         }, 2000);
       }, function(reason) {
         console.log(reason);
       });
-
     },
+
     getJob(data){
 
       var self = this;
@@ -187,7 +200,6 @@ export default Ember.Route.extend({
       }, function(reason) {
         // on rejection
         console.log('reason' , reason);
-
         if( reason.errors[0].status == 409 ){
           setTimeout(function(){
             self.send('getJob',data);
@@ -197,7 +209,7 @@ export default Ember.Route.extend({
     },
 
     updateQuery(){
-      console.log('I am in update query.')
+      console.log('I am in update query.');
     },
 
     goNextPage(){
@@ -285,8 +297,65 @@ export default Ember.Route.extend({
       }else {
         Ember.$('.ember-light-table').css('height', '70vh');
       }
-    }
+    },
+
 
+    openWorksheetModal(){
+      this.get('controller').set('showWorksheetModal', true);
+    },
 
+    saveWorksheetModal(){
+      console.log('I am in saveWorksheetModal');
+      let newTitle = $('#worksheet-title').val();
+
+      let currentQuery = this.get('controller').get('currentQuery');
+      let selectedDb = this.get('controller.model').get('selectedDb');
+      let owner = this.get('controller.model').get('owner');
+      let queryFile = this.get('controller.model').get('queryFile');
+
+      let payload = {"title" : newTitle,
+                     "dataBase": selectedDb,
+                     "owner" : owner,
+                     "shortQuery" : (currentQuery.length > 0) ? currentQuery : 
";",
+                     "queryFile" : queryFile };
+
+      this.get('savedQueries').saveQuery(payload)
+        .then((data) => {
+          console.log('Created saved query.', data);
+          this.get('controller.model').set('title', newTitle);
+          this.get('controller').set('worksheetModalSuccess', true);
+
+          Ember.run.later(() => {
+            this.get('controller').set('showWorksheetModal', false);
+          }, 2 * 1000);
+
+        }, (error) => {
+          console.log("Error encountered", error);
+          Ember.run.later(() => {
+            this.get('controller').set('worksheetModalFail', true);
+          }, 2 * 1000);
+        });
+    },
+
+    closeWorksheetModal(){
+      this.get('controller').set('showWorksheetModal', false);
+    },
+
+    saveToHDFS(jobId, path){
+
+      console.log('saveToHDFS query route with jobId == ', jobId);
+      console.log('saveToHDFS query route with path == ', path);
+
+      this.get('query').saveToHDFS(jobId, path)
+         .then((data) => {
+            Ember.run.later(() => {
+              console.log('successfully saveToHDFS', data);
+            }, 2 * 1000);
+
+          }, (error) => {
+            console.log("Error encountered", error);
+          });
+
+    }
   }
 });

http://git-wip-us.apache.org/repos/asf/ambari/blob/f5b46499/contrib/views/hive20/src/main/resources/ui/app/routes/savedqueries.js
----------------------------------------------------------------------
diff --git 
a/contrib/views/hive20/src/main/resources/ui/app/routes/savedqueries.js 
b/contrib/views/hive20/src/main/resources/ui/app/routes/savedqueries.js
index 8719170..7b9cb09 100644
--- a/contrib/views/hive20/src/main/resources/ui/app/routes/savedqueries.js
+++ b/contrib/views/hive20/src/main/resources/ui/app/routes/savedqueries.js
@@ -19,4 +19,83 @@
 import Ember from 'ember';
 
 export default Ember.Route.extend({
+
+  savedQueries: Ember.inject.service(),
+
+  model() {
+    return this.get('savedQueries').getAllQueries();
+  },
+
+  setupController(controller, model) {
+    this._super(...arguments);
+    controller.set('showDeleteSaveQueryModal', false);
+    controller.set('selectedSavedQueryId', null);
+  },
+
+  actions: {
+    historySavedQuery(id){
+      console.log('historySavedQuery', id);
+    },
+
+    deleteSavedQuery(){
+      let queryId = this.get('controller').get('selectedSavedQueryId');
+
+      console.log('deleteSavedQuery', queryId);
+      this.get('savedQueries').deleteSaveQuery(queryId)
+        .then((data) => {
+          console.log('Deleted saved query.', data);
+          this.get('controller').set('showDeleteSaveQueryModal', false );
+          //$(window).reload();
+        }, (error) => {
+          console.log("Error encountered", error);
+        });
+    },
+
+    deleteSavedQuerypDeclined(){
+      this.get('controller').set('selectedSavedQueryId', null);
+      this.get('controller').set('showDeleteSaveQueryModal', false );
+    },
+
+    openDeleteSavedQueryModal(id){
+      this.get('controller').set('showDeleteSaveQueryModal', true );
+      this.get('controller').set('selectedSavedQueryId', id );
+    },
+
+    openAsWorksheet(savedQuery){
+
+      let hasWorksheetModel = this.modelFor('queries');
+      let worksheetId;
+
+      if (Ember.isEmpty(hasWorksheetModel)){
+        worksheetId = 1;
+      }else {
+
+        let isWorksheetExist = 
(this.controllerFor('queries').get('model').filterBy('title', 
savedQuery.title).get('length') > 0);
+        if(isWorksheetExist) {
+          this.transitionTo('queries.query', savedQuery.title);
+          return;
+        }
+
+        let worksheets = this.controllerFor('queries').get('model');
+        worksheets.forEach((worksheet) => {
+          worksheet.set('selected', false);
+        });
+        worksheetId = `worksheet${worksheets.get('length') + 1}`;
+      }
+
+      let localWs = {
+        id: worksheetId,
+        title: savedQuery.title,
+        query: savedQuery.shortQuery,
+        selectedDb : savedQuery.dataBase,
+        owner: savedQuery.owner,
+        selected: true
+      };
+
+      this.store.createRecord('worksheet', localWs );
+
+      this.transitionTo('queries.query', localWs.title);
+    }
+  }
+
 });

http://git-wip-us.apache.org/repos/asf/ambari/blob/f5b46499/contrib/views/hive20/src/main/resources/ui/app/services/jobs.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive20/src/main/resources/ui/app/services/jobs.js 
b/contrib/views/hive20/src/main/resources/ui/app/services/jobs.js
index 4928e5c..723953c 100644
--- a/contrib/views/hive20/src/main/resources/ui/app/services/jobs.js
+++ b/contrib/views/hive20/src/main/resources/ui/app/services/jobs.js
@@ -24,5 +24,31 @@ export default Ember.Service.extend({
     return this.get('store').findRecord('job', jobId).then((job) => {
       return this.get('store').findRecord('file', job.get('queryFile'));
     })
+  },
+
+  waitForJobToComplete(jobId, after) {
+    return new Ember.RSVP.Promise((resolve, reject) => {
+      Ember.run.later(() => {
+        this.get('store').findRecord('job', jobId, {reload: true})
+          .then((job) => {
+            let status = job.get('status').toLowerCase();
+            if (status === 'succeeded') {
+              this._fetchDummyResult(jobId);
+              resolve();
+            } else if (status === 'error') {
+              reject()
+            } else {
+              resolve(this.waitForJobToComplete(jobId, after));
+            }
+          }, (error) => {
+            reject(error);
+          });
+      }, after);
+    });
+  },
+
+  _fetchDummyResult(jobId) {
+    this.get('store').adapterFor('job').fetchResult(jobId);
   }
+
 });

http://git-wip-us.apache.org/repos/asf/ambari/blob/f5b46499/contrib/views/hive20/src/main/resources/ui/app/services/query.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive20/src/main/resources/ui/app/services/query.js 
b/contrib/views/hive20/src/main/resources/ui/app/services/query.js
index 5a2f62d..d95a2e5 100644
--- a/contrib/views/hive20/src/main/resources/ui/app/services/query.js
+++ b/contrib/views/hive20/src/main/resources/ui/app/services/query.js
@@ -40,6 +40,18 @@ export default Ember.Service.extend({
           reject(err);
       });
     });
+  },
+
+  saveToHDFS(jobId, path){
+    let self = this;
+    return new Promise( (resolve, reject) => {
+      this.get('store').adapterFor('job').saveToHDFS(jobId, 
path).then(function(data) {
+        resolve(data);
+      }, function(err) {
+          reject(err);
+      });
+    });
   }
 
+
 });

http://git-wip-us.apache.org/repos/asf/ambari/blob/f5b46499/contrib/views/hive20/src/main/resources/ui/app/services/saved-queries.js
----------------------------------------------------------------------
diff --git 
a/contrib/views/hive20/src/main/resources/ui/app/services/saved-queries.js 
b/contrib/views/hive20/src/main/resources/ui/app/services/saved-queries.js
new file mode 100644
index 0000000..29ef4b5
--- /dev/null
+++ b/contrib/views/hive20/src/main/resources/ui/app/services/saved-queries.js
@@ -0,0 +1,52 @@
+/**
+ * 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 Ember from 'ember';
+
+export default Ember.Service.extend({
+
+  store: Ember.inject.service(),
+
+  getAllQueries(){
+    let url = this.get('store').adapterFor('saved-query').buildURL();
+    return $.ajax(url, 'GET')
+  },
+
+  saveQuery(payload){
+    return $.ajax({
+      type: "POST",
+      url: this.get('store').adapterFor('saved-query').buildURL(),
+      data: JSON.stringify({savedQuery: payload}) ,
+      contentType:"application/json; charset=utf-8",
+      dataType:"json",
+      headers: {'X-Requested-By': 'ambari'}
+    })
+  },
+  deleteSaveQuery(id){
+    let deletURL = this.get('store').adapterFor('saved-query').buildURL() + id;
+
+    return $.ajax({
+      type: "DELETE",
+      url: deletURL,
+      contentType:"application/json; charset=utf-8",
+      dataType:"json",
+      headers: {'X-Requested-By': 'ambari'}
+    })
+  }
+
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/f5b46499/contrib/views/hive20/src/main/resources/ui/app/styles/app.scss
----------------------------------------------------------------------
diff --git a/contrib/views/hive20/src/main/resources/ui/app/styles/app.scss 
b/contrib/views/hive20/src/main/resources/ui/app/styles/app.scss
index 6bf8e5a..8e0ab21 100644
--- a/contrib/views/hive20/src/main/resources/ui/app/styles/app.scss
+++ b/contrib/views/hive20/src/main/resources/ui/app/styles/app.scss
@@ -287,7 +287,7 @@ pre {
   border: 1px solid darken($database-search-background, 25%);
   margin-right: 0;
   .expand-button{
-    position: absolute;right: 5px;top: 5px;z-index: 9999;cursor: pointer;
+    position: absolute;right: 5px;top: 5px;z-index: 99;cursor: pointer;
   }
 }
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/f5b46499/contrib/views/hive20/src/main/resources/ui/app/templates/components/query-result-table.hbs
----------------------------------------------------------------------
diff --git 
a/contrib/views/hive20/src/main/resources/ui/app/templates/components/query-result-table.hbs
 
b/contrib/views/hive20/src/main/resources/ui/app/templates/components/query-result-table.hbs
index 441352e..4bda978 100644
--- 
a/contrib/views/hive20/src/main/resources/ui/app/templates/components/query-result-table.hbs
+++ 
b/contrib/views/hive20/src/main/resources/ui/app/templates/components/query-result-table.hbs
@@ -18,6 +18,15 @@
 
 {{#if columns.length}}
   <div class="clearfix" style="text-align: right; padding-right:5px">
+
+    <span class="dropdown">
+      <button class="btn btn-default dropdown-toggle" title="Actions" 
data-toggle="dropdown" aria-haspopup="true" aria-expanded="true">{{fa-icon 
"bars"}} </button>
+      <ul class="dropdown-menu dropdown-menu-right" 
aria-labelledby="dropdownMenu">
+        <li><a href="#" {{action "openSaveHdfsModal" }} 
class="text-uppercase">{{fa-icon "save"}} Save To HDFS</a></li>
+        <li><a href="#" {{action "openDownloadCsvModal" }} 
class="text-uppercase">{{fa-icon "download"}} Download As CSV</a></li>
+      </ul>
+    </span>&nbsp;
+
     <button class="btn btn-default" title="Previous Page" {{action 
"goPrevPage" }}  >{{fa-icon "arrow-left"}} </button>
     <button class="btn btn-default" title="Next Page" {{action "goNextPage" 
}}>{{fa-icon "arrow-right"}} </button> &nbsp;
     <button class="btn btn-default" title="Expand/Collspse" {{action 
"expandQueryResultPanel" }}>{{fa-icon "expand"}}</button>
@@ -49,5 +58,25 @@
   {{/light-table}}
 </div>
 
+{{#if showSaveHdfsModal}}
+  {{save-hdfs
+  confirmText="OK"
+  rejectText="CLOSE"
+  label="Please enter save path and name."
+  jobId=jobId
+  labelIcon="save"
+  rejectIcon="times"
+  confirmIcon="check"
+  closable=false
+  confirmClass="success"
+  confirm="saveToHDFS"
+  reject="closeSaveHdfsModal"
+  }}
+{{/if}}
+
+{{#if showDownloadCsvModal}}
+Yahoo
+{{/if}}
+
 {{yield}}
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/f5b46499/contrib/views/hive20/src/main/resources/ui/app/templates/components/save-hdfs.hbs
----------------------------------------------------------------------
diff --git 
a/contrib/views/hive20/src/main/resources/ui/app/templates/components/save-hdfs.hbs
 
b/contrib/views/hive20/src/main/resources/ui/app/templates/components/save-hdfs.hbs
new file mode 100644
index 0000000..5b53102
--- /dev/null
+++ 
b/contrib/views/hive20/src/main/resources/ui/app/templates/components/save-hdfs.hbs
@@ -0,0 +1,37 @@
+{{!
+* 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.
+}}
+
+{{#modal-dialog
+  close="reject"
+  translucentOverlay=true
+  clickOutsideToClose=true
+  container-class="modal-dialog"}}
+  <div class="modal-content">
+    <div class="modal-header text-{{titleClass}}">
+        <button type="button" class="close" {{action "reject"}}><span 
aria-hidden="true">&times;</span></button>
+    </div>
+    <div class="modal-body">
+      <p class="lead">{{#if labelIcon}}{{fa-icon labelIcon size="lg"}}{{/if}} 
{{label}}</p>
+      {{input class="form-control path-name" type="text" value=savePathName}}
+    </div>
+    <div class="modal-footer">
+      <button type="button" class="btn btn-{{rejectClass}}" {{action 
"reject"}}>{{#if rejectIcon}}{{fa-icon rejectIcon}} 
{{/if}}{{rejectText}}</button>
+      <button type="button" class="btn btn-{{confirmClass}}" {{action 
"confirm"}}>{{#if confirmIcon}}{{fa-icon confirmIcon}} 
{{/if}}{{confirmText}}</button>
+    </div>
+  </div>
+{{/modal-dialog}}

http://git-wip-us.apache.org/repos/asf/ambari/blob/f5b46499/contrib/views/hive20/src/main/resources/ui/app/templates/queries/query.hbs
----------------------------------------------------------------------
diff --git 
a/contrib/views/hive20/src/main/resources/ui/app/templates/queries/query.hbs 
b/contrib/views/hive20/src/main/resources/ui/app/templates/queries/query.hbs
index 371f404..120a045 100644
--- a/contrib/views/hive20/src/main/resources/ui/app/templates/queries/query.hbs
+++ b/contrib/views/hive20/src/main/resources/ui/app/templates/queries/query.hbs
@@ -29,6 +29,7 @@
       </div>
       <div class="row query-editor-controls">
         <button class="btn btn-success" {{action "executeQuery" }}>{{fa-icon 
"check"}} Execute</button>
+        <button class="btn btn-default" {{action "openWorksheetModal" 
}}>{{fa-icon "save"}} Save As</button>
         {{#if isQueryRunning}}
           <img src="http://www.bba-reman.com/images/fbloader.gif"; height="22" 
width="32" />
         {{/if}}
@@ -36,18 +37,20 @@
     </div>
     <div class="clearfix row query-editor-results" style="position: relative">
       {{query-result-table
-        queryResult=queryResult
-        updateQuery='updateQuery'
-        previousPage=worksheet.previousPage
-        hidePreviousButton=hidePreviousButton
-        goNextPage='goNextPage'
-        goPrevPage='goPrevPage'
-        expandQueryResultPanel='expandQueryResultPanel'}}
+      queryResult=queryResult
+      jobId=currentJobId
+      updateQuery='updateQuery'
+      previousPage=worksheet.previousPage
+      hidePreviousButton=hidePreviousButton
+      goNextPage='goNextPage'
+      goPrevPage='goPrevPage'
+      expandQueryResultPanel='expandQueryResultPanel'
+      saveToHDFS='saveToHDFS'
+      }}
     </div>
   </div>
 </div>
 
-
 <div class="col-md-3 database-panel">
   <div class="database-container">
     <div class="row">
@@ -59,27 +62,27 @@
               <a role="button" data-toggle="collapse" data-parent="#accordion"
                  href="javascript:void(0)" {{action 'showTables' 
tableModel.dbname }} aria-expanded="true"
                  aria-controls={{tableModel.dbname}}>
-                {{ tableModel.dbname }}
+                {{ tableModel.dbname }} {{#if tableModel.isSelected}} 
{{fa-icon "check"}}  {{/if}}
               </a>
               <small 
class="pull-right">Tables({{tableModel.tables.length}})</small>
             </h4>
           </div>
           <div id={{ tableModel.dbname }} class="db-tables collapse 
panel-collapse {{if singleDbModel 'in'}}" role="tabpanel"
           aria-labelledby="headingOne">
-            <div class="panel-body">
-              {{#if tableModel.tables.length }}
-                {{#list-filter header="tables" items=tableModel.tables
-                placeholder="Search Tables"
-                as |filteredItems|}}
-                  {{#list-group class="table-list" items=filteredItems as 
|item|}}
-                    {{list-item item=item itemClicked="tableSelected"}}
-                  {{/list-group}}
-                {{/list-filter}}
-              {{else}}
-                <div class="empty">No Table found.</div>
-              {{/if}}
-            </div>
+          <div class="panel-body">
+            {{#if tableModel.tables.length }}
+              {{#list-filter header="tables" items=tableModel.tables
+              placeholder="Search Tables"
+              as |filteredItems|}}
+                {{#list-group class="table-list" items=filteredItems as 
|item|}}
+                  {{list-item item=item itemClicked="tableSelected"}}
+                {{/list-group}}
+              {{/list-filter}}
+            {{else}}
+              <div class="empty">No Table found.</div>
+            {{/if}}
           </div>
+        </div>
       </div>
       {{/each}}
     </div>
@@ -87,4 +90,45 @@
 </div>
 </div>
 
+{{#if showWorksheetModal}}
+
+  {{#modal-dialog translucentOverlay=true clickOutsideToClose=true 
container-class="modal-dialog  modal-sm"}}
+    <div class="modal-content">
+      <div class="modal-header">
+        <h4 class="modal-title">Saving worksheet</h4>
+      </div>
+      <div class="modal-body">
+        <div class="form-horizontal">
+          <div class="form-group">
+            <label for="title" class="col-sm-2 control-label">Title</label>
+            <div class="col-sm-10">
+              {{input type="text" class="form-control" id="worksheet-title" 
placeholder="Title" value=worksheet.title }}
+            </div>
+          </div>
+
+          {{#if worksheetModalSuccess }}
+            <div class="text-success">Successfully Saved.</div>
+          {{/if}}
+          {{#if worksheetModalFail }}
+            <div class="text-danger">Error</div>
+          {{/if}}
+
+
+        </div>
+      </div>
+
+      <div class="modal-footer">
+        <button type="button" class="btn btn-default" {{action 
"saveWorksheetModal"}}>{{fa-icon "check"}} Save</button>
+        <button type="button" class="btn btn-default" {{action 
"closeWorksheetModal"}}>{{fa-icon "close"}} Cancel</button>
+      </div>
+    </div>
+  {{/modal-dialog}}
+
+
+{{/if}}
+
+
+
+
+
 {{outlet}}

http://git-wip-us.apache.org/repos/asf/ambari/blob/f5b46499/contrib/views/hive20/src/main/resources/ui/app/templates/savedqueries.hbs
----------------------------------------------------------------------
diff --git 
a/contrib/views/hive20/src/main/resources/ui/app/templates/savedqueries.hbs 
b/contrib/views/hive20/src/main/resources/ui/app/templates/savedqueries.hbs
index b776fd2..0ab6cfd 100644
--- a/contrib/views/hive20/src/main/resources/ui/app/templates/savedqueries.hbs
+++ b/contrib/views/hive20/src/main/resources/ui/app/templates/savedqueries.hbs
@@ -16,4 +16,56 @@
 * limitations under the License.
 }}
 
+<div class="row jobs-table">
+  <div class="col-md-12">
+    <table class="table table-striped">
+      <thead>
+      <tr>
+        <th width="30%">Preview</th>
+        <th width="20%">Title</th>
+        <th width="20%">Database</th>
+        <th width="20%">Owner</th>
+        <th width="10%">Action</th>
+      </tr>
+      </thead>
+      <tbody>
+      {{#each model.savedQueries as |savedQuery| }}
+        <tr>
+          <td>{{savedQuery.shortQuery}}</td>
+          <td>{{savedQuery.title}}</td>
+          <td>{{savedQuery.dataBase}}</td>
+          <td>{{savedQuery.owner}}</td>
+          <td>
+              <div class="dropdown">
+                <a class="dropdown-toggle" id="dropdownMenu1121" 
data-toggle="dropdown" aria-haspopup="true" aria-expanded="true">{{fa-icon 
"cog"}}</a>
+                <ul class="dropdown-menu dropdown-menu-right" 
aria-labelledby="dropdownMenu">
+                  <li><a href="#" {{action "historySavedQuery" savedQuery.id 
}} class="text-uppercase">{{fa-icon "history"}} History</a></li>
+                  <li><a href="#" {{action "openDeleteSavedQueryModal" 
savedQuery.id}} class="text-uppercase">{{fa-icon "remove"}} Delete</a></li>
+                  <li><a href="#" {{action "openAsWorksheet" savedQuery }} 
class="text-uppercase">{{fa-icon "folder-open-o"}} Open as worksheet</a></li>
+                </ul>
+              </div>
+          </td>
+        </tr>
+      {{/each}}
+      </tbody>
+    </table>
+  </div>
+</div>
+
+{{#if showDeleteSaveQueryModal}}
+  {{confirm-dialog
+  title="Confirm"
+  label="Do You want to delete the saved query?"
+  titleIcon="minus"
+  labelIcon="save"
+  rejectIcon="times"
+  confirmIcon="check"
+  closable=false
+  confirmClass="success"
+  confirm="deleteSavedQuery"
+  reject="deleteSavedQuerypDeclined"
+  }}
+{{/if}}
+
+
 {{outlet}}

Reply via email to