Repository: ambari Updated Branches: refs/heads/trunk 187ab949d -> 701ea2bd8
AMBARI-16422. Hive View : Upload table : show UI validation errors while creating table. (Nitiraj Rathore via pallavkul) Project: http://git-wip-us.apache.org/repos/asf/ambari/repo Commit: http://git-wip-us.apache.org/repos/asf/ambari/commit/701ea2bd Tree: http://git-wip-us.apache.org/repos/asf/ambari/tree/701ea2bd Diff: http://git-wip-us.apache.org/repos/asf/ambari/diff/701ea2bd Branch: refs/heads/trunk Commit: 701ea2bd82e68465118308d7d9e136630f79eeee Parents: 187ab94 Author: Pallav Kulshreshtha <pallav....@gmail.com> Authored: Wed May 18 12:27:24 2016 +0530 Committer: Pallav Kulshreshtha <pallav....@gmail.com> Committed: Wed May 18 12:27:24 2016 +0530 ---------------------------------------------------------------------- .../ui/hive-web/app/adapters/file-upload.js | 1 - .../ui/hive-web/app/adapters/upload-table.js | 6 +- .../app/components/validated-text-field.js | 60 ++++++++ .../ui/hive-web/app/controllers/upload-table.js | 152 +++++++++---------- .../ui/hive-web/app/initializers/i18n.js | 62 +++++++- .../resources/ui/hive-web/app/styles/app.scss | 4 + .../components/validated-text-field.hbs | 23 +++ .../ui/hive-web/app/templates/upload-table.hbs | 41 +++-- 8 files changed, 245 insertions(+), 104 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/ambari/blob/701ea2bd/contrib/views/hive/src/main/resources/ui/hive-web/app/adapters/file-upload.js ---------------------------------------------------------------------- diff --git a/contrib/views/hive/src/main/resources/ui/hive-web/app/adapters/file-upload.js b/contrib/views/hive/src/main/resources/ui/hive-web/app/adapters/file-upload.js index 1bd8eee..7bb6e0b 100644 --- a/contrib/views/hive/src/main/resources/ui/hive-web/app/adapters/file-upload.js +++ b/contrib/views/hive/src/main/resources/ui/hive-web/app/adapters/file-upload.js @@ -25,7 +25,6 @@ export default EmberUploader.Uploader.extend({ // Override _ajax: function(settings) { settings = Ember.merge(settings, this.getProperties('headers')); - console.log("_ajax : settings: " + JSON.stringify(settings)); return this._super(settings); } }); http://git-wip-us.apache.org/repos/asf/ambari/blob/701ea2bd/contrib/views/hive/src/main/resources/ui/hive-web/app/adapters/upload-table.js ---------------------------------------------------------------------- diff --git a/contrib/views/hive/src/main/resources/ui/hive-web/app/adapters/upload-table.js b/contrib/views/hive/src/main/resources/ui/hive-web/app/adapters/upload-table.js index ef4df43..76fce50 100644 --- a/contrib/views/hive/src/main/resources/ui/hive-web/app/adapters/upload-table.js +++ b/contrib/views/hive/src/main/resources/ui/hive-web/app/adapters/upload-table.js @@ -30,9 +30,7 @@ export default application.extend({ uploadFiles: function (path, files, extras) { var uploadUrl = this.buildUploadURL(path); - console.log("uplaoder : uploadURL : ", uploadUrl); - console.log("uploader : extras : ", extras); - console.log("uploader : files : ", files); + console.log("uplaoder : uploadURL : ", uploadUrl, " extras : ", extras , "files : ", files); var hdrs = Ember.$.extend(true, {},this.get('headers')); delete hdrs['Content-Type']; @@ -72,10 +70,8 @@ export default application.extend({ headers: self.get('headers'), dataType : 'json' }).done(function(data) { - console.log( "inside done : data : ", data ); resolve(data); }).fail(function(error) { - console.log( "inside fail error : ", error ); reject(error); }); }); http://git-wip-us.apache.org/repos/asf/ambari/blob/701ea2bd/contrib/views/hive/src/main/resources/ui/hive-web/app/components/validated-text-field.js ---------------------------------------------------------------------- diff --git a/contrib/views/hive/src/main/resources/ui/hive-web/app/components/validated-text-field.js b/contrib/views/hive/src/main/resources/ui/hive-web/app/components/validated-text-field.js new file mode 100644 index 0000000..50cea36 --- /dev/null +++ b/contrib/views/hive/src/main/resources/ui/hive-web/app/components/validated-text-field.js @@ -0,0 +1,60 @@ +/** + * 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'; + +/** Example : + * {{#validated-text-field + * inputValue=bindedTextValue invalidClass='form-control red-border' validClass='form-control' regex="^[a-z]+$" + * allowEmpty=false tooltip="Enter valid word" errorMessage="Please enter valid word" placeholder="Enter Word"}} + * {{/validated-text-field}} + */ +export default Ember.Component.extend({ + allowEmpty: true, + valid: true, + setValid: function () { + this.set("valid", true); + this.set("inputClass", this.get("validClass")); + this.set("message", this.get("tooltip")); + }, + setInvalid: function () { + this.set("valid", false); + this.set("inputClass", this.get("invalidClass")); + this.set("message", this.get("errorMessage")); + }, + onChangeInputValue: function () { + var regStr = this.get("regex"); + var regExp = new RegExp(regStr, "g"); + if (this.get("inputValue")) { + var arr = this.get("inputValue").match(regExp); + if (arr != null && arr.length == 1) { + this.setValid(); + } + else { + this.setInvalid(); + } + } else { + if (this.get("allowEmpty")) { + this.setValid(); + } else { + this.setInvalid(); + } + } + }.observes("inputValue").on('init') +}); http://git-wip-us.apache.org/repos/asf/ambari/blob/701ea2bd/contrib/views/hive/src/main/resources/ui/hive-web/app/controllers/upload-table.js ---------------------------------------------------------------------- diff --git a/contrib/views/hive/src/main/resources/ui/hive-web/app/controllers/upload-table.js b/contrib/views/hive/src/main/resources/ui/hive-web/app/controllers/upload-table.js index 361de7b..f08aa18 100644 --- a/contrib/views/hive/src/main/resources/ui/hive-web/app/controllers/upload-table.js +++ b/contrib/views/hive/src/main/resources/ui/hive-web/app/controllers/upload-table.js @@ -22,6 +22,8 @@ import constants from 'hive/utils/constants'; export default Ember.Controller.extend({ + COLUMN_NAME_REGEX:"^[a-zA-Z]{1}[a-zA-Z0-9_]*$", + TABLE_NAME_REGEX:"^[a-zA-Z]{1}[a-zA-Z0-9_]*$", isLocalUpload : Ember.computed.equal("uploadSource","local"), uploadSource : "local", COLUMN_NAME_PREFIX : "column", @@ -93,7 +95,6 @@ export default Ember.Controller.extend({ }, this); }, isFirstRowHeaderDidChange: function () { - console.log("inside onFirstRowHeader : isFirstRowHeader : " + this.get('isFirstRowHeader')); if (this.get('isFirstRowHeader') != null && typeof this.get('isFirstRowHeader') !== 'undefined') { if (this.get('isFirstRowHeader') == false) { if (this.get('rows')) { @@ -112,16 +113,13 @@ export default Ember.Controller.extend({ popUploadProgressInfos : function(){ var msg = this.get('uploadProgressInfos').popObject(); - // console.log("popedup message : " + msg); }, pushUploadProgressInfos : function(info){ this.get('uploadProgressInfos').pushObject(info); - // console.log("pushed message : " + info); }, clearUploadProgressModal : function(){ - // console.log("inside clearUploadProgressModal this.get('uploadProgressInfos') : " + this.get('uploadProgressInfos')); var len = this.get('uploadProgressInfos').length; for( var i = 0 ; i < len ; i++){ this.popUploadProgressInfos(); @@ -129,7 +127,6 @@ export default Ember.Controller.extend({ }, hideUploadModal : function(){ - console.log("hiding the modal ...."); this.clearUploadProgressModal(); Ember.$("#uploadProgressModal").modal("hide"); }, @@ -156,13 +153,10 @@ export default Ember.Controller.extend({ }, printValues: function () { - console.log("printing all values : "); - console.log("header : ", this.get('header')); - console.log("rows : ", this.get('rows')); - console.log("error : ", this.get('error')); - console.log("isFirstRowHeader : ", this.get('isFirstRowHeader')); - console.log("files : ", this.get('files')); - console.log("firstRow : ", this.get('firstRow')); + console.log("header : ", this.get('header'), + ". rows : ",this.get('rows'),". error : ", this.get('error'), + " isFirstRowHeader : ", this.get('isFirstRowHeader'), + "firstRow : ", this.get('firstRow')); }, generateTempTableName : function(){ @@ -180,16 +174,12 @@ export default Ember.Controller.extend({ var self = this; var fetchJobPromise = this.get('jobService').fetchJobStatus(jobId); fetchJobPromise.then(function (data) { - console.log("waitForJobStatus : data : ", data); var status = data.jobStatus; if (status == "Succeeded") { - console.log("resolving waitForJobStatus with : " , status); resolve(status); } else if (status == "Canceled" || status == "Closed" || status == "Error") { - console.log("rejecting waitForJobStatus with : " + status); reject(new Error(status)); } else { - console.log("retrying waitForJobStatus : "); self.waitForJobStatus(jobId, resolve, reject); } }, function (error) { @@ -229,7 +219,7 @@ export default Ember.Controller.extend({ waitForGeneratingPreview: function () { console.log("waitForGeneratingPreview"); this.showUploadModal(); - this.pushUploadProgressInfos("<li> Generating Preview .... </li>") + this.pushUploadProgressInfos(this.formatMessage('hive.messages.generatingPreview')) }, previewTable: function (data) { @@ -241,7 +231,6 @@ export default Ember.Controller.extend({ this.set("defaultColumnNames",defaultColumnNames); this.set("header", data.header); this.set("firstRow", data.rows[0].row); - console.log("firstRow : ", this.get('firstRow')); this.set('isFirstRowHeader', data.isFirstRowHeader); this.set('tableName',data.tableName); if(data.isFirstRowHeader == true){ @@ -264,13 +253,13 @@ export default Ember.Controller.extend({ this.setError(error); }, - createTable: function () { - console.log("table headers : ", this.get('header')); + createActualTable : function(){ + console.log("createActualTable"); + this.pushUploadProgressInfos(this.formatMessage('hive.messages.startingToCreateActualTable')); var headers = this.get('header'); - var selectedDatabase = this.get('selectedDatabase'); - if (null == selectedDatabase || typeof selectedDatabase === 'undefined') { - throw new Error(Ember.I18n.t('hive.errors.emptyDatabase')); + if (!selectedDatabase) { + throw new Error(this.translate('hive.errors.emptyDatabase', {database : this.translate("hive.words.database")})); } this.set('databaseName', this.get('selectedDatabase').get('name')); @@ -279,17 +268,8 @@ export default Ember.Controller.extend({ var isFirstRowHeader = this.get('isFirstRowHeader'); var filetype = this.get("selectedFileType"); - if (null == databaseName || typeof databaseName === 'undefined' || databaseName == '') { - throw new Error(Ember.I18n.t('hive.errors.emptyDatabase')); - } - if (null == tableName || typeof tableName === 'undefined' || tableName == '') { - throw new Error(Ember.I18n.t('hive.errors.emptyTableName')); - } - if (null == isFirstRowHeader || typeof isFirstRowHeader === 'undefined') { - throw new Error(Ember.I18n.t('hive.errors.emptyIsFirstRow')); - } - - this.validateColumns(); + this.validateInput(headers,tableName,databaseName,isFirstRowHeader); + this.showUploadModal(); return this.get('uploader').createTable({ "isFirstRowHeader": isFirstRowHeader, @@ -300,16 +280,10 @@ export default Ember.Controller.extend({ }); }, - createActualTable : function(){ - console.log("createActualTable"); - this.pushUploadProgressInfos("<li> Starting to create Actual table.... </li>"); - return this.createTable(); - }, - waitForCreateActualTable: function (jobId) { console.log("waitForCreateActualTable"); this.popUploadProgressInfos(); - this.pushUploadProgressInfos("<li> Waiting for creation of Actual table.... </li>"); + this.pushUploadProgressInfos(this.formatMessage('hive.messages.waitingToCreateActualTable')); var self = this; var p = new Ember.RSVP.Promise(function (resolve, reject) { self.waitForJobStatus(jobId, resolve, reject); @@ -321,19 +295,19 @@ export default Ember.Controller.extend({ onCreateActualTableSuccess : function(){ console.log("onCreateTableSuccess"); this.popUploadProgressInfos(); - this.pushUploadProgressInfos("<li> Successfully created Actual table. </li>"); + this.pushUploadProgressInfos(this.formatMessage('hive.messages.successfullyCreatedActualTable')); }, onCreateActualTableFailure : function(error){ console.log("onCreateActualTableFailure"); this.popUploadProgressInfos(); - this.pushUploadProgressInfos("<li> Failed to create Actual table. </li>"); + this.pushUploadProgressInfos(this.formatMessage('hive.messages.failedToCreateActualTable')); this.setError(error); }, createTempTable : function(){ console.log("createTempTable"); - this.pushUploadProgressInfos("<li> Starting to create Temporary table.... </li>"); + this.pushUploadProgressInfos(this.formatMessage('hive.messages.startingToCreateTemporaryTable')); var tempTableName = this.generateTempTableName(); this.set('tempTableName',tempTableName); return this.get('uploader').createTable({ @@ -348,7 +322,7 @@ export default Ember.Controller.extend({ waitForCreateTempTable: function (jobId) { console.log("waitForCreateTempTable"); this.popUploadProgressInfos(); - this.pushUploadProgressInfos("<li> Waiting for creation of Temporary table.... </li>"); + this.pushUploadProgressInfos(this.formatMessage('hive.messages.waitingToCreateTemporaryTable')); var self = this; var p = new Ember.RSVP.Promise(function (resolve, reject) { self.waitForJobStatus(jobId, resolve, reject); @@ -360,11 +334,11 @@ export default Ember.Controller.extend({ onCreateTempTableSuccess : function(){ console.log("onCreateTempTableSuccess"); this.popUploadProgressInfos(); - this.pushUploadProgressInfos("<li> Successfully created Temporary table. </li>"); + this.pushUploadProgressInfos(this.formatMessage('hive.messages.successfullyCreatedTemporaryTable')); }, deleteTable : function(databaseName, tableName){ - console.log("deleting table " + databaseName + "." + tableName); + console.log("deleting table ", databaseName , "." , tableName); return this.get('uploader').deleteTable({ "database": databaseName, @@ -375,7 +349,7 @@ export default Ember.Controller.extend({ deleteTableOnError : function(databaseName,tableName, tableLabel){ //delete table and wait for delete job var self = this; - this.pushUploadProgressInfos("<li> Deleting " + tableLabel + " table... </li>"); + this.pushUploadProgressInfos(this.formatMessage('hive.messages.deletingTable',{table:tableLabel})); return this.deleteTable(databaseName,tableName).then(function(data){ return new Ember.RSVP.Promise(function(resolve,reject){ @@ -383,26 +357,31 @@ export default Ember.Controller.extend({ }); }).then(function(){ self.popUploadProgressInfos(); - self.pushUploadProgressInfos("<li> Successfully deleted " + tableLabel + " table. </li>"); + self.pushUploadProgressInfos(this.formatMessage('hive.messages.succesfullyDeletedTable',{table:tableLabel})); return Ember.RSVP.Promise.resolve(); },function(err){ self.popUploadProgressInfos(); - self.pushUploadProgressInfos("<li> Failed to delete " + tableLabel + " table. </li>"); + self.pushUploadProgressInfos(this.formatMessage('hive.messages.failedToDeleteTable',{table:tableLabel})); self.setError(err); return Ember.RSVP.Promise.reject(); }); }, rollBackActualTableCreation : function(){ - return this.deleteTableOnError(this.get("databaseName"),this.get("tableName"),"Actual"); + return this.deleteTableOnError(this.get("databaseName"),this.get("tableName"),this.translate('hive.words.actual')); }, - + translate : function(str,vars){ + return Ember.I18n.t(str,vars); + }, + formatMessage : function(messageId, vars){ + return "<li>" + this.translate(messageId,vars) + "</li>"; + }, onCreateTempTableFailure : function(error){ console.log("onCreateTempTableFailure"); this.setError(error); this.popUploadProgressInfos(); - this.pushUploadProgressInfos("<li> Failed to create temporary table. </li>"); + this.pushUploadProgressInfos(); return this.rollBackActualTableCreation().then(function(data){ return Ember.RSVP.Promise.reject(error); // always reject for the flow to stop },function(err){ @@ -412,7 +391,7 @@ export default Ember.Controller.extend({ uploadFile : function(){ console.log("uploadFile"); - this.pushUploadProgressInfos("<li> Starting to upload the file .... </li>"); + this.pushUploadProgressInfos(this.formatMessage('hive.messages.startingToUploadFile')); if( this.get("isLocalUpload")){ return this.uploadTable(); }else{ @@ -423,7 +402,7 @@ export default Ember.Controller.extend({ waitForUploadingFile: function (data) { console.log("waitForUploadingFile"); this.popUploadProgressInfos(); - this.pushUploadProgressInfos("<li> Waiting for uploading file .... </li>"); + this.pushUploadProgressInfos(this.formatMessage('hive.messages.waitingToUploadFile')); if( data.jobId ){ var self = this; var p = new Ember.RSVP.Promise(function (resolve, reject) { @@ -438,12 +417,12 @@ export default Ember.Controller.extend({ onUploadingFileSuccess: function () { console.log("onUploadingFileSuccess"); this.popUploadProgressInfos(); - this.pushUploadProgressInfos("<li> Successfully uploaded file. </li>"); + this.pushUploadProgressInfos(this.formatMessage('hive.messages.successfullyUploadedFile') ); }, rollBackTempTableCreation : function(){ var self = this; - return this.deleteTableOnError(this.get("databaseName"),this.get("tempTableName"),"Temporary").then(function(data){ + return this.deleteTableOnError(this.get("databaseName"),this.get("tempTableName"),this.translate('hive.words.temporary')).then(function(data){ return self.rollBackActualTableCreation(); },function(err){ return self.rollBackActualTableCreation(); @@ -454,7 +433,7 @@ export default Ember.Controller.extend({ console.log("onUploadingFileFailure"); this.setError(error); this.popUploadProgressInfos(); - this.pushUploadProgressInfos("<li> Failed to upload file. </li>"); + this.pushUploadProgressInfos(this.formatMessage('hive.messages.failedToUploadFile')); return this.rollBackTempTableCreation().then(function(data){ return Ember.RSVP.Promise.reject(error); // always reject for the flow to stop },function(err){ @@ -468,7 +447,7 @@ export default Ember.Controller.extend({ insertIntoTable : function(){ console.log("insertIntoTable"); - this.pushUploadProgressInfos("<li> Starting to Insert rows from temporary table to actual table .... </li>"); + this.pushUploadProgressInfos(this.formatMessage('hive.messages.startingToInsertRows')); return this.get('uploader').insertIntoTable({ "fromDatabase": this.get("databaseName"), @@ -481,7 +460,7 @@ export default Ember.Controller.extend({ waitForInsertIntoTable: function (jobId) { console.log("waitForInsertIntoTable"); this.popUploadProgressInfos(); - this.pushUploadProgressInfos("<li> Waiting for Insertion of rows from temporary table to actual table .... </li>"); + this.pushUploadProgressInfos(this.formatMessage('hive.messages.waitingToInsertRows')); var self = this; var p = new Ember.RSVP.Promise(function (resolve, reject) { self.waitForJobStatus(jobId, resolve, reject); @@ -493,14 +472,14 @@ export default Ember.Controller.extend({ onInsertIntoTableSuccess : function(){ console.log("onInsertIntoTableSuccess"); this.popUploadProgressInfos(); - this.pushUploadProgressInfos("<li> Successfully inserted rows from temporary table to actual table. </li>"); + this.pushUploadProgressInfos(this.formatMessage('hive.messages.successfullyInsertedRows')); }, onInsertIntoTableFailure : function(error){ console.log("onInsertIntoTableFailure"); this.setError(error); this.popUploadProgressInfos(); - this.pushUploadProgressInfos("<li> Failed to insert rows from temporary table to actual table. </li>"); + this.pushUploadProgressInfos(this.formatMessage('hive.messages.failedToInsertRows')); return this.rollBackUploadFile().then(function(data){ return Ember.RSVP.Promise.reject(error); // always reject for the flow to stop },function(err){ @@ -510,7 +489,7 @@ export default Ember.Controller.extend({ deleteTempTable : function(){ console.log("deleteTempTable"); - this.pushUploadProgressInfos("<li> Starting to delete temporary table .... </li>"); + this.pushUploadProgressInfos(this.formatMessage('hive.messages.startingToDeleteTemporaryTable')); return this.deleteTable( this.get("databaseName"), @@ -521,7 +500,7 @@ export default Ember.Controller.extend({ waitForDeleteTempTable: function (jobId) { console.log("waitForDeleteTempTable"); this.popUploadProgressInfos(); - this.pushUploadProgressInfos("<li> Waiting for deletion of temporary table .... </li>"); + this.pushUploadProgressInfos(this.formatMessage('hive.messages.waitingToDeleteTemporaryTable')); var self = this; var p = new Ember.RSVP.Promise(function (resolve, reject) { self.waitForJobStatus(jobId, resolve, reject); @@ -533,31 +512,28 @@ export default Ember.Controller.extend({ onDeleteTempTableSuccess : function(){ console.log("onDeleteTempTableSuccess"); this.popUploadProgressInfos(); - this.pushUploadProgressInfos("<li>Successfully inserted row. </li>"); + this.pushUploadProgressInfos(this.formatMessage('hive.messages.successfullyDeletedTemporaryTable')); this.onUploadSuccessfull(); }, onDeleteTempTableFailure : function(error){ console.log("onDeleteTempTableFailure"); this.setError(error); - this.setError("You will have to manually delete the table " + this.get("databaseName") + "." + this.get("tempTableName")); + this.setError(this.formatMessage('hive.messages.manuallyDeleteTable',{databaseName:this.get('databaseName'), tableName: this.get("tempTableName")})); }, createTableAndUploadFile : function(){ var self = this; self.setError(); - self.showUploadModal(); self.createActualTable() .then(function(data){ - console.log("1. received data : ", data); return self.waitForCreateActualTable(data.jobId); },function(error){ - self.onCreateActualTableFailure(error); console.log("Error occurred: ", error); + self.onCreateActualTableFailure(error); throw error; }) .then(function(data){ - console.log("2. received data : ", data); self.onCreateActualTableSuccess(data); return self.createTempTable(data); },function(error){ @@ -568,7 +544,6 @@ export default Ember.Controller.extend({ throw error; }) .then(function(data){ - console.log("3. received data : ", data); return self.waitForCreateTempTable(data.jobId); },function(error){ if(!self.get('error')){ @@ -578,7 +553,6 @@ export default Ember.Controller.extend({ throw error; }) .then(function(data){ - console.log("4. received data : ", data); self.onCreateTempTableSuccess(data); return self.uploadFile(data); },function(error){ @@ -588,7 +562,6 @@ export default Ember.Controller.extend({ } throw error; }).then(function(data){ - console.log("4.5 received data : ", data); return self.waitForUploadingFile(data); },function(error){ if(!self.get('error')){ @@ -598,7 +571,6 @@ export default Ember.Controller.extend({ throw error; }) .then(function(data){ - console.log("5. received data : ", data); self.onUploadingFileSuccess(data); return self.insertIntoTable(data); },function(error){ @@ -609,7 +581,6 @@ export default Ember.Controller.extend({ throw error; }) .then(function(data){ - console.log("6. received data : ", data); return self.waitForInsertIntoTable(data.jobId); },function(error){ if(!self.get('error')){ @@ -619,7 +590,6 @@ export default Ember.Controller.extend({ throw error; }) .then(function(data){ - console.log("7. received data : ", data); self.onInsertIntoTableSuccess(data); return self.deleteTempTable(data); },function(error){ @@ -630,7 +600,6 @@ export default Ember.Controller.extend({ throw error; }) .then(function(data){ - console.log("8. received data : ", data); return self.waitForDeleteTempTable(data.jobId); },function(error){ if(!self.get('error')){ @@ -640,7 +609,6 @@ export default Ember.Controller.extend({ throw error; }) .then(function(data){ - console.log("9. received data : ", data); self.onDeleteTempTableSuccess(data); },function(error){ if(!self.get('error')){ @@ -656,9 +624,30 @@ export default Ember.Controller.extend({ }); }, - validateColumns: function () { + validateInput: function (headers,tableName,databaseName,isFirstRowHeader) { // throw exception if invalid. + if(!headers || headers.length == 0) throw new Error(this.translate('hive.errors.emptyHeaders')); + + var regex = new RegExp(this.get("COLUMN_NAME_REGEX"),"g"); + + headers.forEach(function(column,index){ + if( !column ) throw new Error(this.translate('hive.errors.emptyColumnName')); + var matchArr = column.name.match(regex); + if(matchArr == null || matchArr.length != 1 ) throw new Error(this.translate('hive.errors.illegalColumnName',{ columnName : column.name, index : (index + 1)})); + },this); + + if(!tableName) throw new Error(this.translate('hive.errors.emptyTableName', {tableNameField : this.translate('hive.ui.tableName')})); + var tableRegex = new RegExp(this.get("TABLE_NAME_REGEX"),"g"); + var mArr = tableName.match(tableRegex); + if(mArr == null || mArr.length != 1 ) throw new Error(this.translate('hive.errors.illegalTableName', {tableNameField:this.translate('hive.ui.tableName'),tableName:tableName}) ); + + if(!databaseName) throw new Error(this.translate('hive.errors.emptyDatabase', {database:this.translate('hive.words.database')})); + + if (null == isFirstRowHeader || typeof isFirstRowHeader === 'undefined') { //this can be true or false. so explicitly checking for null/ undefined. + throw new Error(this.translate('hive.errors.emptyIsFirstRow', {isFirstRowHeaderField:this.translate('hive.ui.isFirstRowHeader')})); + } }, + setError: function (error) { if(error){ console.log("upload table error : ", error); @@ -676,7 +665,7 @@ export default Ember.Controller.extend({ uploadTableFromHdfs : function(){ console.log("uploadTableFromHdfs called."); if(!(this.get("inputFileTypeCSV") == true && this.get("isFirstRowHeader") == false) ){ - this.pushUploadProgressInfos("<li>Uploading file .... </li>"); + this.pushUploadProgressInfos(this.formatMessage('uploadingFromHdfs')); } return this.get('uploader').uploadFromHDFS({ "isFirstRowHeader": this.get("isFirstRowHeader"), @@ -698,7 +687,8 @@ export default Ember.Controller.extend({ onUploadSuccessfull: function (data) { console.log("onUploadSuccessfull : ", data); - this.get('notifyService').success("Uploaded Successfully", "Table " + this.get('tableName') + " created in database " + this.get("databaseName")); + this.get('notifyService').success(this.translate('hive.messages.successfullyUploadedTableHeader'), + this.translate('hive.messages.successfullyUploadedTableMessage' ,{tableName:this.get('tableName') ,databaseName:this.get("databaseName")})); this.clearFields(); }, http://git-wip-us.apache.org/repos/asf/ambari/blob/701ea2bd/contrib/views/hive/src/main/resources/ui/hive-web/app/initializers/i18n.js ---------------------------------------------------------------------- diff --git a/contrib/views/hive/src/main/resources/ui/hive-web/app/initializers/i18n.js b/contrib/views/hive/src/main/resources/ui/hive-web/app/initializers/i18n.js index b3630c1..d2f6aaf 100644 --- a/contrib/views/hive/src/main/resources/ui/hive-web/app/initializers/i18n.js +++ b/contrib/views/hive/src/main/resources/ui/hive-web/app/initializers/i18n.js @@ -244,9 +244,65 @@ TRANSLATIONS = { hive: { errors: { 'no.query': "No query to process.", - 'emptyDatabase' : "Please select Database.", - 'emptyTableName' : "Please enter tableName.", - 'emptyIsFirstRow' : "Please select is First Row Header?" + 'emptyDatabase' : "Please select {{ database }}.", + 'emptyTableName' : "Please enter {{ tableNameField }}.", + 'illegalTableName':"Illegal {{ tableNameField }} : '{{ tableName }}'", + 'emptyIsFirstRow' : "{{isFirstRowHeaderField}} cannot be null.", + 'emptyHeaders':"Headers (containing column names) cannot be null.", + 'emptyColumnName':"Column name cannot be null.", + 'illegalColumnName':"Illegal column name : '{{columnName}}' in column number {{index}}", + }, + messages : { + 'generatingPreview':"Generating Preview.", + 'startingToCreateActualTable' : "Starting to create Actual table", + 'waitingToCreateActualTable' : "Waiting for creation of Actual table", + 'successfullyCreatedActualTable' : "Successfully created Actual table.", + 'failedToCreateActualTable' : "Failed to create Actual table.", + 'startingToCreateTemporaryTable' : "Starting to create Temporary table.", + 'waitingToCreateTemporaryTable' : "Waiting for creation of Temporary table.", + 'successfullyCreatedTemporaryTable' : "Successfully created Temporary table.", + 'failedToCreateTemporaryTable' : " Failed to create temporary table.", + 'deletingTable' : "Deleting {{table}} table.", + 'succesfullyDeletedTable' : "Successfully deleted {{ table}} table.", + 'failedToDeleteTable' : "Failed to delete {{table}} table.", + 'startingToUploadFile' : "Starting to upload the file.", + 'waitingToUploadFile' : "Waiting for uploading file.", + 'successfullyUploadedFile' : "Successfully uploaded file.", + 'failedToUploadFile' : "Failed to upload file.", + 'startingToInsertRows' : "Starting to insert rows from temporary table to actual table.", + 'waitingToInsertRows' : "Waiting for insertion of rows from temporary table to actual table.", + 'successfullyInsertedRows' : "Successfully inserted rows from temporary table to actual table.", + 'failedToInsertRows' : "Failed to insert rows from temporary table to actual table.", + 'startingToDeleteTemporaryTable' : "Starting to delete temporary table.", + 'waitingToDeleteTemporaryTable' : "Waiting for deletion of temporary table.", + 'successfullyDeletedTemporaryTable' : "Successfully deleted temporary table", + 'manuallyDeleteTable' : "You will have to manually delete the table {{databaseName}}.{{tableName}}", + 'uploadingFromHdfs' : "Uploading file from HDFS ", + 'successfullyUploadedTableMessage' : "Table {{tableName}} created in database {{databaseName}}", + 'successfullyUploadedTableHeader' : "Uploaded Successfully" + }, + words :{ + temporary : "Temporary", + actual : "Actual", + database : "Database", + }, + ui : { + 'uploadProgress' : "Upload Progress", + 'uploadFromLocal':"Upload from Local", + 'uploadFromHdfs':"Upload from HDFS", + 'selectFileType':"Select File Type", + 'fileType':"File type", + 'selectFromLocal':"Select from local", + 'hdfsPath':"HDFS Path", + 'selectDatabase':"Select a Database", + 'tableName':"Table name", + 'tableNameErrorMessage':"Only alphanumeric and underscore characters are allowed in table name.", + 'tableNameTooltip':"Enter valid (alphanumeric + underscore) table name.", + 'storedAs':"Stored as", + 'isFirstRowHeader':"Is first row header ?", + 'columnNameTooltip':"Enter valid (alphanumeric + underscore) column name.", + 'columnNameErrorMessage':"Only alphanumeric and underscore characters are allowed in column names.", + } }, http://git-wip-us.apache.org/repos/asf/ambari/blob/701ea2bd/contrib/views/hive/src/main/resources/ui/hive-web/app/styles/app.scss ---------------------------------------------------------------------- diff --git a/contrib/views/hive/src/main/resources/ui/hive-web/app/styles/app.scss b/contrib/views/hive/src/main/resources/ui/hive-web/app/styles/app.scss index ec4f201..d0a6fb7 100644 --- a/contrib/views/hive/src/main/resources/ui/hive-web/app/styles/app.scss +++ b/contrib/views/hive/src/main/resources/ui/hive-web/app/styles/app.scss @@ -683,3 +683,7 @@ td.data-upload-form-field { table.no-border, table.no-border tr, table.no-border tr td { border: none; } + +.red-border { + border-color :red; +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/ambari/blob/701ea2bd/contrib/views/hive/src/main/resources/ui/hive-web/app/templates/components/validated-text-field.hbs ---------------------------------------------------------------------- diff --git a/contrib/views/hive/src/main/resources/ui/hive-web/app/templates/components/validated-text-field.hbs b/contrib/views/hive/src/main/resources/ui/hive-web/app/templates/components/validated-text-field.hbs new file mode 100644 index 0000000..7cf0fcf --- /dev/null +++ b/contrib/views/hive/src/main/resources/ui/hive-web/app/templates/components/validated-text-field.hbs @@ -0,0 +1,23 @@ +{{! +* 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. +}} + +{{! +* see example in validated-text-field.js component file +}} + +{{input class=inputClass value=inputValue title=message placeholder=placeholder}} http://git-wip-us.apache.org/repos/asf/ambari/blob/701ea2bd/contrib/views/hive/src/main/resources/ui/hive-web/app/templates/upload-table.hbs ---------------------------------------------------------------------- diff --git a/contrib/views/hive/src/main/resources/ui/hive-web/app/templates/upload-table.hbs b/contrib/views/hive/src/main/resources/ui/hive-web/app/templates/upload-table.hbs index eb95292..0fffed4 100644 --- a/contrib/views/hive/src/main/resources/ui/hive-web/app/templates/upload-table.hbs +++ b/contrib/views/hive/src/main/resources/ui/hive-web/app/templates/upload-table.hbs @@ -30,7 +30,7 @@ <!-- Modal content--> <div class="modal-content"> <div class="modal-header"> - <h4 class="modal-title">Upload Progress</h4> + <h4 class="modal-title">{{t "hive.ui.uploadProgress"}}</h4> </div> <div class="modal-body"> <p> @@ -51,29 +51,30 @@ <div> <table class="table data-upload-form pull-left"> <tr> - <td class="data-upload-form-label"><label>Upload from Local</label></td> + <td class="data-upload-form-label"><label>{{t "hive.ui.uploadFromLocal"}}</label></td> <td class="data-upload-form-field"> {{radio-button value='local' checked=uploadSource}}</td> - <td class="data-upload-form-label"><label>Upload from HDFS</label></td> + <td class="data-upload-form-label"><label>{{t "hive.ui.uploadFromHdfs"}}</label></td> <td class="data-upload-form-field">{{radio-button value='hdfs' checked=uploadSource}}</td> </tr> <tr> - <td class="data-upload-form-label"><label>File type</label></td> + <td class="data-upload-form-label"><label>{{t "hive.ui.fileType"}}</label></td> <td class="data-upload-form-field"> {{typeahead-widget content=inputFileTypes optionValuePath="id" optionLabelPath="name" selection=inputFileType - placeholder="Select File Type"}} + placeholder=(t "hive.ui.uploadFromHdfs") + }} </td> {{#if isLocalUpload }} - <td class="data-upload-form-label"><label>Select from local</label></td> + <td class="data-upload-form-label"><label>{{t "hive.ui.selectFromLocal"}}</label></td> <td class="data-upload-form-field">{{file-upload filesUploaded="filesUploaded"}}</td> {{else}} - <td class="data-upload-form-label"><label>HDFS Path</label></td> + <td class="data-upload-form-label"><label>{{t "hive.ui.hdfsPath"}}</label></td> <td class="data-upload-form-field" id="hdfs-param">{{input type="text" class="form-control" placeholder="Enter full HDFS path" value=hdfsPath }} <button style="margin-left: 5px; padding-top: 6px;padding-bottom: 6px; padding-right: 10px; padding-left: 10px;" type="button" {{action "previewFromHdfs"}} {{bind-attr class=":btn :btn-sm :btn-default"}}>{{t "buttons.showPreview"}}</button></td> @@ -81,30 +82,36 @@ </tr> {{#if showPreview}} <tr> - <td class="data-upload-form-label"><label>Database</label></td> + <td class="data-upload-form-label"><label>{{t "hive.words.database"}}</label></td> <td class="data-upload-form-field"> {{typeahead-widget content=controllers.databases.databases optionValuePath="id" optionLabelPath="name" selection=selectedDatabase - placeholder="Select a Database" + placeholder=(t "hive.ui.selectDatabase") }} </td> - <td class="data-upload-form-label"><label>Table name</label></td> + <td class="data-upload-form-label"><label>{{t "hive.ui.tableName"}}</label></td> <td - class="data-upload-form-field">{{input type="text" class="form-control" placeholder="Table Name" value=tableName }}</td> + class="data-upload-form-field"> + {{#validated-text-field inputValue=tableName allowEmpty=false + tooltip=(t "hive.ui.tableNameTooltip") + invalidClass='form-control red-border' validClass='form-control' regex=TABLE_NAME_REGEX + errorMessage=(t "hive.ui.tableNameErrorMessage") }} + {{/validated-text-field}} + </td> </tr> <tr> - <td class="data-upload-form-label"><label>Stored as</label></td> + <td class="data-upload-form-label"><label>{{t "hive.ui.storedAs"}}</label></td> <td class="data-upload-form-field"> {{typeahead-widget content=fileTypes selection=selectedFileType}} </td> {{#if inputFileTypeCSV }} - <td class="data-upload-form-label"><label>Is first row header ?</label></td> + <td class="data-upload-form-label"><label>{{t "hive.ui.isFirstRowHeader"}}</label></td> <td class="data-upload-form-field"> {{input id="isFirstRowHeader" type="checkbox" checked=isFirstRowHeader }} </td> @@ -133,7 +140,13 @@ <thead> <tr> {{#each column in header}} - <th>{{input placeholder="column-name" type="text" class="form-control" value=column.name}}</th> + <th> + {{#validated-text-field inputValue=column.name allowEmpty=false + tooltip=(t "hive.ui.columnNameTooltip") + invalidClass='form-control red-border' validClass='form-control' regex=COLUMN_NAME_REGEX + errorMessage=(t "hive.ui.columnNameErrorMessage")}} + {{/validated-text-field}} + </th> {{/each}} </tr> <tr id="upload-controls">