AMBARI-19844. Hive View 2.0: Allow user to rename table.(dipayanb) (cherry picked from commit 5a9f3817eef2a163d24dee8c20598136f6dd5e1f)
Change-Id: Ib1f75fd0a31768ea031eeef3b9efccc44df6b4ea Project: http://git-wip-us.apache.org/repos/asf/ambari/repo Commit: http://git-wip-us.apache.org/repos/asf/ambari/commit/52c2da12 Tree: http://git-wip-us.apache.org/repos/asf/ambari/tree/52c2da12 Diff: http://git-wip-us.apache.org/repos/asf/ambari/diff/52c2da12 Branch: refs/heads/branch-feature-BUG-74026 Commit: 52c2da12de0367972d56cfc84e7910654799c94c Parents: 21af204 Author: Dipayan Bhowmick <dipayan.bhowm...@gmail.com> Authored: Mon Feb 6 11:43:04 2017 +0530 Committer: Zuul <rel...@hortonworks.com> Committed: Tue Feb 7 06:59:45 2017 -0800 ---------------------------------------------------------------------- .../hive20/resources/browser/DDLService.java | 20 +++-- .../resources/ui/app/adapters/application.js | 33 ++++---- .../src/main/resources/ui/app/adapters/table.js | 9 +++ .../ui/app/components/table-rename-form.js | 63 +++++++++++++++ .../resources/ui/app/controllers/application.js | 5 +- .../hive20/src/main/resources/ui/app/router.js | 1 + .../main/resources/ui/app/routes/application.js | 3 +- .../databases/database/tables/table/rename.js | 83 ++++++++++++++++++++ .../ui/app/services/table-operations.js | 11 +++ .../templates/components/table-rename-form.hbs | 31 ++++++++ .../databases/database/tables/table.hbs | 1 + .../databases/database/tables/table/rename.hbs | 46 +++++++++++ .../src/main/resources/ui/config/environment.js | 6 ++ 13 files changed, 290 insertions(+), 22 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/ambari/blob/52c2da12/contrib/views/hive20/src/main/java/org/apache/ambari/view/hive20/resources/browser/DDLService.java ---------------------------------------------------------------------- diff --git a/contrib/views/hive20/src/main/java/org/apache/ambari/view/hive20/resources/browser/DDLService.java b/contrib/views/hive20/src/main/java/org/apache/ambari/view/hive20/resources/browser/DDLService.java index af8e1cd..89b9d84 100644 --- a/contrib/views/hive20/src/main/java/org/apache/ambari/view/hive20/resources/browser/DDLService.java +++ b/contrib/views/hive20/src/main/java/org/apache/ambari/view/hive20/resources/browser/DDLService.java @@ -158,18 +158,17 @@ public class DDLService extends BaseService { @PUT @Path("databases/{database_id}/tables/{table_id}/rename") @Produces(MediaType.APPLICATION_JSON) - @Consumes(MediaType.APPLICATION_FORM_URLENCODED) + @Consumes(MediaType.APPLICATION_JSON) public Response renameTable(@PathParam("database_id") String oldDatabaseName, @PathParam("table_id") String oldTableName, - @FormParam("new_database_id") String newDatabaseName, @FormParam("new_table_id") - String newTableName) { + TableRenameRequest request) { try { - Job job = proxy.renameTable(oldDatabaseName, oldTableName, newDatabaseName, newTableName, getResourceManager()); + Job job = proxy.renameTable(oldDatabaseName, oldTableName, request.newDatabase, request.newTable, getResourceManager()); JSONObject response = new JSONObject(); response.put("job", job); return Response.status(Response.Status.ACCEPTED).entity(response).build(); } catch (ServiceException e) { LOG.error("Exception occurred while renaming table for oldDatabaseName {}, oldTableName: {}, newDatabaseName : {}," + - " newTableName : {}", oldDatabaseName, oldTableName, newDatabaseName, newTableName, e); + " newTableName : {}", oldDatabaseName, oldTableName, request.newDatabase, request.newTable, e); throw new ServiceFormattedException(e); } } @@ -346,4 +345,15 @@ public class DDLService extends BaseService { public static class CreateDatabaseRequest { public String name; } + + /** + * Wrapper class for table rename request + */ + public static class TableRenameRequest { + /* New database name */ + public String newDatabase; + + /* New table name */ + public String newTable; + } } http://git-wip-us.apache.org/repos/asf/ambari/blob/52c2da12/contrib/views/hive20/src/main/resources/ui/app/adapters/application.js ---------------------------------------------------------------------- diff --git a/contrib/views/hive20/src/main/resources/ui/app/adapters/application.js b/contrib/views/hive20/src/main/resources/ui/app/adapters/application.js index 1cdab9e..9cc8658 100644 --- a/contrib/views/hive20/src/main/resources/ui/app/adapters/application.js +++ b/contrib/views/hive20/src/main/resources/ui/app/adapters/application.js @@ -21,14 +21,14 @@ import DS from 'ember-data'; import ENV from 'ui/config/environment'; export default DS.RESTAdapter.extend({ - init: function() { + init: function () { Ember.$.ajaxSetup({ cache: false }); }, - namespace: Ember.computed(function() { - var parts = window.location.pathname.split('/').filter(function(i) { + namespace: Ember.computed(function () { + var parts = window.location.pathname.split('/').filter(function (i) { return i !== ""; }); var view = parts[parts.length - 3]; @@ -39,19 +39,19 @@ export default DS.RESTAdapter.extend({ instance = parts[parts.length - 2]; version = ''; } - if(ENV.environment === 'development') { + if (ENV.environment === 'development') { return 'resources'; } return 'api/v1/views/' + view + version + '/instances/' + instance + '/resources'; }), - headers: Ember.computed(function() { + headers: Ember.computed(function () { let headers = { 'X-Requested-By': 'ambari', 'Content-Type': 'application/json' }; - if(ENV.environment === 'development') { + if (ENV.environment === 'development') { // In development mode when the UI is served using ember serve the xhr requests are proxied to ambari server // by setting the proxyurl parameter in ember serve and for ambari to authenticate the requests, it needs this // basic authorization. This is for default admin/admin username/password combination. @@ -59,21 +59,24 @@ export default DS.RESTAdapter.extend({ //headers['Authorization'] = 'Basic aGl2ZTpoaXZl'; //headers['Authorization'] = 'Basic ZGlwYXlhbjpkaXBheWFu'; } - return headers; + return headers; }), parseErrorResponse(responseText) { let json = this._super(responseText); - let error = {}; - error.message = json.message; - error.trace = json.trace; - error.status = json.status; + if (Ember.isEmpty(json.errors)) { + let error = {}; + error.message = json.message; + error.trace = json.trace; + error.status = json.status; - delete json.trace; - delete json.status; - delete json.message; + delete json.trace; + delete json.status; + delete json.message; + + json.errors = error; + } - json.errors = error; return json; } }); http://git-wip-us.apache.org/repos/asf/ambari/blob/52c2da12/contrib/views/hive20/src/main/resources/ui/app/adapters/table.js ---------------------------------------------------------------------- diff --git a/contrib/views/hive20/src/main/resources/ui/app/adapters/table.js b/contrib/views/hive20/src/main/resources/ui/app/adapters/table.js index e878899..47174e4 100644 --- a/contrib/views/hive20/src/main/resources/ui/app/adapters/table.js +++ b/contrib/views/hive20/src/main/resources/ui/app/adapters/table.js @@ -49,6 +49,15 @@ export default DDLAdapter.extend({ return this.ajax(deletURL, 'DELETE'); }, + renameTable(database, newTableName, oldTableName) { + let renameUrl = this.buildURL('table', null, null, 'query', { databaseId: database, tableName: oldTableName }) + '/rename'; + let data = { + newDatabase: database, + newTable: newTableName + }; + return this.ajax(renameUrl, 'PUT', {data: data}); + }, + analyseTable(databaseName, tableName, withColumns = false) { let analyseUrl = this.buildURL('table', null, null, 'query', { databaseId: databaseName, tableName: tableName }) + '/analyze' + http://git-wip-us.apache.org/repos/asf/ambari/blob/52c2da12/contrib/views/hive20/src/main/resources/ui/app/components/table-rename-form.js ---------------------------------------------------------------------- diff --git a/contrib/views/hive20/src/main/resources/ui/app/components/table-rename-form.js b/contrib/views/hive20/src/main/resources/ui/app/components/table-rename-form.js new file mode 100644 index 0000000..7640dd6 --- /dev/null +++ b/contrib/views/hive20/src/main/resources/ui/app/components/table-rename-form.js @@ -0,0 +1,63 @@ +/** + * 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({ + classNames: ['form-horizontal'], + + errorCleaner: Ember.observer('newTableName', function() { + if(this.get('error')) { + this.clearError(); + } + }), + + validate() { + if(Ember.isEmpty(this.get('newTableName'))) { + this.setError("Table name cannot be empty"); + return false; + } + if(this.get('newTableName') === this.get('table.table')) { + this.setError("New table name cannot be same as the old table name"); + return false; + } + return true; + }, + + setError(message) { + this.set('error', true); + this.set('errorMessage', message); + }, + + clearError() { + this.set('error'); + this.set('errorMessage'); + }, + + actions: { + rename() { + if(this.validate()) { + this.sendAction('rename', this.get('newTableName')); + } + }, + + cancel() { + this.sendAction('cancel'); + } + } +}); http://git-wip-us.apache.org/repos/asf/ambari/blob/52c2da12/contrib/views/hive20/src/main/resources/ui/app/controllers/application.js ---------------------------------------------------------------------- diff --git a/contrib/views/hive20/src/main/resources/ui/app/controllers/application.js b/contrib/views/hive20/src/main/resources/ui/app/controllers/application.js index 54df442..beb97e6 100644 --- a/contrib/views/hive20/src/main/resources/ui/app/controllers/application.js +++ b/contrib/views/hive20/src/main/resources/ui/app/controllers/application.js @@ -17,9 +17,12 @@ */ import Ember from 'ember'; +import ENV from 'ui/config/environment'; export default Ember.Controller.extend({ serviceCheck: Ember.inject.service(), - serviceCheckCompleted: Ember.computed.alias('serviceCheck.transitionToApplication') + serviceCheckCompleted: Ember.computed('serviceCheck.transitionToApplication', function() { + return !ENV.APP.SHOULD_PERFORM_SERVICE_CHECK || this.get('serviceCheck.transitionToApplication'); + }) }); http://git-wip-us.apache.org/repos/asf/ambari/blob/52c2da12/contrib/views/hive20/src/main/resources/ui/app/router.js ---------------------------------------------------------------------- diff --git a/contrib/views/hive20/src/main/resources/ui/app/router.js b/contrib/views/hive20/src/main/resources/ui/app/router.js index 428cb43..52361ff 100644 --- a/contrib/views/hive20/src/main/resources/ui/app/router.js +++ b/contrib/views/hive20/src/main/resources/ui/app/router.js @@ -40,6 +40,7 @@ Router.map(function() { this.route('new'); this.route('upload-table'); this.route('table', {path: '/:name'}, function() { + this.route('rename'); this.route('columns'); this.route('partitions'); this.route('storage'); http://git-wip-us.apache.org/repos/asf/ambari/blob/52c2da12/contrib/views/hive20/src/main/resources/ui/app/routes/application.js ---------------------------------------------------------------------- diff --git a/contrib/views/hive20/src/main/resources/ui/app/routes/application.js b/contrib/views/hive20/src/main/resources/ui/app/routes/application.js index 697f727..f4ceeb9 100644 --- a/contrib/views/hive20/src/main/resources/ui/app/routes/application.js +++ b/contrib/views/hive20/src/main/resources/ui/app/routes/application.js @@ -18,6 +18,7 @@ import Ember from 'ember'; import tabs from '../configs/top-level-tabs'; +import ENV from 'ui/config/environment'; export default Ember.Route.extend({ keepAlive: Ember.inject.service('keep-alive'), @@ -28,7 +29,7 @@ export default Ember.Route.extend({ }, beforeModel() { - if (!this.get('serviceCheck.checkCompleted')) { + if (ENV.APP.SHOULD_PERFORM_SERVICE_CHECK && !this.get('serviceCheck.checkCompleted')) { this.transitionTo('service-check'); } }, http://git-wip-us.apache.org/repos/asf/ambari/blob/52c2da12/contrib/views/hive20/src/main/resources/ui/app/routes/databases/database/tables/table/rename.js ---------------------------------------------------------------------- diff --git a/contrib/views/hive20/src/main/resources/ui/app/routes/databases/database/tables/table/rename.js b/contrib/views/hive20/src/main/resources/ui/app/routes/databases/database/tables/table/rename.js new file mode 100644 index 0000000..cac471e --- /dev/null +++ b/contrib/views/hive20/src/main/resources/ui/app/routes/databases/database/tables/table/rename.js @@ -0,0 +1,83 @@ +/** + * 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 TableMetaRouter from './table-meta-router'; + +export default TableMetaRouter.extend({ + + tableOperations: Ember.inject.service(), + + activate() { + let tableController = this.controllerFor('databases.database.tables.table'); + this.set('existingTabs', tableController.get('tabs')); + tableController.set('tabs', []); + }, + + deactivate() { + let tableController = this.controllerFor('databases.database.tables.table'); + tableController.set('tabs', this.get('existingTabs')); + }, + + actions: { + cancel() { + this.transitionTo('databases.database.tables'); + }, + + rename(newTableName) { + let tableName = this.controller.get('table.table'); + let databaseName = this.controller.get('table.database'); + this._renameTo(newTableName, tableName, databaseName); + } + }, + + _renameTo(newTableName, oldTableName, databaseName) { + this._modalStatus(true, 'Submitting request to rename table'); + this.get('tableOperations').renameTable(databaseName, newTableName, oldTableName).then((job) => { + this._modalStatus(true, 'Waiting for the table to be renamed'); + return this.get('tableOperations').waitForJobToComplete(job.get('id'), 5 * 1000); + }).then((status) => { + this._modalStatus(true, 'Successfully renamed table'); + this._transitionToTables(); + }).catch((err) => { + this._modalStatus(true, 'Failed to rename table'); + this._alertMessage('Failed to rename table', err); + this._transitionToTables(); + }); + }, + + _modalStatus(status, message) { + this.controller.set('showModal', status); + if(status) { + this.controller.set('modalMessage', message); + } + }, + + _transitionToTables() { + Ember.run.later(() => { + this._modalStatus(false); + this.transitionTo('databases'); + }, 2000); + }, + + _alertMessage(message, err) { + console.log(message, err); + // TODO: user alert message here + } + + +}); http://git-wip-us.apache.org/repos/asf/ambari/blob/52c2da12/contrib/views/hive20/src/main/resources/ui/app/services/table-operations.js ---------------------------------------------------------------------- diff --git a/contrib/views/hive20/src/main/resources/ui/app/services/table-operations.js b/contrib/views/hive20/src/main/resources/ui/app/services/table-operations.js index e442a36..d11816c 100644 --- a/contrib/views/hive20/src/main/resources/ui/app/services/table-operations.js +++ b/contrib/views/hive20/src/main/resources/ui/app/services/table-operations.js @@ -56,6 +56,17 @@ export default Ember.Service.extend({ }) }, + renameTable(databaseName, newTableName, oldTableName ) { + return new Promise((resolve, reject) => { + this.get('store').adapterFor('table').renameTable(databaseName, newTableName, oldTableName).then((data) => { + this.get('store').pushPayload(data); + resolve(this.get('store').peekRecord('job', data.job.id)); + }, (err) => { + reject(err); + }); + }) + }, + deleteDatabase(database) { return new Promise((resolve, reject) => { this.get('store').adapterFor('database').deleteDatabase(database.get('name')).then((data) => { http://git-wip-us.apache.org/repos/asf/ambari/blob/52c2da12/contrib/views/hive20/src/main/resources/ui/app/templates/components/table-rename-form.hbs ---------------------------------------------------------------------- diff --git a/contrib/views/hive20/src/main/resources/ui/app/templates/components/table-rename-form.hbs b/contrib/views/hive20/src/main/resources/ui/app/templates/components/table-rename-form.hbs new file mode 100644 index 0000000..b692a9c --- /dev/null +++ b/contrib/views/hive20/src/main/resources/ui/app/templates/components/table-rename-form.hbs @@ -0,0 +1,31 @@ +{{! +* 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. +}} + +<div class="form-group"> + <label class="col-sm-4 control-label">New Table Name</label> + <div class="col-sm-8 {{if error 'has-error'}}"> + {{input value=newTableName class="form-control" placeholder="Table Name"}} + <span class="help-block">{{errorMessage}}</span> + </div> +</div> +<div class="form-group"> + <div class="col-sm-offset-4 col-sm-8"> + <button type="submit" class="btn btn-warning" {{action "rename"}}>{{fa-icon "pencil-square-o"}} Rename</button> + <button type="submit" class="btn btn-primary" {{action "cancel"}}>{{fa-icon "times"}} Cancel</button> + </div> +</div> http://git-wip-us.apache.org/repos/asf/ambari/blob/52c2da12/contrib/views/hive20/src/main/resources/ui/app/templates/databases/database/tables/table.hbs ---------------------------------------------------------------------- diff --git a/contrib/views/hive20/src/main/resources/ui/app/templates/databases/database/tables/table.hbs b/contrib/views/hive20/src/main/resources/ui/app/templates/databases/database/tables/table.hbs index 2d1d075..e3fe400 100644 --- a/contrib/views/hive20/src/main/resources/ui/app/templates/databases/database/tables/table.hbs +++ b/contrib/views/hive20/src/main/resources/ui/app/templates/databases/database/tables/table.hbs @@ -26,6 +26,7 @@ </button> <ul class="dropdown-menu dropdown-menu-right" aria-labelledby="dropdownMenu1"> <li><a href="#" class="text-uppercase" {{action "editTable" model}}>{{fa-icon "edit"}} Edit</a></li> + <li>{{#link-to "databases.database.tables.table.rename" class="text-uppercase"}}{{fa-icon "edit"}} Rename{{/link-to}}</li> <li><a href="#" class="text-uppercase" {{action "deleteTable" model}}>{{fa-icon "trash"}} Delete</a></li> </ul> </div> http://git-wip-us.apache.org/repos/asf/ambari/blob/52c2da12/contrib/views/hive20/src/main/resources/ui/app/templates/databases/database/tables/table/rename.hbs ---------------------------------------------------------------------- diff --git a/contrib/views/hive20/src/main/resources/ui/app/templates/databases/database/tables/table/rename.hbs b/contrib/views/hive20/src/main/resources/ui/app/templates/databases/database/tables/table/rename.hbs new file mode 100644 index 0000000..31da3d4 --- /dev/null +++ b/contrib/views/hive20/src/main/resources/ui/app/templates/databases/database/tables/table/rename.hbs @@ -0,0 +1,46 @@ +{{! +* 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. +}} + +<div class="row"> + <div class="alert alert-info"> + <p class="lead">{{fa-icon "pencil-square-o" size=1}} Rename table <strong class="text-uppercase">{{table.table}}</strong></p> + </div> +</div> + +<div class="row stats-section"> + <div class="col-md-6"> + {{table-rename-form table=table + cancel="cancel" + rename="rename"}} + </div> +</div> + +{{#if showModal}} + {{#modal-dialog + translucentOverlay=true + container-class="modal-dialog modal-sm"}} + <div class="modal-content"> + <div class="modal-header text-danger"> + <p class="modal-title">{{fa-icon "pencil-square-o"}} Rename Table</p> + </div> + <div class="modal-body text-center text-primary"> + <p>{{modalMessage}}</p> + </div> + </div><!-- /.modal-content --> + {{/modal-dialog}} +{{/if}} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/ambari/blob/52c2da12/contrib/views/hive20/src/main/resources/ui/config/environment.js ---------------------------------------------------------------------- diff --git a/contrib/views/hive20/src/main/resources/ui/config/environment.js b/contrib/views/hive20/src/main/resources/ui/config/environment.js index 98b3c8c..3714eb9 100644 --- a/contrib/views/hive20/src/main/resources/ui/config/environment.js +++ b/contrib/views/hive20/src/main/resources/ui/config/environment.js @@ -34,6 +34,7 @@ module.exports = function(environment) { APP: { // Here you can pass flags/options to your application instance // when it is created + SHOULD_PERFORM_SERVICE_CHECK: true } }; @@ -43,6 +44,11 @@ module.exports = function(environment) { // ENV.APP.LOG_TRANSITIONS = true; // ENV.APP.LOG_TRANSITIONS_INTERNAL = true; // ENV.APP.LOG_VIEW_LOOKUPS = true; + + + // Change the value to false to prevent the service checks. This is required in development mode + // as service checks take up time and hence increase the overall development time. + ENV.APP.SHOULD_PERFORM_SERVICE_CHECK = true; } if (environment === 'test') {