You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ambari.apache.org by jl...@apache.org on 2016/06/27 23:36:36 UTC
[10/34] ambari git commit: AMBARI-17355 & AMBARI-17354: POC: FE & BE
changes for first class support for Yarn hosted services
http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/resources/ui/hive-web/app/controllers/queries.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/app/controllers/queries.js b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/controllers/queries.js
new file mode 100644
index 0000000..cbf6b42
--- /dev/null
+++ b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/controllers/queries.js
@@ -0,0 +1,125 @@
+/**
+ * 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 FilterableMixin from 'hive/mixins/filterable';
+import constants from 'hive/utils/constants';
+
+export default Ember.ArrayController.extend(FilterableMixin, {
+ needs: [ constants.namingConventions.routes.history,
+ constants.namingConventions.openQueries ],
+
+ history: Ember.computed.alias('controllers.' + constants.namingConventions.routes.history),
+ openQueries: Ember.computed.alias('controllers.' + constants.namingConventions.openQueries),
+
+ sortAscending: true,
+ sortProperties: [],
+
+ init: function () {
+ this._super();
+
+ this.set('columns', Ember.ArrayProxy.create({ content: Ember.A([
+ Ember.Object.create({
+ caption: "columns.shortQuery",
+ property: 'shortQuery',
+ link: constants.namingConventions.subroutes.savedQuery
+ }),
+ Ember.Object.create({
+ caption: "columns.title",
+ property: 'title',
+ link: constants.namingConventions.subroutes.savedQuery
+ }),
+ Ember.Object.create({
+ caption: "columns.database",
+ property: 'dataBase',
+ link: constants.namingConventions.subroutes.savedQuery
+ }),
+ Ember.Object.create({
+ caption: "columns.owner",
+ property: 'owner',
+ link: constants.namingConventions.subroutes.savedQuery
+ })
+ ])}));
+ },
+
+ //row buttons
+ links: [
+ "buttons.history",
+ "buttons.delete"
+ ],
+
+ model: function () {
+ return this.filter(this.get('queries'));
+ }.property('queries', 'filters.@each'),
+
+ actions: {
+ executeAction: function (action, savedQuery) {
+ var self = this;
+
+ switch (action) {
+ case "buttons.history":
+ this.get('history').filterBy('queryId', savedQuery.get('id'), true);
+ this.transitionToRoute(constants.namingConventions.routes.history);
+ break;
+ case "buttons.delete":
+ var defer = Ember.RSVP.defer();
+ this.send('openModal',
+ 'modal-delete',
+ {
+ heading: "modals.delete.heading",
+ text: "modals.delete.message",
+ defer: defer
+ });
+
+ defer.promise.then(function () {
+ savedQuery.destroyRecord();
+ self.get('openQueries').updatedDeletedQueryTab(savedQuery);
+ });
+
+ break;
+ }
+ },
+
+ sort: function (property) {
+ //if same column has been selected, toggle flag, else default it to true
+ if (this.get('sortProperties').objectAt(0) === property) {
+ this.set('sortAscending', !this.get('sortAscending'));
+ } else {
+ this.set('sortAscending', true);
+ this.set('sortProperties', [ property ]);
+ }
+ },
+
+ clearFilters: function () {
+ var columns = this.get('columns');
+
+ if (columns) {
+ columns.forEach(function (column) {
+ var filterValue = column.get('filterValue');
+
+ if (filterValue && typeof filterValue === 'string') {
+ column.set('filterValue');
+ }
+ });
+ }
+
+ //call clear filters from Filterable mixin
+ this.clearFilters();
+ }
+ }
+});
http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/resources/ui/hive-web/app/controllers/query-tabs.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/app/controllers/query-tabs.js b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/controllers/query-tabs.js
new file mode 100644
index 0000000..5f31c19
--- /dev/null
+++ b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/controllers/query-tabs.js
@@ -0,0 +1,176 @@
+/**
+ * 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 constants from 'hive/utils/constants';
+
+export default Ember.Controller.extend({
+ jobProgressService: Ember.inject.service(constants.namingConventions.jobProgress),
+ openQueries : Ember.inject.controller(constants.namingConventions.openQueries),
+ notifyService: Ember.inject.service(constants.namingConventions.notify),
+ index: Ember.inject.controller(),
+
+ tabClassNames : "fa queries-icon query-context-tab",
+
+ tabs: [
+ Ember.Object.create({
+ iconClass: 'text-icon',
+ id: 'query-icon',
+ text: 'SQL',
+ action: 'setDefaultActive',
+ name: constants.namingConventions.index,
+ tooltip: Ember.I18n.t('tooltips.query')
+ }),
+ Ember.Object.create({
+ iconClass: 'fa-gear',
+ id: 'settings-icon',
+ action: 'toggleOverlay',
+ template: 'settings',
+ outlet: 'overlay',
+ into: 'open-queries',
+ tooltip: Ember.I18n.t('tooltips.settings')
+ }),
+ Ember.Object.create({
+ iconClass: 'fa-area-chart',
+ id: 'visualization-icon',
+ action: 'toggleOverlay',
+ tooltip: Ember.I18n.t('tooltips.visualization'),
+ into: 'index',
+ outlet: 'overlay',
+ template: 'visualization-ui',
+ onTabOpen: 'onTabOpen'
+ }),
+ Ember.Object.create({
+ iconClass: 'fa-link',
+ id: 'visual-explain-icon',
+ action: 'toggleOverlay',
+ template: 'visual-explain',
+ outlet: 'overlay',
+ into: 'index',
+ onTabOpen: 'onTabOpen',
+ tooltip: Ember.I18n.t('tooltips.visualExplain')
+ }),
+ Ember.Object.create({
+ iconClass: 'text-icon',
+ id: 'tez-icon',
+ text: 'TEZ',
+ action: 'toggleOverlay',
+ template: 'tez-ui',
+ outlet: 'overlay',
+ into: 'index',
+ tooltip: Ember.I18n.t('tooltips.tez')
+ }),
+ Ember.Object.create({
+ iconClass: 'fa-envelope',
+ id: 'notifications-icon',
+ action: 'toggleOverlay',
+ template: 'messages',
+ outlet: 'overlay',
+ into: 'index',
+ badgeProperty: 'count',
+ onTabOpen: 'markMessagesAsSeen',
+ tooltip: Ember.I18n.t('tooltips.notifications')
+ })
+ ],
+
+ init: function() {
+ this.setupControllers();
+ this.setDefaultTab();
+ this.setupTabsBadges();
+ },
+
+ setupControllers: function() {
+ var tabs = this.get('tabs');
+ var self = this;
+
+ tabs.map(function (tab) {
+ var controller;
+
+ if (tab.get('template')) {
+ controller = self.container.lookup('controller:' + tab.get('template'));
+ tab.set('controller', controller);
+ }
+ });
+ },
+
+ setDefaultTab: function () {
+ var defaultTab = this.get('tabs.firstObject');
+
+ defaultTab.set('active', true);
+
+ this.set('default', defaultTab);
+ this.set('activeTab', defaultTab);
+ },
+
+ setupTabsBadges: function () {
+ var tabs = this.get('tabs').filterProperty('badgeProperty');
+
+ tabs.map(function (tab) {
+ Ember.oneWay(tab, 'badge', 'controller.' + tab.badgeProperty);
+ });
+ },
+
+ closeActiveOverlay: function () {
+ this.send('closeOverlay', this.get('activeTab'));
+ },
+
+ onTabOpen: function (tab) {
+ if (!tab.onTabOpen) {
+ return;
+ }
+
+ var controller = this.container.lookup('controller:' + tab.template);
+ controller.send(tab.onTabOpen, controller);
+ },
+
+ openOverlay: function (tab) {
+ this.closeActiveOverlay();
+ this.set('activeTab.active', false);
+ tab.set('active', true);
+ this.set('activeTab', tab);
+
+ this.onTabOpen(tab);
+ this.send('openOverlay', tab);
+ },
+
+ setDefaultActive: function () {
+ var activeTab = this.get('activeTab');
+ var defaultTab = this.get('default');
+
+ if (activeTab !== defaultTab) {
+ this.closeActiveOverlay();
+ defaultTab.set('active', true);
+ activeTab.set('active', false);
+ this.set('activeTab', defaultTab);
+ }
+ },
+
+ actions: {
+ toggleOverlay: function (tab) {
+ if (tab !== this.get('default') && tab.get('active')) {
+ this.setDefaultActive();
+ } else {
+ this.openOverlay(tab);
+ }
+ },
+
+ setDefaultActive: function () {
+ this.setDefaultActive();
+ }
+ }
+});
http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/resources/ui/hive-web/app/controllers/settings.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/app/controllers/settings.js b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/controllers/settings.js
new file mode 100644
index 0000000..77250b4
--- /dev/null
+++ b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/controllers/settings.js
@@ -0,0 +1,69 @@
+/**
+ * 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.Controller.extend({
+ openQueries: Ember.inject.controller(),
+ index: Ember.inject.controller(),
+
+ settingsService: Ember.inject.service('settings'),
+
+ predefinedSettings: Ember.computed.alias('settingsService.predefinedSettings'),
+ settings: Ember.computed.alias('settingsService.settings'),
+
+ init: function() {
+ this._super();
+
+ this.get('settingsService').loadDefaultSettings();
+ },
+
+ excluded: function() {
+ var settings = this.get('settings');
+
+ return this.get('predefinedSettings').filter(function(setting) {
+ return settings.findBy('key.name', setting.name);
+ });
+ }.property('settings.@each.key'),
+
+ parseGlobalSettings: function () {
+ this.get('settingsService').parseGlobalSettings(this.get('openQueries.currentQuery'), this.get('index.model'));
+ }.observes('openQueries.currentQuery', 'openQueries.currentQuery.fileContent', 'openQueries.tabUpdated').on('init'),
+
+ actions: {
+ add: function () {
+ this.get('settingsService').add();
+ },
+
+ remove: function (setting) {
+ this.get('settingsService').remove(setting);
+ },
+
+ addKey: function (name) {
+ this.get('settingsService').createKey(name);
+ },
+
+ removeAll: function () {
+ this.get('settingsService').removeAll();
+ },
+
+ saveDefaultSettings: function() {
+ this.get('settingsService').saveDefaultSettings();
+ }
+ }
+});
http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/resources/ui/hive-web/app/controllers/splash.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/app/controllers/splash.js b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/controllers/splash.js
new file mode 100644
index 0000000..5db93f7
--- /dev/null
+++ b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/controllers/splash.js
@@ -0,0 +1,126 @@
+/**
+ * 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 constants from 'hive/utils/constants';
+
+export default Ember.Controller.extend({
+
+ databaseService: Ember.inject.service(constants.namingConventions.database),
+ isExpanded: false,
+ errors: "",
+ stackTrace: "",
+ startTests: function() {
+
+ var model = this.get('model');
+ var url = this.container.lookup('adapter:application').buildURL() + '/resources/hive/'
+ var self = this;
+
+ var processResponse = function(name, data) {
+
+ if( data != undefined ){
+ if(data.databases){
+ data = Ember.Object.create( {trace: null, message: "OK", status: "200"});
+ } else {
+ data = data;
+ }
+ } else {
+ data = Ember.Object.create( {trace: null, message: "Server Error", status: "500"});
+ }
+
+ model.set(name + 'Test', data.status == 200);
+
+ if (data.status != 200) {
+ var checkFailedMessage = "Service '" + name + "' check failed";
+ var errors = self.get("errors");
+ errors += checkFailedMessage;
+ errors += (data.message)?(': <i>' + data.message + '</i><br>'):'<br>';
+ self.set("errors", errors);
+ }
+
+ if (data.trace != null) {
+ var stackTrace = self.get("stackTrace");
+ stackTrace += checkFailedMessage + ':\n' + data.trace;
+ self.set("stackTrace", stackTrace);
+ }
+
+ model.set(name + 'TestDone', true);
+
+ var percent = model.get('percent');
+ model.set('percent', percent + 33.33);
+ };
+
+ var promises = ['hdfs', 'hiveserver', 'ats'].map(function(name) {
+
+ var finalurl = ((name == 'hiveserver') ? self.get('databaseService.baseUrl') : (url + name + 'Status')) || '' ;
+
+ return Ember.$.getJSON( finalurl )
+ .then(
+ function(data) {
+ processResponse(name, data);
+ },
+ function(reason) {
+ processResponse(name, reason.responseJSON);
+ }
+ );
+ });
+
+ return Ember.RSVP.all(promises);
+ },
+
+ progressBarStyle: function() {
+ return 'width: ' + this.get("model").get("percent") + '%;';
+ }.property("model.percent"),
+
+ allTestsCompleted: function(){
+ return this.get('modelhdfsTestDone') && this.get('modelhiveserverTestDone') && this.get('modelatsTestDone');
+ }.property('modelhdfsTestDone', 'modelhiveserverTestDone', 'modelatsTestDone'),
+
+ modelhdfsTestDone: function() {
+ return this.get('model.hdfsTestDone');
+ }.property('model.hdfsTestDone' ),
+
+ modelhiveserverTestDone: function() {
+ return this.get('model.hiveserverTestDone');
+ }.property('model.hiveserverTestDone' ),
+
+ modelatsTestDone: function() {
+ return this.get('model.atsTestDone');
+ }.property('model.atsTestDone' ),
+
+ modelhdfsTest: function() {
+ return this.get('model.hdfsTest');
+ }.property('model.hdfsTest' ),
+
+ modelhiveserverTest: function() {
+ return this.get('model.hiveserverTest');
+ }.property('model.hiveserverTest' ),
+
+ modelatsTest: function() {
+ return this.get('model.atsTest');
+ }.property('model.atsTest' ),
+
+ actions: {
+ toggleStackTrace:function () {
+ var value = this.get('isExpanded');
+ this.set('isExpanded', !value);
+ }
+ }
+});
+
+
http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/resources/ui/hive-web/app/controllers/tez-ui.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/app/controllers/tez-ui.js b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/controllers/tez-ui.js
new file mode 100644
index 0000000..43835e0
--- /dev/null
+++ b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/controllers/tez-ui.js
@@ -0,0 +1,106 @@
+/**
+ * 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 constants from 'hive/utils/constants';
+
+export default Ember.Controller.extend({
+ needs: [ constants.namingConventions.index ],
+
+ index: Ember.computed.alias('controllers.' + constants.namingConventions.index),
+
+ tezViewURL: null,
+ tezApiURL: '/api/v1/views/TEZ',
+ tezURLPrefix: '/views/TEZ',
+ tezDagPath: '?viewPath=/#/dag/',
+
+ isTezViewAvailable: Ember.computed.bool('tezViewURL'),
+
+ dagId: function () {
+ if (this.get('isTezViewAvailable')) {
+ return this.get('index.model.dagId');
+ }
+
+ return false;
+ }.property('index.model.dagId', 'isTezViewAvailable'),
+
+ dagURL: function () {
+ if (this.get('dagId')) {
+ return "%@%@%@".fmt(this.get('tezViewURL'), this.get('tezDagPath'), this.get('dagId'));
+ }
+
+ return false;
+ }.property('dagId'),
+
+ getTezView: function () {
+ if (this.get('isTezViewAvailable')) {
+ return;
+ }
+
+ var self = this;
+ Ember.$.getJSON(this.get('tezApiURL'))
+ .then(function (response) {
+ self.getTezViewInstance(response);
+ })
+ .fail(function (response) {
+ self.setTezViewError(response);
+ });
+ }.on('init'),
+
+ getTezViewInstance: function (data) {
+ var self = this;
+ var url = this.get('tezApiURL') + '/versions/' + data.versions[0].ViewVersionInfo.version;
+
+ Ember.$.getJSON(url)
+ .then(function (response) {
+ if (!response.instances.length) {
+ self.setTezViewError(response);
+ return;
+ }
+
+ self.set('isTezViewAvailable', true);
+
+ var instance = response.instances[0].ViewInstanceInfo;
+ self.setTezViewURL(instance);
+ });
+ },
+
+ setTezViewURL: function (instance) {
+ var url = "%@/%@/%@/".fmt(
+ this.get('tezURLPrefix'),
+ instance.version,
+ instance.instance_name
+ );
+
+ this.set('tezViewURL', url);
+ },
+
+ setTezViewError: function (data) {
+ // status: 404 => Tev View isn't deployed
+ if (data.status && data.status === 404) {
+ this.set('error', 'tez.errors.not.deployed');
+ return;
+ }
+
+ // no instance created
+ if (data.instances && !data.instances.length) {
+ this.set('error', 'tez.errors.no.instance');
+ return;
+ }
+ }
+});
http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/resources/ui/hive-web/app/controllers/udfs.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/app/controllers/udfs.js b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/controllers/udfs.js
new file mode 100644
index 0000000..3aec378
--- /dev/null
+++ b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/controllers/udfs.js
@@ -0,0 +1,143 @@
+/**
+ * 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 FilterableMixin from 'hive/mixins/filterable';
+import constants from 'hive/utils/constants';
+
+export default Ember.ArrayController.extend(FilterableMixin, {
+ fileResources: [],
+
+ sortAscending: true,
+ sortProperties: [],
+
+ columns: [
+ Ember.Object.create({
+ caption: 'placeholders.udfs.name',
+ property: 'name'
+ }),
+ Ember.Object.create({
+ caption: 'placeholders.udfs.className',
+ property: 'classname'
+ })
+ ],
+
+ model: function () {
+ return this.filter(this.get('udfs'));
+ }.property('udfs', 'filters.@each'),
+
+ actions: {
+ handleAddFileResource: function (udf) {
+ var file = this.store.createRecord(constants.namingConventions.fileResource);
+ udf.set('fileResource', file);
+ udf.set('isEditingResource', true);
+ },
+
+ handleDeleteFileResource: function (file) {
+ var defer = Ember.RSVP.defer();
+
+ this.send('openModal',
+ 'modal-delete',
+ {
+ heading: 'modals.delete.heading',
+ text: 'modals.delete.message',
+ defer: defer
+ });
+
+ defer.promise.then(function () {
+ file.destroyRecord();
+ });
+ },
+
+ handleSaveUdf: function (udf) {
+ var self = this,
+ saveUdf = function () {
+ udf.save().then(function () {
+ udf.set('isEditing', false);
+ udf.set('isEditingResource', false);
+ });
+ };
+
+ //replace with a validation system if needed.
+ if (!udf.get('name') || !udf.get('classname')) {
+ return;
+ }
+
+ udf.get('fileResource').then(function (file) {
+ if (file) {
+ if (!file.get('name') || !file.get('path')) {
+ return;
+ }
+
+ file.save().then(function () {
+ saveUdf();
+ });
+ } else {
+ saveUdf();
+ }
+ });
+ },
+
+ handleDeleteUdf: function (udf) {
+ var defer = Ember.RSVP.defer();
+
+ this.send('openModal',
+ 'modal-delete',
+ {
+ heading: 'modals.delete.heading',
+ text: 'modals.delete.message',
+ defer: defer
+ });
+
+ defer.promise.then(function () {
+ udf.destroyRecord();
+ });
+ },
+
+ sort: function (property) {
+ //if same column has been selected, toggle flag, else default it to true
+ if (this.get('sortProperties').objectAt(0) === property) {
+ this.set('sortAscending', !this.get('sortAscending'));
+ } else {
+ this.set('sortAscending', true);
+ this.set('sortProperties', [ property ]);
+ }
+ },
+
+ add: function () {
+ this.store.createRecord(constants.namingConventions.udf);
+ },
+
+ clearFilters: function () {
+ var columns = this.get('columns');
+
+ if (columns) {
+ columns.forEach(function (column) {
+ var filterValue = column.get('filterValue');
+
+ if (filterValue && typeof filterValue === 'string') {
+ column.set('filterValue');
+ }
+ });
+ }
+
+ //call clear filters from Filterable mixin
+ this.clearFilters();
+ }
+ }
+});
http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/resources/ui/hive-web/app/controllers/upload-table.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/app/controllers/upload-table.js b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/controllers/upload-table.js
new file mode 100644
index 0000000..3f17760
--- /dev/null
+++ b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/controllers/upload-table.js
@@ -0,0 +1,740 @@
+/**
+ * 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 Uploader from 'hive/adapters/upload-table'
+import constants from 'hive/utils/constants';
+
+
+export default Ember.Controller.extend({
+ isLocalUpload : Ember.computed.equal("uploadSource","local"),
+ uploadSource : "local",
+ hdfsPath : "",
+ jobService: Ember.inject.service(constants.namingConventions.job),
+ notifyService: Ember.inject.service(constants.namingConventions.notify),
+ needs: ['databases'],
+ showErrors: false,
+ uploader: Uploader.create(),
+ baseUrl: "/resources/upload",
+ isFirstRowHeader: true, // is first row header
+ header: null, // header received from server
+ files: null, // files that need to be uploaded only file[0] is relevant
+ firstRow: [], // the actual first row of the table.
+ rows: null, // preview rows received from server
+ databaseName: null,
+ selectedDatabase: null,
+ filePath: null,
+ tableName: null,
+ uploadProgressInfos : [],
+ onChangeUploadSource : function(){
+ this.clearFields();
+ }.observes("uploadSource"),
+ uploadProgressInfo : Ember.computed("uploadProgressInfos.[]",function(){
+ var info = "";
+ for( var i = 0 ; i < this.get('uploadProgressInfos').length ; i++)
+ info += this.get('uploadProgressInfos').objectAt(i);
+
+ return new Ember.Handlebars.SafeString(info);
+ }),
+ inputFileTypes :[
+ {id : "CSV", name : "CSV"},
+ {id : "JSON", name : "JSON"},
+ {id : "XML", name : "XML"}
+ ],
+ inputFileType : {id : "CSV", name : "CSV"},
+ inputFileTypeCSV : Ember.computed.equal('inputFileType.id',"CSV"),
+ fileTypes:[
+ "SEQUENCEFILE",
+ "TEXTFILE" ,
+ "RCFILE" ,
+ "ORC" ,
+ "PARQUET" ,
+ "AVRO" ,
+ "INPUTFORMAT"
+ ],
+ selectedFileType: "ORC",
+ dataTypes: [
+ "TINYINT", //
+ "SMALLINT", //
+ "INT", //
+ "BIGINT", //
+ "BOOLEAN", //
+ "FLOAT", //
+ "DOUBLE", //
+ "STRING", //
+ "BINARY", // -- (Note: Available in Hive 0.8.0 and later)
+ "TIMESTAMP", // -- (Note: Available in Hive 0.8.0 and later)
+ "DECIMAL", // -- (Note: Available in Hive 0.11.0 and later)
+ "DATE", // -- (Note: Available in Hive 0.12.0 and later)
+ "VARCHAR", // -- (Note: Available in Hive 0.12.0 and later)
+ "CHAR" // -- (Note: Available in Hive 0.13.0 and later)
+ ],
+ 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')) {
+ this.get('rows').unshiftObject({row: this.get('firstRow')});
+ }
+ } else if( this.get('header') ) { // headers are available
+ // take first row of
+ this.get('header').forEach(function (item, index) {
+ console.log("item : ", item);
+ console.log("this.get('firstRow').objectAt(index) : ", this.get('firstRow').objectAt(index));
+ Ember.set(item, 'name', this.get('firstRow')[index]);
+ }, this);
+
+ this.get('rows').removeAt(0);
+ }
+
+ this.printValues();
+ }
+ }.observes('isFirstRowHeader'),
+
+ 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();
+ }
+ },
+
+ hideUploadModal : function(){
+ console.log("hiding the modal ....");
+ this.clearUploadProgressModal();
+ Ember.$("#uploadProgressModal").modal("hide");
+ },
+
+ showUploadModal : function(){
+ Ember.$("#uploadProgressModal").modal("show");
+ },
+
+ clearFields: function () {
+ this.set("hdfsPath");
+ this.set("header");
+ this.set("rows");
+ this.set("error");
+ this.set('isFirstRowHeader',true);
+ this.set('files');
+ this.set("firstRow");
+ this.set("selectedDatabase",null);
+ this.set("databaseName");
+ this.set("filePath");
+ this.set('tableName');
+ this.clearUploadProgressModal();
+ this.printValues();
+ },
+
+ 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'));
+ },
+
+ generateTempTableName : function(){
+ var text = "";
+ var possible = "abcdefghijklmnopqrstuvwxyz";
+
+ for( var i=0; i < 30; i++ )
+ text += possible.charAt(Math.floor(Math.random() * possible.length));
+
+ return text;
+ },
+
+ waitForJobStatus: function (jobId, resolve, reject) {
+ console.log("finding status of job: ", jobId);
+ 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) {
+ console.log("rejecting waitForJobStatus with : " + error);
+ reject(error);
+ })
+ },
+
+ uploadForPreview: function (files) {
+ console.log("uploaderForPreview called.");
+ var self = this;
+ return this.get('uploader').uploadFiles('preview', files, {"isFirstRowHeader" : self.get("isFirstRowHeader"), "inputFileType" : self.get("inputFileType").id});
+ },
+
+ uploadForPreviewFromHDFS : function(){
+ console.log("uploadForPreviewFromHDFS called.");
+ return this.get('uploader').previewFromHDFS({"isFirstRowHeader" : this.get("isFirstRowHeader"),"inputFileType" : this.get("inputFileType").id , "hdfsPath" : this.get("hdfsPath") });
+ },
+
+ generatePreview : function(files){
+ var self = this;
+ var promise = null;
+ this.waitForGeneratingPreview();
+ if(this.get('isLocalUpload')){
+ promise = this.uploadForPreview(files);
+ }else{
+ promise = this.uploadForPreviewFromHDFS();
+ }
+
+ return promise.then(function (data) {
+ self.onGeneratePreviewSuccess(data);
+ }, function (error) {
+ self.onGeneratePreviewFailure(error);
+ });
+ },
+
+ waitForGeneratingPreview: function () {
+ console.log("waitForGeneratingPreview");
+ this.showUploadModal();
+ this.pushUploadProgressInfos("<li> Generating Preview .... </li>")
+ },
+
+ previewTable: function (data) {
+ console.log('inside previewTable');
+ 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){
+ data.rows = data.rows.slice(1);
+ }
+ this.set("rows", data.rows);
+ },
+
+ onGeneratePreviewSuccess: function (data) {
+ console.log("onGeneratePreviewSuccess");
+ this.hideUploadModal();
+ this.previewTable(data);
+ },
+
+ onGeneratePreviewFailure: function (error) {
+ console.log("onGeneratePreviewFailure");
+ this.hideUploadModal();
+ this.setError(error);
+ },
+
+ createTable: function () {
+ console.log("table headers : ", this.get('header'));
+ 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'));
+ }
+
+ this.set('databaseName', this.get('selectedDatabase').get('name'));
+ var databaseName = this.get('databaseName');
+ var tableName = this.get('tableName');
+ 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();
+
+ return this.get('uploader').createTable({
+ "isFirstRowHeader": isFirstRowHeader,
+ "header": headers,
+ "tableName": tableName,
+ "databaseName": databaseName,
+ "fileType":filetype
+ });
+ },
+
+ 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>");
+ var self = this;
+ var p = new Ember.RSVP.Promise(function (resolve, reject) {
+ self.waitForJobStatus(jobId, resolve, reject);
+ });
+
+ return p;
+ },
+
+ onCreateActualTableSuccess : function(){
+ console.log("onCreateTableSuccess");
+ this.popUploadProgressInfos();
+ this.pushUploadProgressInfos("<li> Successfully created Actual table. </li>");
+ },
+
+ onCreateActualTableFailure : function(error){
+ console.log("onCreateActualTableFailure");
+ this.popUploadProgressInfos();
+ this.pushUploadProgressInfos("<li> Failed to create Actual table. </li>");
+ this.setError(error);
+ },
+
+ createTempTable : function(){
+ console.log("createTempTable");
+ this.pushUploadProgressInfos("<li> Starting to create Temporary table.... </li>");
+ var tempTableName = this.generateTempTableName();
+ this.set('tempTableName',tempTableName);
+ return this.get('uploader').createTable({
+ "isFirstRowHeader": this.get("isFirstRowHeader"),
+ "header": this.get("header"),
+ "tableName": tempTableName,
+ "databaseName": this.get('databaseName'),
+ "fileType":"TEXTFILE"
+ });
+ },
+
+ waitForCreateTempTable: function (jobId) {
+ console.log("waitForCreateTempTable");
+ this.popUploadProgressInfos();
+ this.pushUploadProgressInfos("<li> Waiting for creation of Temporary table.... </li>");
+ var self = this;
+ var p = new Ember.RSVP.Promise(function (resolve, reject) {
+ self.waitForJobStatus(jobId, resolve, reject);
+ });
+
+ return p;
+ },
+
+ onCreateTempTableSuccess : function(){
+ console.log("onCreateTempTableSuccess");
+ this.popUploadProgressInfos();
+ this.pushUploadProgressInfos("<li> Successfully created Temporary table. </li>");
+ },
+
+ deleteTable : function(databaseName, tableName){
+ console.log("deleting table " + databaseName + "." + tableName);
+
+ return this.get('uploader').deleteTable({
+ "database": databaseName,
+ "table": tableName
+ });
+ },
+
+ deleteTableOnError : function(databaseName,tableName, tableLabel){
+ //delete table and wait for delete job
+ var self = this;
+ this.pushUploadProgressInfos("<li> Deleting " + tableLabel + " table... </li>");
+
+ return this.deleteTable(databaseName,tableName).then(function(data){
+ return new Ember.RSVP.Promise(function(resolve,reject){
+ self.waitForJobStatus(data.jobId,resolve,reject);
+ });
+ }).then(function(){
+ self.popUploadProgressInfos();
+ self.pushUploadProgressInfos("<li> Successfully deleted " + tableLabel + " table. </li>");
+ return Ember.RSVP.Promise.resolve();
+ },function(err){
+ self.popUploadProgressInfos();
+ self.pushUploadProgressInfos("<li> Failed to delete " + tableLabel + " table. </li>");
+ self.setError(err);
+ return Ember.RSVP.Promise.reject();
+ });
+ },
+
+ rollBackActualTableCreation : function(){
+ return this.deleteTableOnError(this.get("databaseName"),this.get("tableName"),"Actual");
+ },
+
+
+ onCreateTempTableFailure : function(error){
+ console.log("onCreateTempTableFailure");
+ this.setError(error);
+ this.popUploadProgressInfos();
+ this.pushUploadProgressInfos("<li> Failed to create temporary table. </li>");
+ return this.rollBackActualTableCreation().then(function(data){
+ return Ember.RSVP.Promise.reject(error); // always reject for the flow to stop
+ },function(err){
+ return Ember.RSVP.Promise.reject(error); // always reject for the flow to stop
+ });
+ },
+
+ uploadFile : function(){
+ console.log("uploadFile");
+ this.pushUploadProgressInfos("<li> Starting to upload the file .... </li>");
+ if( this.get("isLocalUpload")){
+ return this.uploadTable();
+ }else{
+ return this.uploadTableFromHdfs();
+ }
+ },
+
+ waitForUploadingFile: function (data) {
+ console.log("waitForUploadingFile");
+ this.popUploadProgressInfos();
+ this.pushUploadProgressInfos("<li> Waiting for uploading file .... </li>");
+ if( data.jobId ){
+ var self = this;
+ var p = new Ember.RSVP.Promise(function (resolve, reject) {
+ self.waitForJobStatus(data.jobId, resolve, reject);
+ });
+ return p;
+ }else{
+ return Ember.RSVP.Promise.resolve(data);
+ }
+ },
+
+ onUploadingFileSuccess: function () {
+ console.log("onUploadingFileSuccess");
+ this.popUploadProgressInfos();
+ this.pushUploadProgressInfos("<li> Successfully uploaded file. </li>");
+ },
+
+ rollBackTempTableCreation : function(){
+ var self = this;
+ return this.deleteTableOnError(this.get("databaseName"),this.get("tempTableName"),"Temporary").then(function(data){
+ return self.rollBackActualTableCreation();
+ },function(err){
+ return self.rollBackActualTableCreation();
+ })
+ },
+
+ onUploadingFileFailure: function (error) {
+ console.log("onUploadingFileFailure");
+ this.setError(error);
+ this.popUploadProgressInfos();
+ this.pushUploadProgressInfos("<li> Failed to upload file. </li>");
+ return this.rollBackTempTableCreation().then(function(data){
+ return Ember.RSVP.Promise.reject(error); // always reject for the flow to stop
+ },function(err){
+ return Ember.RSVP.Promise.reject(error); // always reject for the flow to stop
+ });
+ },
+
+ rollBackUploadFile : function(){
+ return this.rollBackTempTableCreation();
+ },
+
+ insertIntoTable : function(){
+ console.log("insertIntoTable");
+ this.pushUploadProgressInfos("<li> Starting to Insert rows from temporary table to actual table .... </li>");
+
+ return this.get('uploader').insertIntoTable({
+ "fromDatabase": this.get("databaseName"),
+ "fromTable": this.get("tempTableName"),
+ "toDatabase": this.get("databaseName"),
+ "toTable": this.get("tableName")
+ });
+ },
+
+ waitForInsertIntoTable: function (jobId) {
+ console.log("waitForInsertIntoTable");
+ this.popUploadProgressInfos();
+ this.pushUploadProgressInfos("<li> Waiting for Insertion of rows from temporary table to actual table .... </li>");
+ var self = this;
+ var p = new Ember.RSVP.Promise(function (resolve, reject) {
+ self.waitForJobStatus(jobId, resolve, reject);
+ });
+
+ return p;
+ },
+
+ onInsertIntoTableSuccess : function(){
+ console.log("onInsertIntoTableSuccess");
+ this.popUploadProgressInfos();
+ this.pushUploadProgressInfos("<li> Successfully inserted rows from temporary table to actual table. </li>");
+ },
+
+ 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>");
+ return this.rollBackUploadFile().then(function(data){
+ return Ember.RSVP.Promise.reject(error); // always reject for the flow to stop
+ },function(err){
+ return Ember.RSVP.Promise.reject(error); // always reject for the flow to stop
+ });
+ },
+
+ deleteTempTable : function(){
+ console.log("deleteTempTable");
+ this.pushUploadProgressInfos("<li> Starting to delete temporary table .... </li>");
+
+ return this.deleteTable(
+ this.get("databaseName"),
+ this.get("tempTableName")
+ );
+ },
+
+ waitForDeleteTempTable: function (jobId) {
+ console.log("waitForDeleteTempTable");
+ this.popUploadProgressInfos();
+ this.pushUploadProgressInfos("<li> Waiting for deletion of temporary table .... </li>");
+ var self = this;
+ var p = new Ember.RSVP.Promise(function (resolve, reject) {
+ self.waitForJobStatus(jobId, resolve, reject);
+ });
+
+ return p;
+ },
+
+ onDeleteTempTableSuccess : function(){
+ console.log("onDeleteTempTableSuccess");
+ this.popUploadProgressInfos();
+ this.pushUploadProgressInfos("<li>Successfully inserted row. </li>");
+ 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"));
+ },
+
+ 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);
+ throw error;
+ })
+ .then(function(data){
+ console.log("2. received data : ", data);
+ self.onCreateActualTableSuccess(data);
+ return self.createTempTable(data);
+ },function(error){
+ if(!self.get('error')){
+ console.log("Error occurred: ", error);
+ self.onCreateActualTableFailure(new Error("Server job for creation of actual table failed."));
+ }
+ throw error;
+ })
+ .then(function(data){
+ console.log("3. received data : ", data);
+ return self.waitForCreateTempTable(data.jobId);
+ },function(error){
+ if(!self.get('error')){
+ console.log("Error occurred: ", error);
+ return self.onCreateTempTableFailure(error);
+ }
+ throw error;
+ })
+ .then(function(data){
+ console.log("4. received data : ", data);
+ self.onCreateTempTableSuccess(data);
+ return self.uploadFile(data);
+ },function(error){
+ if(!self.get('error')){
+ console.log("Error occurred: ", error);
+ return self.onCreateTempTableFailure(new Error("Server job for creation of temporary table failed."));
+ }
+ throw error;
+ }).then(function(data){
+ console.log("4.5 received data : ", data);
+ return self.waitForUploadingFile(data);
+ },function(error){
+ if(!self.get('error')){
+ console.log("Error occurred: ", error);
+ return self.onUploadingFileFailure(error);
+ }
+ throw error;
+ })
+ .then(function(data){
+ console.log("5. received data : ", data);
+ self.onUploadingFileSuccess(data);
+ return self.insertIntoTable(data);
+ },function(error){
+ if(!self.get('error')){
+ console.log("Error occurred: ", error);
+ return self.onUploadingFileFailure(new Error("Server job for upload of file failed."));
+ }
+ throw error;
+ })
+ .then(function(data){
+ console.log("6. received data : ", data);
+ return self.waitForInsertIntoTable(data.jobId);
+ },function(error){
+ if(!self.get('error')){
+ console.log("Error occurred: ", error);
+ return self.onInsertIntoTableFailure(error);
+ }
+ throw error;
+ })
+ .then(function(data){
+ console.log("7. received data : ", data);
+ self.onInsertIntoTableSuccess(data);
+ return self.deleteTempTable(data);
+ },function(error){
+ if(!self.get('error')){
+ console.log("Error occurred: ", error);
+ return self.onInsertIntoTableFailure(new Error("Server job for insert from temporary to actual table failed."));
+ }
+ throw error;
+ })
+ .then(function(data){
+ console.log("8. received data : ", data);
+ return self.waitForDeleteTempTable(data.jobId);
+ },function(error){
+ if(!self.get('error')){
+ console.log("Error occurred: ", error);
+ self.onDeleteTempTableFailure(error);
+ }
+ throw error;
+ })
+ .then(function(data){
+ console.log("9. received data : ", data);
+ self.onDeleteTempTableSuccess(data);
+ },function(error){
+ if(!self.get('error')){
+ console.log("Error occurred: ", error);
+ self.onDeleteTempTableFailure(new Error("Server job for deleting temporary table failed."));
+ }
+ throw error;
+ }).catch(function(error){
+ console.log("inside catch : ", error);
+ }).finally(function(){
+ console.log("finally hide the modal always");
+ self.hideUploadModal();
+ });
+ },
+
+ validateColumns: function () {
+ // throw exception if invalid.
+ },
+ setError: function (error) {
+ if(error){
+ console.log("upload table error : ", error);
+ this.set('error', JSON.stringify(error));
+ this.get('notifyService').error(error);
+ }else{
+ this.set("error");
+ }
+ },
+
+ previewError: function (error) {
+ this.setError(error);
+ },
+
+ uploadTableFromHdfs : function(){
+ console.log("uploadTableFromHdfs called.");
+ if(!(this.get("inputFileTypeCSV") == true && this.get("isFirstRowHeader") == false) ){
+ this.pushUploadProgressInfos("<li>Uploading file .... </li>");
+ }
+ return this.get('uploader').uploadFromHDFS({
+ "isFirstRowHeader": this.get("isFirstRowHeader"),
+ "databaseName" : this.get('databaseName'),
+ "tableName" : this.get("tempTableName"),
+ "inputFileType" : this.get("inputFileType").id,
+ "hdfsPath" : this.get("hdfsPath")
+ });
+ },
+ uploadTable: function () {
+ this.printValues();
+ return this.get('uploader').uploadFiles('upload', this.get('files'), {
+ "isFirstRowHeader": this.get("isFirstRowHeader"),
+ "databaseName" : this.get('databaseName'),
+ "tableName" : this.get("tempTableName"),
+ "inputFileType" : this.get("inputFileType").id
+ });
+ },
+
+ onUploadSuccessfull: function (data) {
+ console.log("onUploadSuccessfull : ", data);
+ this.get('notifyService').success("Uploaded Successfully", "Table " + this.get('tableName') + " created in database " + this.get("databaseName"));
+ this.clearFields();
+ },
+
+ onUploadError: function (error) {
+ console.log("onUploadError : ", error);
+ this.setError(error);
+ },
+ showOrHide: function () {
+ if (this.get('show') == false) {
+ this.set("displayOption", "display:none");
+ this.set("showMoreOrLess", "Show More");
+ } else {
+ this.set("displayOption", "display:table-row");
+ this.set("showMoreOrLess", "Show Less");
+ }
+ },
+ displayOption: "display:none",
+ actions: {
+ toggleErrors: function () {
+ this.toggleProperty('showErrors');
+ },
+ filesUploaded: function (files) {
+ console.log("upload-table.js : uploaded new files : ", files);
+
+ this.clearFields();
+
+ this.set('files', files);
+ var name = files[0].name;
+ var i = name.indexOf(".");
+ var tableName = name.substr(0, i);
+ this.set('tableName', tableName);
+ var self = this;
+ return this.generatePreview(files)
+ },
+ previewFromHdfs : function(){
+ return this.generatePreview();
+ },
+ uploadTable : function(){
+ try{
+ this.createTableAndUploadFile();
+ }catch(e){
+ console.log("exception occured : ", e);
+ this.setError(e);
+ this.hideUploadModal();
+ }
+ },
+ uploadFromHDFS : function(){
+ this.set("isLocalUpload",false);
+ }
+ }
+});
http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/resources/ui/hive-web/app/controllers/visual-explain.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/app/controllers/visual-explain.js b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/controllers/visual-explain.js
new file mode 100644
index 0000000..272aa11
--- /dev/null
+++ b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/controllers/visual-explain.js
@@ -0,0 +1,64 @@
+/**
+ * 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 constants from 'hive/utils/constants';
+
+export default Ember.Controller.extend({
+ jobProgressService: Ember.inject.service(constants.namingConventions.jobProgress),
+ openQueries : Ember.inject.controller(constants.namingConventions.openQueries),
+ notifyService: Ember.inject.service(constants.namingConventions.notify),
+
+ index: Ember.inject.controller(),
+ verticesProgress: Ember.computed.alias('jobProgressService.currentJob.stages'),
+
+ actions: {
+ onTabOpen: function () {
+ var self = this;
+
+ // Empty query
+ if(this.get('openQueries.currentQuery.fileContent').length == 0){
+ this.set('json', undefined);
+ this.set('noquery', 'hive.errors.no.query');
+ return;
+ } else {
+ this.set('noquery', undefined);
+ }
+ // Introducing a common function
+ var getVisualExplainJson = function(){
+ self.set('showSpinner', undefined);
+ self.set('rerender');
+ self.get('index')._executeQuery(constants.jobReferrer.visualExplain, true, true).then(function (json) {
+ //this condition should be changed once we change the way of retrieving this json
+ if (json['STAGE PLANS']['Stage-1']) {
+ self.set('json', json);
+ } else {
+ self.set('json', {})
+ }
+ }, function (error) {
+ self.set('json', undefined);
+ self.get('notifyService').error(error);
+ });
+ self.toggleProperty('shouldChangeGraph');
+ }
+
+ getVisualExplainJson();
+
+ }
+ }
+});
http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/resources/ui/hive-web/app/controllers/visualization-ui.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/app/controllers/visualization-ui.js b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/controllers/visualization-ui.js
new file mode 100644
index 0000000..c908afd
--- /dev/null
+++ b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/controllers/visualization-ui.js
@@ -0,0 +1,134 @@
+/**
+* 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 constants from 'hive/utils/constants';
+
+export default Ember.Controller.extend({
+ selectedRowCount: constants.defaultVisualizationRowCount,
+ needs: [ constants.namingConventions.index,
+ constants.namingConventions.openQueries,
+ constants.namingConventions.jobResults
+ ],
+ index : Ember.computed.alias('controllers.' + constants.namingConventions.index),
+ openQueries : Ember.computed.alias('controllers.' + constants.namingConventions.openQueries),
+ results : Ember.computed.alias('controllers.' + constants.namingConventions.jobResults),
+ notifyService: Ember.inject.service(constants.namingConventions.notify),
+
+ polestarUrl: '',
+ voyagerUrl: '',
+ polestarPath: 'polestar/#/',
+ voyagerPath: 'voyager/#/',
+
+ showDataExplorer: true,
+ showAdvVisulization: false,
+
+ visualizationTabs: function () {
+ return [
+ Ember.Object.create({
+ name: 'Data Visualization',
+ id: 'visualization',
+ url: this.get('polestarUrl')
+ }),
+ Ember.Object.create({
+ name: 'Data Explorer',
+ id: 'data_explorer',
+ url: this.get('voyagerUrl')
+ })
+ ]
+ }.property('polestarUrl', 'voyagerUrl'),
+
+ activeTab: function () {
+ console.log("I am in activeTab function.");
+ this.get('visualizationTabs')[0].active = this.get("showDataExplorer");
+ this.get('visualizationTabs')[1].active = this.get("showAdvVisulization");
+ }.observes('polestarUrl', 'voyagerUrl'),
+
+ alterIframe: function () {
+ Ember.$("#visualization_frame").height(Ember.$("#visualization").height());
+ },
+
+ actions: {
+ onTabOpen: function () {
+ var self = this;
+ var model = this.get('index.model');
+ if (model) {
+ var existingJob = this.get('results').get('cachedResults').findBy('id', model.get('id'));
+ var url = this.container.lookup('adapter:application').buildURL();
+ url += '/' + constants.namingConventions.jobs + '/' + model.get('id') + '/results?&first=true';
+ url += '&count='+self.get('selectedRowCount')+'&job_id='+model.get('id')
+ if (existingJob) {
+ if(existingJob.results[0].rows.length === 0){
+ this.set("error", "Query has insufficient results to visualize the data.");
+ return;
+ }
+ this.set("error", null);
+ var id = model.get('id');
+ this.set("polestarUrl", this.get('polestarPath') + "?url=" + url);
+ this.set("voyagerUrl", this.get('voyagerPath') + "?url=" + url);
+ Ember.run.scheduleOnce('afterRender', this, function(){
+ self.alterIframe();
+ });
+ } else {
+ this.set("error", "No visualization available. Please execute a query and wait for the results to visualize the data.");
+ }
+ }
+ },
+
+ changeRowCount: function () {
+ var self = this;
+ if(isNaN(self.get('selectedRowCount')) || !(self.get('selectedRowCount')%1 === 0) || (self.get('selectedRowCount') <= 0)){
+ self.get('notifyService').error("Please enter a posive integer number.");
+ return;
+ }
+ var model = this.get('index.model');
+ if (model) {
+ var existingJob = this.get('results').get('cachedResults').findBy('id', model.get('id'));
+ var url = this.container.lookup('adapter:application').buildURL();
+ url += '/' + constants.namingConventions.jobs + '/' + model.get('id') + '/results?&first=true';
+ url += '&count='+self.get('selectedRowCount')+'&job_id='+model.get('id');
+ if (existingJob) {
+ this.set("error", null);
+ var id = model.get('id');
+
+ $('.nav-tabs.visualization-tabs li.active').each(function( index ) {
+
+ if($(this)[index].innerText.indexOf("Data Explorer") > -1){
+ self.set("showDataExplorer",true);
+ self.set("showAdvVisulization",false);
+ self.set("voyagerUrl", self.get('voyagerPath') + "?url=" + url);
+ self.set("polestarUrl", self.get('polestarPath') + "?url=" + url);
+ document.getElementById("visualization_frame").src = self.get("voyagerUrl");
+ }
+ if($(this)[index].innerText.indexOf("Advanced Visualization") > -1){
+ self.set("showAdvVisulization",true);
+ self.set("showDataExplorer",false);
+ self.set("voyagerUrl", self.get('voyagerPath') + "?url=" + url);
+ self.set("polestarUrl", self.get('polestarPath') + "?url=" + url);
+ document.getElementById("visualization_frame").src = self.get("polestarUrl");
+ }
+ })
+ document.getElementById("visualization_frame").contentWindow.location.reload();
+ } else {
+ this.set("error", "No visualization available. Please execute a query and wait for the results to visualize data.");
+ }
+ }
+
+ }
+ }
+});
http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/resources/ui/hive-web/app/helpers/.gitkeep
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/app/helpers/.gitkeep b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/helpers/.gitkeep
new file mode 100644
index 0000000..e69de29
http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/resources/ui/hive-web/app/helpers/all-uppercase.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/app/helpers/all-uppercase.js b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/helpers/all-uppercase.js
new file mode 100644
index 0000000..92930a9
--- /dev/null
+++ b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/helpers/all-uppercase.js
@@ -0,0 +1,25 @@
+/**
+ * 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 function allUppercase (input) {
+ return input ? input.toUpperCase() : input;
+}
+
+export default Ember.Handlebars.makeBoundHelper(allUppercase);
http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/resources/ui/hive-web/app/helpers/code-helper.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/app/helpers/code-helper.js b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/helpers/code-helper.js
new file mode 100644
index 0000000..8bbd19e
--- /dev/null
+++ b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/helpers/code-helper.js
@@ -0,0 +1,28 @@
+/**
+ * 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 function code (text) {
+ text = Ember.Handlebars.Utils.escapeExpression(text);
+ text = text.replace(/(\r\n|\n|\r)/gm, '<br>');
+
+ return new Ember.Handlebars.SafeString('<code>' + text + '</code>');
+}
+
+export default Ember.Handlebars.makeBoundHelper(code);
http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/resources/ui/hive-web/app/helpers/date-binding.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/app/helpers/date-binding.js b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/helpers/date-binding.js
new file mode 100644
index 0000000..61251f8
--- /dev/null
+++ b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/helpers/date-binding.js
@@ -0,0 +1,27 @@
+/**
+ * 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.
+ */
+
+/* globals moment */
+
+import Ember from 'ember';
+
+export function pathBinding (data, key) {
+ return moment(data.get(key)).fromNow();
+}
+
+export default Ember.Handlebars.makeBoundHelper(pathBinding);
http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/resources/ui/hive-web/app/helpers/format-column-type.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/app/helpers/format-column-type.js b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/helpers/format-column-type.js
new file mode 100644
index 0000000..13528b7
--- /dev/null
+++ b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/helpers/format-column-type.js
@@ -0,0 +1,39 @@
+/**
+ * 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.
+ */
+
+/**
+ used to format the precision and scale of type in database's table's columns
+**/
+
+import Ember from "ember";
+
+var columnTypeFormatter = function(column) {
+ var type = column.type;
+ var ext = type;
+ if( type === "VARCHAR" || type === "CHAR" || type == "DECIMAL" ) {
+ ext += '(' + column.precision;
+ if (type == "DECIMAL") {
+ ext += "," + column.scale;
+ }
+ ext += ")";
+ }
+
+ return ext;
+};
+
+export default Ember.Handlebars.makeBoundHelper(columnTypeFormatter);
http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/resources/ui/hive-web/app/helpers/log-helper.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/app/helpers/log-helper.js b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/helpers/log-helper.js
new file mode 100644
index 0000000..c29d129
--- /dev/null
+++ b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/helpers/log-helper.js
@@ -0,0 +1,28 @@
+/**
+ * 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 function log (text) {
+ text = Ember.Handlebars.Utils.escapeExpression(text);
+ text = text.replace(/(\r\n|\n|\r)/gm, '<br>');
+
+ return new Ember.Handlebars.SafeString(text);
+}
+
+export default Ember.Handlebars.makeBoundHelper(log);
http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/resources/ui/hive-web/app/helpers/path-binding.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/app/helpers/path-binding.js b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/helpers/path-binding.js
new file mode 100644
index 0000000..926aaaa
--- /dev/null
+++ b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/helpers/path-binding.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 Ember from 'ember';
+
+export function pathBinding (data, key) {
+ if (!data || !key) {
+ return;
+ }
+
+ return data.get ? data.get(key) : data[key];
+}
+
+export default Ember.Handlebars.makeBoundHelper(pathBinding);
http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/resources/ui/hive-web/app/helpers/preformatted-string.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/app/helpers/preformatted-string.js b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/helpers/preformatted-string.js
new file mode 100644
index 0000000..4ab6a2e
--- /dev/null
+++ b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/helpers/preformatted-string.js
@@ -0,0 +1,28 @@
+/**
+* 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 function preformattedString (string) {
+ string = string.replace(/\\n/g, ' '); // newline
+ string = string.replace(/\\t/g, '	'); // tabs
+ string = string.replace(/^\s+|\s+$/g, ''); // trim
+
+ return new Ember.Handlebars.SafeString(string);
+}
+
+export default Ember.Handlebars.makeBoundHelper(preformattedString);
http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/resources/ui/hive-web/app/helpers/tb-helper.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/app/helpers/tb-helper.js b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/helpers/tb-helper.js
new file mode 100644
index 0000000..81af5ff
--- /dev/null
+++ b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/helpers/tb-helper.js
@@ -0,0 +1,33 @@
+/**
+ * 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 function tb (key, data) {
+ var path = data.get ? data.get(key) : data[key];
+
+ if (!path && key) {
+ return Ember.I18n.t(key);
+ }
+
+ if (path) {
+ return Ember.I18n.t(path);
+ }
+}
+
+export default Ember.Handlebars.makeBoundHelper(tb);
http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/resources/ui/hive-web/app/index.html
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/app/index.html b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/index.html
new file mode 100644
index 0000000..2cbf9f0
--- /dev/null
+++ b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/index.html
@@ -0,0 +1,42 @@
+<!--
+ * 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.
+-->
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta charset="utf-8">
+ <meta http-equiv="X-UA-Compatible" content="IE=edge">
+ <title>Hive</title>
+ <meta name="description" content="">
+ <meta name="viewport" content="width=device-width, initial-scale=1">
+
+ {{content-for 'head'}}
+
+ <link rel="stylesheet" href="assets/vendor.css">
+ <link rel="stylesheet" href="assets/hive.css">
+
+ {{content-for 'head-footer'}}
+ </head>
+ <body>
+ {{content-for 'body'}}
+
+ <script src="assets/vendor.js"></script>
+ <script src="assets/hive.js"></script>
+
+ {{content-for 'body-footer'}}
+ </body>
+</html>
http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/resources/ui/hive-web/app/initializers/i18n.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/app/initializers/i18n.js b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/initializers/i18n.js
new file mode 100644
index 0000000..b3630c1
--- /dev/null
+++ b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/initializers/i18n.js
@@ -0,0 +1,269 @@
+/**
+ * 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';
+
+var TRANSLATIONS;
+
+export default {
+ name: 'i18n',
+ initialize: function () {
+ Ember.ENV.I18N_COMPILE_WITHOUT_HANDLEBARS = true;
+ Ember.FEATURES.I18N_TRANSLATE_HELPER_SPAN = false;
+ Ember.I18n.translations = TRANSLATIONS;
+ Ember.TextField.reopen(Ember.I18n.TranslateableAttributes);
+ }
+};
+
+TRANSLATIONS = {
+ tooltips: {
+ refresh: 'Refresh database',
+ loadSample: 'Load sample data',
+ query: 'Query',
+ settings: 'Settings',
+ visualExplain: 'Visual Explain',
+ tez: 'Tez',
+ visualization: 'Visualization',
+ notifications: 'Notifications',
+ expand: 'Expand query panel',
+ makeSettingGlobal: 'Make setting global',
+ overwriteGlobalValue: 'Overwrite global setting value'
+ },
+
+ alerts: {
+ errors: {
+ save: {
+ query: "Error when trying to execute the query",
+ results: "Error when trying to save the results."
+ },
+ get: {
+ tables: 'Error when trying to retrieve the tables for the selected database',
+ columns: 'Error when trying to retrieve the table columns.'
+ },
+ sessions: {
+ delete: 'Error invalidating sessions'
+ },
+ job: {
+ status: "An error occured while processing the job."
+ }
+ },
+ success: {
+ sessions: {
+ deleted: 'Session invalidated.'
+ },
+ settings: {
+ saved: 'Settings have been saved.'
+ },
+ query: {
+ execution: 'Query has been submitted.',
+ save: 'The query has been saved.',
+ update: 'The query has been updated.'
+ }
+ }
+ },
+
+ modals: {
+ delete: {
+ heading: 'Confirm deletion',
+ message: 'Are you sure you want to delete this item?',
+ emptyQueryMessage: "Your query is empty. Do you want to delete this item?"
+ },
+
+ save: {
+ heading: 'Saving item',
+ saveBeforeCloseHeading: "Save item before closing?",
+ message: 'Enter name:',
+ overwrite: 'Saving will overwrite previously saved query'
+ },
+
+ download: {
+ csv: 'Download results as CSV',
+ hdfs: 'Please enter save path and name'
+ },
+
+ changeTitle: {
+ heading: 'Rename worksheet'
+ },
+ authenticationLDAP: {
+ heading: 'Enter the LDAP password'
+ }
+ },
+
+ titles: {
+ database: 'Database Explorer',
+ explorer: 'Databases',
+ results: 'Search Results',
+ settings: 'Database Settings',
+ query: {
+ tab: 'Worksheet',
+ editor: 'Query Editor',
+ process: 'Query Process Results',
+ parameters: 'Parameters',
+ visualExplain: 'Visual Explain',
+ tez: 'TEZ',
+ status: 'Status: ',
+ messages: 'Messages',
+ visualization: 'Visualization'
+ },
+ download: 'Save results...',
+ tableSample: '{{tableName}} sample'
+ },
+
+ placeholders: {
+ search: {
+ tables: 'Search tables...',
+ columns: 'Search columns in result tables...',
+ results: 'Filter columns...'
+ },
+ select: {
+ database: 'Select Database...',
+ udfs: 'Insert udfs',
+ file: 'Select File Resource...',
+ noFileResource: '(no file)',
+ value: "Select value..."
+ },
+ fileResource: {
+ name: "resource name",
+ path: "resource path"
+ },
+ udfs: {
+ name: 'udf name',
+ className: 'udf class name',
+ path: "resource path",
+ database: 'Select Database...'
+ },
+ settings: {
+ key: 'mapred.reduce.tasks',
+ value: '1'
+ }
+ },
+
+ menus: {
+ query: 'Query',
+ savedQueries: 'Saved Queries',
+ history: 'History',
+ udfs: 'UDFs',
+ uploadTable: 'Upload Table',
+ logs: 'Logs',
+ results: 'Results',
+ explain: 'Explain'
+ },
+
+ columns: {
+ id: 'id',
+ shortQuery: 'preview',
+ fileResource: 'file resource',
+ title: 'title',
+ database: 'database',
+ owner: 'owner',
+ user: 'user',
+ date: 'date submitted',
+ duration: 'duration',
+ status: 'status',
+ expand: '',
+ actions: ''
+ },
+
+ buttons: {
+ addItem: 'Add new item...',
+ insert: 'Insert',
+ delete: 'Delete',
+ cancel: 'Cancel',
+ edit: 'Edit',
+ execute: 'Execute',
+ explain: 'Explain',
+ saveAs: 'Save as...',
+ save: 'Save',
+ newQuery: 'New Worksheet',
+ newUdf: 'New UDF',
+ history: 'History',
+ ok: 'OK',
+ stopJob: 'Stop execution',
+ stoppingJob: 'Stopping...',
+ close: 'Close',
+ clearFilters: 'Clear filters',
+ expand: 'Expand message',
+ collapse: 'Collapse message',
+ previousPage: 'previous',
+ uploadTable: 'Upload Table',
+ showPreview: 'Preview',
+ nextPage: 'next',
+ loadMore: 'Load more...',
+ saveHdfs: 'Save to HDFS',
+ saveCsv: 'Download as CSV',
+ runOnTez: 'Run on Tez',
+ killSession: 'Kill Session'
+ },
+
+ labels: {
+ noTablesMatch: 'No tables match',
+ table: 'Table ',
+ hoursShort: "{{hours}} hrs",
+ minsShort: "{{minutes}} mins",
+ secsShort: "{{seconds}} secs"
+ },
+
+ popover: {
+ visualExplain: {
+ statistics: "Statistics"
+ },
+ queryEditorHelp: {
+ title: "Did you know?",
+ content: {
+ line1: "Press CTRL + Space to autocomplete",
+ line2: "You can execute queries with multiple SQL statements delimited by a semicolon ';'",
+ line3: "You can highlight and run a fragment of a query"
+ }
+ },
+ add: 'Add'
+ },
+
+ tez: {
+ errors: {
+ 'not.deployed': "Tez View isn't deployed.",
+ 'no.instance': "No instance of Tez View found.",
+ 'no.dag': "No DAG available"
+ }
+ },
+
+ hive: {
+ errors: {
+ 'no.query': "No query to process.",
+ 'emptyDatabase' : "Please select Database.",
+ 'emptyTableName' : "Please enter tableName.",
+ 'emptyIsFirstRow' : "Please select is First Row Header?"
+ }
+ },
+
+ emptyList: {
+ history: {
+ noItems: "No queries were run.",
+ noMatches: "No jobs match your filtering criteria",
+ },
+ savedQueries: {
+ noItems: "No queries were saved.",
+ noMatches: "No queries match your filtering criteria"
+ }
+ },
+
+ settings: {
+ parsed: "Query settings added"
+ },
+
+ generalError: 'Unexpected error'
+};
http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/resources/ui/hive-web/app/mixins/filterable.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/app/mixins/filterable.js b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/mixins/filterable.js
new file mode 100644
index 0000000..aa1f4cd
--- /dev/null
+++ b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/mixins/filterable.js
@@ -0,0 +1,106 @@
+/**
+ * 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 utils from 'hive/utils/functions';
+
+export default Ember.Mixin.create({
+ init: function () {
+ this._super();
+ this.clearFilters();
+ },
+
+ filter: function (items) {
+ var self = this;
+
+ if (items && this.get('filters.length')) {
+ items = items.filter(function (item) {
+ return self.get('filters').every(function (filter) {
+ var propValue = item.get(filter.property);
+
+ if (!!filter.value) {
+ if (filter.min !== undefined && filter.max !== undefined) {
+ if (utils.isInteger(propValue)) {
+ return +propValue >= +filter.min && +propValue <= +filter.max;
+ } else if (utils.isDate(propValue)) {
+ return propValue >= filter.min && propValue <= filter.max;
+ } else {
+ return false;
+ }
+ } else if (filter.exactMatch) {
+ return propValue == filter.value;
+ } else {
+ return propValue && propValue.toLowerCase().indexOf(filter.value.toLowerCase()) > -1;
+ }
+ }
+
+ return false;
+ });
+ });
+ }
+
+ return items;
+ },
+
+ updateFilters: function (property, filterValue, exactMatch) {
+ var addFilter = function () {
+ if (!filterValue) {
+ return;
+ }
+
+ this.get('filters').pushObject(Ember.Object.create({
+ property: property,
+ exactMatch: exactMatch,
+ min: filterValue.min,
+ max: filterValue.max,
+ value: filterValue
+ }));
+ };
+
+ var existentFilter = this.get('filters').find(function (filter) {
+ return filter.property === property;
+ });
+
+ if (existentFilter) {
+ if (filterValue) {
+ //remove and add again for triggering collection change thus avoiding to add observers on individual properties of a filter
+ this.get('filters').removeObject(existentFilter);
+ addFilter.apply(this);
+ } else {
+ //ensures removal of the filterValue when it's an empty string
+ this.set('filters', this.get('filters').without(existentFilter));
+ }
+ } else {
+ addFilter.apply(this);
+ }
+ },
+
+ clearFilters: function () {
+ var filters = this.get('filters');
+
+ if (!filters || filters.get('length')) {
+ this.set('filters', Ember.A());
+ }
+ },
+
+ actions: {
+ filter: function (property, filterValue) {
+ this.updateFilters(property, filterValue);
+ }
+ }
+});