You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ambari.apache.org by al...@apache.org on 2015/04/17 21:10:33 UTC
[4/5] ambari git commit: AMBARI-10528. Hive View: Visual Explain,
Error handling and bugfixes (alexantonenko)
http://git-wip-us.apache.org/repos/asf/ambari/blob/672eee34/contrib/views/hive/src/main/resources/ui/hive-web/.travis.yml
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/resources/ui/hive-web/.travis.yml b/contrib/views/hive/src/main/resources/ui/hive-web/.travis.yml
new file mode 100644
index 0000000..5d96e28
--- /dev/null
+++ b/contrib/views/hive/src/main/resources/ui/hive-web/.travis.yml
@@ -0,0 +1,38 @@
+# 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.
+
+---
+language: node_js
+node_js:
+ - "0.12"
+
+sudo: false
+
+cache:
+ directories:
+ - node_modules
+
+before_install:
+ - "npm config set spin false"
+ - "npm install -g npm@^2"
+
+install:
+ - npm install -g bower
+ - npm install
+ - bower install
+
+script:
+ - npm test
http://git-wip-us.apache.org/repos/asf/ambari/blob/672eee34/contrib/views/hive/src/main/resources/ui/hive-web/Brocfile.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/resources/ui/hive-web/Brocfile.js b/contrib/views/hive/src/main/resources/ui/hive-web/Brocfile.js
index db65f1f..8a367c9 100644
--- a/contrib/views/hive/src/main/resources/ui/hive-web/Brocfile.js
+++ b/contrib/views/hive/src/main/resources/ui/hive-web/Brocfile.js
@@ -25,9 +25,13 @@ var app = new EmberApp({
//valid values are `default`, `bootstrap2`, `bootstrap3` or false
'theme': 'bootstrap3'
},
+ vendorFiles: {
+ 'handlebars.js': null
+ },
hinting: false
});
+app.import('bower_components/ember/ember-template-compiler.js');
app.import('bower_components/bootstrap/dist/js/bootstrap.js');
app.import('bower_components/bootstrap/dist/css/bootstrap.css');
app.import('bower_components/bootstrap/dist/css/bootstrap.css.map', {
@@ -42,5 +46,6 @@ app.import('vendor/codemirror/sql-hint.js');
app.import('vendor/codemirror/show-hint.js');
app.import('vendor/codemirror/codemirror.css');
app.import('vendor/codemirror/show-hint.css');
+app.import('vendor/dagre.min.js');
module.exports = app.toTree();
http://git-wip-us.apache.org/repos/asf/ambari/blob/672eee34/contrib/views/hive/src/main/resources/ui/hive-web/app/components/alert-message-widget.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/resources/ui/hive-web/app/components/alert-message-widget.js b/contrib/views/hive/src/main/resources/ui/hive-web/app/components/alert-message-widget.js
index fd8c1d7..df44c37 100644
--- a/contrib/views/hive/src/main/resources/ui/hive-web/app/components/alert-message-widget.js
+++ b/contrib/views/hive/src/main/resources/ui/hive-web/app/components/alert-message-widget.js
@@ -19,17 +19,17 @@
import Ember from 'ember';
export default Ember.Component.extend({
- click: function () {
- this.toggleProperty('message.isExpanded');
-
- if (!this.get('message.isExpanded')) {
- this.sendAction('removeLater', this.get('message'));
- }
- },
-
actions: {
remove: function () {
this.sendAction('removeMessage', this.get('message'));
+ },
+
+ toggleMessage: function() {
+ this.toggleProperty('message.isExpanded');
+
+ if (!this.get('message.isExpanded')) {
+ this.sendAction('removeLater', this.get('message'));
+ }
}
}
});
http://git-wip-us.apache.org/repos/asf/ambari/blob/672eee34/contrib/views/hive/src/main/resources/ui/hive-web/app/components/collapsible-widget.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/resources/ui/hive-web/app/components/collapsible-widget.js b/contrib/views/hive/src/main/resources/ui/hive-web/app/components/collapsible-widget.js
index 4425b59..f2081f2 100644
--- a/contrib/views/hive/src/main/resources/ui/hive-web/app/components/collapsible-widget.js
+++ b/contrib/views/hive/src/main/resources/ui/hive-web/app/components/collapsible-widget.js
@@ -28,6 +28,11 @@ export default Ember.Component.extend({
if (this.get('isExpanded')) {
this.sendAction('expanded', this.get('heading'), this.get('toggledParam'));
}
+ },
+
+ sendControlAction: function(action) {
+ this.set('controlAction', action);
+ this.sendAction('controlAction', this.get('heading'), this.get('toggledParam'));
}
}
});
http://git-wip-us.apache.org/repos/asf/ambari/blob/672eee34/contrib/views/hive/src/main/resources/ui/hive-web/app/components/modal-widget.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/resources/ui/hive-web/app/components/modal-widget.js b/contrib/views/hive/src/main/resources/ui/hive-web/app/components/modal-widget.js
index b9179bb..790e84b 100644
--- a/contrib/views/hive/src/main/resources/ui/hive-web/app/components/modal-widget.js
+++ b/contrib/views/hive/src/main/resources/ui/hive-web/app/components/modal-widget.js
@@ -25,10 +25,32 @@ export default Ember.Component.extend(Ember.I18n.TranslateableProperties, {
}.bind(this));
}.on('didInsertElement'),
+ keyPress: function(e) {
+ Ember.run.debounce(this, function() {
+ if (e.which === 13) {
+ this.send('ok');
+ } else if (e.which === 27) {
+ this.send('close');
+ }
+ }, 200)
+ },
+
+ setupEvents: function() {
+ this.$(document).on('keyup', Ember.$.proxy(this.keyPress, this));
+ }.on('didInsertElement'),
+
+ destroyEvents: function() {
+ this.$(document).off('keyup', Ember.$.proxy(this.keyPress, this));
+ }.on('willDestroyElement'),
+
actions: {
ok: function () {
this.$('.modal').modal('hide');
this.sendAction('ok');
+ },
+ close: function () {
+ this.$('.modal').modal('hide');
+ this.sendAction('close');
}
}
});
http://git-wip-us.apache.org/repos/asf/ambari/blob/672eee34/contrib/views/hive/src/main/resources/ui/hive-web/app/components/notify-widget.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/resources/ui/hive-web/app/components/notify-widget.js b/contrib/views/hive/src/main/resources/ui/hive-web/app/components/notify-widget.js
new file mode 100644
index 0000000..5a37f13
--- /dev/null
+++ b/contrib/views/hive/src/main/resources/ui/hive-web/app/components/notify-widget.js
@@ -0,0 +1,32 @@
+/**
+* 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({
+ tagName: 'notifications',
+ classNames: ['notifications-container'],
+ notifications : Ember.computed.alias('notify.notifications'),
+
+ actions: {
+ removeNotification: function(notification) {
+ this.notify.removeNotification(notification);
+ }
+ }
+});
http://git-wip-us.apache.org/repos/asf/ambari/blob/672eee34/contrib/views/hive/src/main/resources/ui/hive-web/app/components/number-range-widget.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/resources/ui/hive-web/app/components/number-range-widget.js b/contrib/views/hive/src/main/resources/ui/hive-web/app/components/number-range-widget.js
index ad98beb..4ab1dba 100644
--- a/contrib/views/hive/src/main/resources/ui/hive-web/app/components/number-range-widget.js
+++ b/contrib/views/hive/src/main/resources/ui/hive-web/app/components/number-range-widget.js
@@ -24,27 +24,25 @@ export default Ember.Component.extend({
var slider;
- this.$(function() {
- if (!self.get('numberRange.from') && !self.get('numberRange.to')) {
- self.get('numberRange').set('from', self.get('numberRange.min'));
- self.get('numberRange').set('to', self.get('numberRange.max'));
- }
+ if (!self.get('numberRange.from') && !self.get('numberRange.to')) {
+ self.get('numberRange').set('from', self.get('numberRange.min'));
+ self.get('numberRange').set('to', self.get('numberRange.max'));
+ }
- slider = self.$( ".slider" ).slider({
- range: true,
- min: self.get('numberRange.min'),
- max: self.get('numberRange.max'),
- units: self.get('numberRange.units'),
- values: [ self.get('numberRange.from'), self.get('numberRange.to') ],
- slide: function (event, ui) {
- self.set('numberRange.from', ui.values[0]);
- self.set('numberRange.to', ui.values[1]);
- },
+ slider = self.$( ".slider" ).slider({
+ range: true,
+ min: self.get('numberRange.min'),
+ max: self.get('numberRange.max'),
+ units: self.get('numberRange.units'),
+ values: [ self.get('numberRange.from'), self.get('numberRange.to') ],
+ slide: function (event, ui) {
+ self.set('numberRange.from', ui.values[0]);
+ self.set('numberRange.to', ui.values[1]);
+ },
- change: function () {
- self.sendAction('rangeChanged', self.get('numberRange'));
- }
- });
+ change: function () {
+ self.sendAction('rangeChanged', self.get('numberRange'));
+ }
});
this.set('slider', slider);
http://git-wip-us.apache.org/repos/asf/ambari/blob/672eee34/contrib/views/hive/src/main/resources/ui/hive-web/app/components/query-tabs.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/resources/ui/hive-web/app/components/query-tabs.js b/contrib/views/hive/src/main/resources/ui/hive-web/app/components/query-tabs.js
new file mode 100644
index 0000000..0ef6768
--- /dev/null
+++ b/contrib/views/hive/src/main/resources/ui/hive-web/app/components/query-tabs.js
@@ -0,0 +1,121 @@
+/**
+ * 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({
+ tabClassNames : "fa queries-icon query-context-tab",
+ openOverlayAction : 'openOverlay',
+ closeOverlayAction : 'closeOverlay',
+
+ tabs: [
+ Ember.Object.create({
+ iconClass: 'fa-code',
+ action: 'setDefaultActive'
+ }),
+ Ember.Object.create({
+ iconClass: 'fa-gear',
+ action: 'toggleOverlay',
+ template: 'settings',
+ outlet: 'overlay',
+ into: 'open-queries'
+ }),
+ Ember.Object.create({
+ iconClass: 'fa-bar-chart',
+ action: 'toggleOverlay',
+ template: 'visual-explain',
+ outlet: 'overlay',
+ into: 'index'
+ }),
+ Ember.Object.create({
+ iconClass: 'text-icon',
+ text: 'TEZ',
+ action: 'toggleOverlay',
+ template: 'tez-ui',
+ outlet: 'overlay',
+ into: 'index'
+ }),
+ Ember.Object.create({
+ iconClass: 'fa-envelope',
+ action: 'toggleOverlay',
+ template: 'messages',
+ outlet: 'overlay',
+ into: 'open-queries',
+ badgeProperty: 'count'
+ })
+ ],
+
+ setDefaultTab: function() {
+ var defaultTab = this.get('tabs.firstObject');
+
+ defaultTab.set('active', true);
+ this.set('default', defaultTab);
+ this.set('active', defaultTab);
+ }.on('init'),
+
+ setupTabsBadges: function() {
+ var tabs = this.get('tabs');
+ var self = this;
+
+ tabs.map(function(tab) {
+ if (tab.get('badgeProperty')) {
+ var controller = self.container.lookup('controller:' + tab.get('template'));
+ tab.set('controller', controller);
+
+ Ember.oneWay(tab, 'badge', 'controller.count');
+ }
+ });
+ }.on('init'),
+
+ closeActiveOverlay: function() {
+ this.sendAction('closeOverlayAction', this.get('active'));
+ },
+
+ openOverlay: function(tab) {
+ this.closeActiveOverlay();
+ this.set('active.active', false);
+ tab.set('active', true);
+ this.set('active', tab);
+ this.sendAction('openOverlayAction', tab);
+ },
+
+ setDefaultActive: function() {
+ var active = this.get('active');
+ var defaultTab = this.get('default');
+
+ if (active !== defaultTab) {
+ this.closeActiveOverlay();
+ defaultTab.set('active', true);
+ active.set('active', false);
+ this.set('active', 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/672eee34/contrib/views/hive/src/main/resources/ui/hive-web/app/components/typeahead-widget.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/resources/ui/hive-web/app/components/typeahead-widget.js b/contrib/views/hive/src/main/resources/ui/hive-web/app/components/typeahead-widget.js
index 34c1f4b..51f09be 100644
--- a/contrib/views/hive/src/main/resources/ui/hive-web/app/components/typeahead-widget.js
+++ b/contrib/views/hive/src/main/resources/ui/hive-web/app/components/typeahead-widget.js
@@ -23,15 +23,60 @@ export default Typeahead.extend(Ember.I18n.TranslateableProperties, {
didInsertElement: function() {
this._super();
- if(!this.get('selection') && this.get('content.firstObject')) {
+ if (!this.get('selection') && this.get('content.firstObject')) {
this.set('selection', this.get('content.firstObject'));
}
this.selectize.on('dropdown_close', Ember.$.proxy(this.onClose, this));
},
+ removeExcludedObserver: function() {
+ var self = this;
+ var options = this.get('content');
+
+ if (!options) {
+ options = this.removeExcluded(true);
+ this.set('content', options);
+ } else {
+ this.removeExcluded();
+ }
+ }.observes('excluded.@each.key').on('init'),
+
+ removeExcluded: function(shouldReturn) {
+ var self = this;
+ var excluded = this.get('excluded') || [];
+ var options = this.get('options');
+ var selection = this.get('selection');
+ var objectToModify = this.get('content');
+ var objectsToRemove = [];
+ var objectsToAdd = [];
+
+ if (!options) {
+ return;
+ }
+
+ if (shouldReturn) {
+ objectToModify = Ember.copy(options);
+ }
+
+ if (options) {
+ options.forEach(function(option, index) {
+ if (excluded.contains(option) && option !== selection) {
+ objectsToRemove.push(option);
+ } else if (!objectToModify.contains(option)) {
+ objectsToAdd.push(option);
+ }
+ });
+ }
+
+ objectToModify.removeObjects(objectsToRemove);
+ objectToModify.pushObjects(objectsToAdd);
+
+ return objectToModify;
+ },
+
onClose: function() {
- if(!this.get('selection') && this.get('prevSelection')) {
+ if (!this.get('selection') && this.get('prevSelection')) {
this.set('selection', this.get('prevSelection'));
}
},
http://git-wip-us.apache.org/repos/asf/ambari/blob/672eee34/contrib/views/hive/src/main/resources/ui/hive-web/app/controllers/alerts.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/resources/ui/hive-web/app/controllers/alerts.js b/contrib/views/hive/src/main/resources/ui/hive-web/app/controllers/alerts.js
deleted file mode 100644
index be70566..0000000
--- a/contrib/views/hive/src/main/resources/ui/hive-web/app/controllers/alerts.js
+++ /dev/null
@@ -1,47 +0,0 @@
-/**
- * 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.ArrayController.extend({
- pushObject: function (object) {
- object.typeClass = 'alert-' + object.type;
- this._super(object);
- this.removeLater(object);
- },
-
- removeLater: function (object) {
- var self = this;
-
- Ember.run.later(function() {
- if (!object.isExpanded) {
- self.removeObject(object);
- }
- }, 5000);
- },
-
- actions: {
- remove: function (message) {
- this.removeObject(message);
- },
-
- removeLater: function (message) {
- this.removeLater(message);
- }
- }
-});
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/ambari/blob/672eee34/contrib/views/hive/src/main/resources/ui/hive-web/app/controllers/databases.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/resources/ui/hive-web/app/controllers/databases.js b/contrib/views/hive/src/main/resources/ui/hive-web/app/controllers/databases.js
index 6a259ba..0b103cd 100644
--- a/contrib/views/hive/src/main/resources/ui/hive-web/app/controllers/databases.js
+++ b/contrib/views/hive/src/main/resources/ui/hive-web/app/controllers/databases.js
@@ -30,13 +30,13 @@ export default Ember.ArrayController.extend({
dbTables: Ember.computed.alias('controllers.' + constants.namingConventions.tables),
dbColumns: Ember.computed.alias('controllers.' + constants.namingConventions.columns),
- _handleTablesError: function (err) {
- this.send('addAlert', constants.alerts.error, err.responseText, "alerts.errors.get.tables");
+ _handleTablesError: function (error) {
+ this.notify.error(error.responseJSON.message, error.responseJSON.trace);
this.set('isLoading', false);
},
- _handleColumnsError: function (err) {
- this.send('addAlert', constants.alerts.error, err.responseText, "alerts.errors.get.columns");
+ _handleColumnsError: function (error) {
+ this.notify.error(error.responseJSON.message, error.responseJSON.trace);
this.set('isLoading', false);
},
@@ -191,7 +191,52 @@ export default Ember.ArrayController.extend({
return defer.promise;
},
+ tableControls: Ember.A([
+ Ember.Object.create({
+ icon: 'fa-list',
+ action: 'loadSampleData',
+ tooltip: Ember.I18n.t('tooltips.loadSample')
+ })
+ ]),
+
+ panelIconActions: function () {
+ return [
+ Ember.Object.create({
+ icon: 'fa-refresh',
+ action: 'refreshDatabaseExplorer'
+ })
+ ];
+ }.property(),
+
actions: {
+ refreshDatabaseExplorer: function() {
+ var self = this;
+ var selectedDatabase = this.get('selectedDatabase');
+
+ this.store.unloadAll('database');
+ this.store.fetchAll('database').then(function() {
+ var database = self.get('model').findBy('id', selectedDatabase.get('id'));
+ self.set('selectedDatabase', database);
+ }).catch(function(response) {
+ self.notify.error(response.responseJSON.message, response.responseJSON.trace);
+ });
+ },
+
+ loadSampleData: function(tableName, database) {
+ var self = this;
+ this.send('addQuery', Ember.I18n.t('titles.tableSample', { tableName: tableName }));
+
+ Ember.run.later(function() {
+ var query = constants.sampleDataQuery.fmt(tableName);
+
+ self.set('selectedDatabase', database);
+ self.get('openQueries.currentQuery')
+ .set('fileContent', query);
+
+ self.send('executeQuery');
+ });
+ },
+
getTables: function (dbName) {
var database = this.findBy('name', dbName),
tables = database.tables,
@@ -257,6 +302,7 @@ export default Ember.ArrayController.extend({
resultsTab = this.get('tabs').findBy('view', constants.namingConventions.databaseSearch),
tableSearchResults = this.get('tableSearchResults');
+ this.set('tablesSearchTerm', searchTerm);
resultsTab.set('visible', true);
this.set('selectedTab', resultsTab);
this.set('columnSearchTerm', '');
@@ -351,4 +397,4 @@ export default Ember.ArrayController.extend({
});
}
}
-});
\ No newline at end of file
+});
http://git-wip-us.apache.org/repos/asf/ambari/blob/672eee34/contrib/views/hive/src/main/resources/ui/hive-web/app/controllers/index.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/resources/ui/hive-web/app/controllers/index.js b/contrib/views/hive/src/main/resources/ui/hive-web/app/controllers/index.js
index 954b42b..df2d088 100644
--- a/contrib/views/hive/src/main/resources/ui/hive-web/app/controllers/index.js
+++ b/contrib/views/hive/src/main/resources/ui/hive-web/app/controllers/index.js
@@ -42,10 +42,19 @@ export default Ember.Controller.extend({
visualExplain: Ember.computed.alias('controllers.' + constants.namingConventions.visualExplain),
tezUI: Ember.computed.alias('controllers.' + constants.namingConventions.tezUI),
+ isQueryTabActive: function() {
+ return !this.get('tezUI.showOverlay') && !this.get('visualExplain.showOverlay') && !this.get('settings.showOverlay');
+ }.property('tezUI.showOverlay', 'visualExplain.showOverlay', 'settings.showOverlay'),
+
shouldShowTez: function() {
return this.get('model.dagId') && this.get('tezUI.isTezViewAvailable');
}.property('model.dagId', 'tezUI.isTezViewAvailable'),
+ shouldShowVisualExplain: function () {
+ return this.get('openQueries.currentQuery.fileContent');
+ }.property('openQueries.currentQuery.fileContent'),
+
+
canExecute: function () {
var isModelRunning = this.get('model.isRunning');
var hasParams = this.get('queryParams.length');
@@ -84,11 +93,12 @@ export default Ember.Controller.extend({
currentParams.setObjects(updatedParams);
}.observes('openQueries.currentQuery.fileContent'),
- _executeQuery: function (shouldExplain) {
+ _executeQuery: function (shouldExplain, shouldGetVisualExplain) {
var queryId,
query,
finalQuery,
job,
+ defer = Ember.RSVP.defer(),
originalModel = this.get('model');
job = this.store.createRecord(constants.namingConventions.job, {
@@ -110,15 +120,55 @@ export default Ember.Controller.extend({
query = this.get('openQueries').getQueryForModel(originalModel);
- finalQuery = this.buildQuery(query, shouldExplain);
+ query = this.buildQuery(query, shouldExplain, shouldGetVisualExplain);
+
+ // for now we won't support multiple queries
+ // buildQuery will return false it multiple queries
+ // are selected
+ if (!query) {
+ originalModel.set('isRunning', false);
+ defer.reject({
+ responseJSON: {
+ message: 'Running multiple queries is not supported.'
+ }
+ });
+
+ return defer.promise;
+ }
+
+ finalQuery = query;
finalQuery = this.bindQueryParams(finalQuery);
finalQuery = this.prependQuerySettings(finalQuery);
job.set('forcedContent', finalQuery);
+ if (shouldGetVisualExplain) {
+ return this.getVisualExplainJson(job, originalModel);
+ }
+
return this.saveQuery(job, originalModel);
},
+ getVisualExplainJson: function (job, originalModel) {
+ var self = this;
+ var defer = Ember.RSVP.defer();
+
+ job.save().then(function () {
+ self.get('results').getResultsJson(job).then(function (json) {
+ defer.resolve(json);
+ originalModel.set('isRunning', undefined);
+ }, function (err) {
+ defer.reject(err);
+ originalModel.set('isRunning', undefined);
+ });
+ }, function (err) {
+ defer.reject(err);
+ originalModel.set('isRunning', undefined);
+ });
+
+ return defer.promise;
+ },
+
saveQuery: function (job, originalModel) {
var defer = Ember.RSVP.defer(),
self = this,
@@ -158,35 +208,41 @@ export default Ember.Controller.extend({
return query;
},
- buildQuery: function (query, shouldExplain) {
+ buildQuery: function (query, shouldExplain, shouldGetVisualExplain) {
var selections = this.get('openQueries.highlightedText'),
isQuerySelected = selections && selections[0] !== "",
- queryComponents = this.extractComponents(query.get('fileContent')),
+ queryContent = query ? query.get('fileContent') : '',
+ queryComponents = this.extractComponents(queryContent),
finalQuery = '',
- queries;
+ queries = null;
if (isQuerySelected) {
- queries = selections.map(function (s) {
- return s.replace(";", "");
- });
- } else {
- queries = queryComponents.queryString.split(';');
- queries = queries.filter(Boolean);
+ queryComponents.queryString = selections.join('');
+ }
+
+ queries = queryComponents.queryString.split(';');
+ queries = queries.map(function(s) {
+ return s.trim();
+ });
+ queries = queries.filter(Boolean);
+
+ // return false if multiple queries are selected
+ // @FIXME: Remove this to support multiple queries
+ if (queries.length > 1) {
+ return false;
}
queries = queries.map(function (query) {
if (shouldExplain) {
- if (query.indexOf(constants.namingConventions.explainPrefix) === -1) {
+ query = query.replace(/explain|formatted/gi, '').trim();
+
+ if (shouldGetVisualExplain) {
+ return constants.namingConventions.explainFormattedPrefix + query;
+ } else {
return constants.namingConventions.explainPrefix + query;
}
-
- return query;
} else {
- if (query.indexOf(constants.namingConventions.explainPrefix) > -1) {
- return query.replace(constants.namingConventions.explainPrefix, '');
- }
-
- return query;
+ return query.replace(/explain|formatted/gi, '').trim();
}
});
@@ -199,6 +255,7 @@ export default Ember.Controller.extend({
}
finalQuery += queries.join(";");
+ finalQuery += ";";
return finalQuery;
},
@@ -278,6 +335,10 @@ export default Ember.Controller.extend({
});
}.observes('content'),
+ selectedDatabaseChanged: function() {
+ this.set('content.dataBase', this.get('databases.selectedDatabase.name'));
+ }.observes('databases.selectedDatabase'),
+
csvUrl: function () {
if (this.get('content.constructor.typeKey') !== constants.namingConventions.job) {
return;
@@ -309,7 +370,7 @@ export default Ember.Controller.extend({
items.push(
Ember.Object.create({
title: Ember.I18n.t('buttons.saveCsv'),
- href: this.get('csvUrl')
+ action: 'downloadAsCSV'
})
);
}
@@ -350,7 +411,7 @@ export default Ember.Controller.extend({
}).then(function (response) {
self.pollSaveToHDFS(response);
}, function (response) {
- self.send('addAlert', constants.alerts.error, response.message, "alerts.errors.save.results");
+ self.notify.error(response.responseJSON.message, response.responseJSON.trace);
});
},
@@ -367,7 +428,7 @@ export default Ember.Controller.extend({
self.set('content.isRunning', false);
}
}, function (response) {
- self.send('addAlert', constants.alerts.error, response.message, "alerts.errors.save.results");
+ self.notify.error(response.responseJSON.message, response.responseJSON.trace);
});
}, 2000);
},
@@ -386,6 +447,25 @@ export default Ember.Controller.extend({
this.saveToHDFS();
},
+ downloadAsCSV: function() {
+ var self = this,
+ defer = Ember.RSVP.defer();
+
+ this.send('openModal', 'modal-save', {
+ heading: "modals.download.csv",
+ text: this.get('content.title'),
+ defer: defer
+ });
+
+ defer.promise.then(function (text) {
+ // download file ...
+ var urlString = "%@/?fileName=%@.csv";
+ var url = self.get('csvUrl');
+ url = urlString.fmt(url, text);
+ window.open(url);
+ });
+ },
+
insertUdf: function (item) {
var query = this.get('openQueries').getQueryForModel(this.get('model'));
@@ -418,17 +498,16 @@ export default Ember.Controller.extend({
addQuery: (function () {
var idCounter = 0;
- return function () {
+ return function (workSheetName) {
var model = this.store.createRecord(constants.namingConventions.savedQuery, {
dataBase: this.get('databases.selectedDatabase.name'),
- title: 'New Query',
- type: constants.namingConventions.savedQuery,
+ title: workSheetName ? workSheetName : Ember.I18n.t('titles.query.tab'),
queryFile: '',
id: 'fixture_' + idCounter
});
- if (idCounter) {
- model.set('title', model.get('title') + ' (' + idCounter + ')')
+ if (idCounter && !workSheetName) {
+ model.set('title', model.get('title') + ' (' + idCounter + ')');
}
idCounter++;
@@ -438,26 +517,34 @@ export default Ember.Controller.extend({
}()),
saveQuery: function () {
+ //case 1. Save a new query from a new query tab -> route changes to new id
+ //case 2. Save a new query from an existing query tab -> route changes to new id
+ //case 3. Save a new query from a job tab -> route doesn't change
+ //case 4. Update an existing query tab. -> route doesn't change
+
var self = this,
- wasNew = this.get('model.isNew'),
defer = Ember.RSVP.defer();
this.set('model.dataBase', this.get('databases.selectedDatabase.name'));
- this.send('openModal', 'modal-save', {
- heading: "modals.save.heading",
+ this.send('openModal', 'modal-save-query', {
+ heading: 'modals.save.heading',
+ message: 'modals.save.overwrite',
text: this.get('content.title'),
+ content: this.get('content'),
defer: defer
});
- defer.promise.then(function (text) {
- self.get('content').set('title', text);
-
- self.get('openQueries').save(self.get('content')).then(function () {
- if (wasNew) {
- self.transitionToRoute(constants.namingConventions.subroutes.savedQuery, self.get('model.id'));
- }
- });
+ defer.promise.then(function (result) {
+ if (result.get('overwrite')) {
+ self.get('openQueries').save(self.get('content'), null, true, result.get('text'));
+ } else {
+ self.get('openQueries').save(self.get('content'), null, false, result.get('text')).then(function (newId) {
+ if (self.get('model.constructor.typeKey') !== constants.namingConventions.job) {
+ self.transitionToRoute(constants.namingConventions.subroutes.savedQuery, newId);
+ }
+ });
+ }
});
},
@@ -476,7 +563,8 @@ export default Ember.Controller.extend({
self.transitionToRoute(constants.namingConventions.subroutes.historyQuery, job.get('id'));
}, function (err) {
- self.send('addAlert', constants.alerts.error, err.responseText, "alerts.errors.save.query");
+ var errorBody = err.responseJSON.trace ? err.responseJSON.trace : false;
+ self.notify.error(err.responseJSON.message, errorBody);
});
},
@@ -488,11 +576,13 @@ export default Ember.Controller.extend({
self.transitionToRoute(constants.namingConventions.subroutes.historyQuery, job.get('id'));
}, function (err) {
- self.send('addAlert', constants.alerts.error, err.responseText, "alerts.errors.save.query");
+ this.notify.error(err.responseJSON.message, err.responseJSON.trace);
});
},
toggleOverlay: function (targetController) {
+ var self = this;
+
if (this.get('visualExplain.showOverlay') && targetController !== 'visualExplain') {
this.set('visualExplain.showOverlay', false);
} else if (this.get('tezUI.showOverlay') && targetController !== 'tezUI') {
@@ -501,12 +591,28 @@ export default Ember.Controller.extend({
this.set('settings.showOverlay', false);
}
+ if (!targetController) {
+ return;
+ }
+
if (targetController !== 'settings') {
//set content for visual explain and tez ui.
this.set(targetController + '.content', this.get('content'));
}
- this.toggleProperty(targetController + '.showOverlay');
+ if (targetController === 'visualExplain' && !this.get(targetController + '.showOverlay')) {
+ this._executeQuery(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(targetController + '.json', json);
+ self.toggleProperty(targetController + '.showOverlay');
+ }
+ }, function (err) {
+ self.notify.error(err.responseJSON.message, err.responseJSON.trace);
+ });
+ } else {
+ this.toggleProperty(targetController + '.showOverlay');
+ }
}
}
});
http://git-wip-us.apache.org/repos/asf/ambari/blob/672eee34/contrib/views/hive/src/main/resources/ui/hive-web/app/controllers/index/history-query/explain.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/resources/ui/hive-web/app/controllers/index/history-query/explain.js b/contrib/views/hive/src/main/resources/ui/hive-web/app/controllers/index/history-query/explain.js
index dc75280..e61df51 100644
--- a/contrib/views/hive/src/main/resources/ui/hive-web/app/controllers/index/history-query/explain.js
+++ b/contrib/views/hive/src/main/resources/ui/hive-web/app/controllers/index/history-query/explain.js
@@ -39,30 +39,44 @@ export default Ember.ObjectController.extend({
if (cachedExplain) {
this.formatExplainResults(cachedExplain);
} else {
- this.getExplain();
+ this.getExplain(true);
}
}.observes('content'),
- getExplain: function () {
+ getExplain: function (firstPage, rows) {
var self = this;
var url = this.container.lookup('adapter:application').buildURL();
- url += '/' + constants.namingConventions.jobs + '/' + this.get('content.id') + '/results?first=true';
+ url += '/' + constants.namingConventions.jobs + '/' + this.get('content.id') + '/results';
+
+ if (firstPage) {
+ url += '?first=true';
+ }
Ember.$.getJSON(url).then(function (data) {
- var explainSet = self.get('cachedExplains').pushObject(Ember.Object.create({
- id: self.get('content.id'),
- explain: data
- }));
+ var explainSet;
+
+ //if rows from a previous page read exist, prepend them
+ if (rows) {
+ data.rows.unshiftObjects(rows);
+ }
- self.set('content.explain', explainSet);
+ if (!data.hasNext) {
+ explainSet = self.get('cachedExplains').pushObject(Ember.Object.create({
+ id: self.get('content.id'),
+ explain: data
+ }));
- self.formatExplainResults(explainSet);
+ self.set('content.explain', explainSet);
+
+ self.formatExplainResults(explainSet);
+ } else {
+ self.getExplain(false, data.rows);
+ }
});
},
formatExplainResults: function (explainSet) {
var formatted = [],
- orderedNodes = [],
currentNode,
currentNodeWhitespace,
previousNode,
@@ -116,4 +130,4 @@ export default Ember.ObjectController.extend({
this.set('formattedExplain', formatted);
}
-});
\ No newline at end of file
+});
http://git-wip-us.apache.org/repos/asf/ambari/blob/672eee34/contrib/views/hive/src/main/resources/ui/hive-web/app/controllers/index/history-query/logs.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/resources/ui/hive-web/app/controllers/index/history-query/logs.js b/contrib/views/hive/src/main/resources/ui/hive-web/app/controllers/index/history-query/logs.js
index 02edc86..59c0892 100644
--- a/contrib/views/hive/src/main/resources/ui/hive-web/app/controllers/index/history-query/logs.js
+++ b/contrib/views/hive/src/main/resources/ui/hive-web/app/controllers/index/history-query/logs.js
@@ -28,13 +28,22 @@ export default Ember.ObjectController.extend({
reloadJobLogs: function (job) {
var self = this,
defer = Ember.RSVP.defer(),
- handleError = function (err) {
- self.send('addAlert', constants.namingConventions.alerts.error, err.responseText);
+ handleError = function (error) {
+ job.set('isRunning', false);
+
+ if (typeof error === "string") {
+ self.notify.error(error);
+ } else {
+ self.notify.error(error.responseJSON.message, error.responseJSON.trace);
+ }
defer.reject();
};
job.reload().then(function () {
- self.get('files').reload(job.get('logFile')).then(function (file) {
+ if (utils.insensitiveCompare(job.get('status'), constants.statuses.error)) {
+ handleError(job.get('statusMessage'));
+ } else {
+ self.get('files').reload(job.get('logFile')).then(function (file) {
var fileContent = file.get('fileContent');
if (fileContent) {
@@ -42,9 +51,10 @@ export default Ember.ObjectController.extend({
}
defer.resolve();
- },function (err) {
- handleError(err);
- });
+ },function (err) {
+ handleError(err);
+ });
+ }
}, function (err) {
handleError(err);
});
http://git-wip-us.apache.org/repos/asf/ambari/blob/672eee34/contrib/views/hive/src/main/resources/ui/hive-web/app/controllers/index/history-query/results.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/resources/ui/hive-web/app/controllers/index/history-query/results.js b/contrib/views/hive/src/main/resources/ui/hive-web/app/controllers/index/history-query/results.js
index 7977541..9a50f27 100644
--- a/contrib/views/hive/src/main/resources/ui/hive-web/app/controllers/index/history-query/results.js
+++ b/contrib/views/hive/src/main/resources/ui/hive-web/app/controllers/index/history-query/results.js
@@ -22,6 +22,25 @@ import utils from 'hive/utils/functions';
export default Ember.ObjectController.extend({
cachedResults: [],
+ formattedResults: [],
+
+ processResults: function() {
+ var results = this.get('results');
+
+ if (!results || !results.schema || !results.rows) {
+ return;
+ }
+
+ var schema = results.schema.map(function(column) {
+ return {
+ name: column[0],
+ type: column[1],
+ index: column[2]
+ }
+ });
+
+ this.set('formattedResults', { schema: schema, rows: results.rows });
+ }.observes('results'),
keepAlive: function (job) {
Ember.run.later(this, function () {
@@ -73,6 +92,20 @@ export default Ember.ObjectController.extend({
return this.cachedResults.findBy('id', this.get('content.id')).results.indexOf(this.get('results')) <= 0;
}.property('results'),
+ getResultsJson: function (job) {
+ var defer = Ember.RSVP.defer();
+ var url = this.container.lookup('adapter:application').buildURL();
+ url += '/' + constants.namingConventions.jobs + '/' + job.get('id') + '/results?first=true';
+
+ Ember.$.getJSON(url).then(function (results) {
+ defer.resolve(JSON.parse(results.rows[0][0]));
+ }, function (err) {
+ defer.reject(err);
+ });
+
+ return defer.promise;
+ },
+
actions: {
getNextPage: function (firstPage, job) {
var self = this;
@@ -115,6 +148,7 @@ export default Ember.ObjectController.extend({
if (firstPage) {
self.keepAlive(job || self.get('content'));
}
+
}, function (err) {
self.set('error', err.responseText);
});
http://git-wip-us.apache.org/repos/asf/ambari/blob/672eee34/contrib/views/hive/src/main/resources/ui/hive-web/app/controllers/messages.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/resources/ui/hive-web/app/controllers/messages.js b/contrib/views/hive/src/main/resources/ui/hive-web/app/controllers/messages.js
new file mode 100644
index 0000000..6de1c64
--- /dev/null
+++ b/contrib/views/hive/src/main/resources/ui/hive-web/app/controllers/messages.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 default Ember.Controller.extend({
+ messages: Ember.computed.alias('notify.messages'),
+ count: Ember.computed.alias('messages.length'),
+
+ actions: {
+ removeMessage: function(message) {
+ this.notify.removeMessage(message);
+ },
+
+ removeAllMessages: function() {
+ this.notify.removeAllMessages();
+ }
+ }
+});
http://git-wip-us.apache.org/repos/asf/ambari/blob/672eee34/contrib/views/hive/src/main/resources/ui/hive-web/app/controllers/modal-save-query.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/resources/ui/hive-web/app/controllers/modal-save-query.js b/contrib/views/hive/src/main/resources/ui/hive-web/app/controllers/modal-save-query.js
new file mode 100644
index 0000000..d878bc7
--- /dev/null
+++ b/contrib/views/hive/src/main/resources/ui/hive-web/app/controllers/modal-save-query.js
@@ -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.
+ */
+
+import Ember from 'ember';
+import ModalSave from '../controllers/modal-save';
+import constants from '../utils/constants';
+
+export default ModalSave.extend({
+ showMessage: function () {
+ var content = this.get('content');
+
+ return !content.get('isNew') &&
+ content.get('title') === this.get('text') &&
+ content.get('constructor.typeKey') !== constants.namingConventions.job;
+ }.property('content.isNew', 'text'),
+
+ actions: {
+ save: function () {
+ this.send('closeModal');
+
+ this.defer.resolve(Ember.Object.create({
+ text: this.get('text'),
+ overwrite: this.get('showMessage')
+ }));
+ }
+ }
+});
http://git-wip-us.apache.org/repos/asf/ambari/blob/672eee34/contrib/views/hive/src/main/resources/ui/hive-web/app/controllers/open-queries.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/resources/ui/hive-web/app/controllers/open-queries.js b/contrib/views/hive/src/main/resources/ui/hive-web/app/controllers/open-queries.js
index 2abfff6..a0c033e 100644
--- a/contrib/views/hive/src/main/resources/ui/hive-web/app/controllers/open-queries.js
+++ b/contrib/views/hive/src/main/resources/ui/hive-web/app/controllers/open-queries.js
@@ -154,7 +154,7 @@ export default Ember.ArrayController.extend({
return defer.promise;
},
- save: function (model, query) {
+ save: function (model, query, isUpdating, newTitle) {
var tab = this.getTabForModel(model),
self = this,
wasNew,
@@ -168,6 +168,7 @@ export default Ember.ArrayController.extend({
if (model.get('isNew')) {
wasNew = true;
+ model.set('title', newTitle);
model.set('id', null);
}
@@ -175,16 +176,30 @@ export default Ember.ArrayController.extend({
if (model.get('constructor.typeKey') === constants.namingConventions.job) {
model = this.store.createRecord(constants.namingConventions.savedQuery, {
dataBase: this.get('databases.selectedDatabase.name'),
- title: model.get('title'),
+ title: newTitle,
queryFile: model.get('queryFile'),
owner: model.get('owner')
});
+ } else {
+ tab.set('name', newTitle);
+ }
+
+ //if saving a new query from an existing one create a new record and save it
+ if (!isUpdating && !model.get('isNew') && model.get('constructor.typeKey') !== constants.namingConventions.job) {
+ model = this.store.createRecord(constants.namingConventions.savedQuery, {
+ dataBase: this.get('databases.selectedDatabase.name'),
+ title: newTitle,
+ owner: model.get('owner')
+ });
+
+ wasNew = true;
}
model.save().then(function (updatedModel) {
- tab.set('name', updatedModel.get('title'));
jobModel.set('queryId', updatedModel.get('id'));
+ tab.set('isDirty', false);
+
var content = self.get('index').prependQuerySettings(query.get('fileContent'));
//update query tab path with saved model id if its a new record
if (wasNew) {
@@ -198,7 +213,7 @@ export default Ember.ArrayController.extend({
self.pushObject(updatedFile);
self.set('currentQuery', updatedFile);
- defer.resolve();
+ defer.resolve(updatedModel.get('id'));
}, function (err) {
defer.reject(err);
});
@@ -209,7 +224,7 @@ export default Ember.ArrayController.extend({
query.set('fileContent', content);
query.save().then(function () {
self.toggleProperty('tabUpdated');
- defer.resolve();
+ defer.resolve(updatedModel.get('id'));
}, function (err) {
defer.reject(err);
});
@@ -259,34 +274,83 @@ export default Ember.ArrayController.extend({
hasSettings;
},
+ isDirty: function(model) {
+ var query = this.getQueryForModel(model);
+
+ if (model.get('isNew') && !query.get('fileContent')) {
+ return false;
+ }
+
+ if (query && query.get('isDirty')) {
+ return true;
+ }
+
+ return !!(!model.get('queryId') && model.get('isDirty'));
+
+
+ },
+
+ updatedDeletedQueryTab: function (model) {
+ var tab = this.getTabForModel(model);
+
+ if (tab) {
+ this.closeTab(tab);
+ }
+ },
+
+ dirtyObserver: function () {
+ var tab;
+ var model = this.get('index.model');
+
+ if (model) {
+ tab = this.getTabForModel(model);
+
+ if (tab) {
+ tab.set('isDirty', this.isDirty(model));
+ }
+ }
+ }.observes('currentQuery.isDirty', 'currentQuery.fileContent'),
+
+ closeTab: function (tab, goToNextTab) {
+ var remainingTabs = this.get('queryTabs').without(tab);
+
+ this.set('queryTabs', remainingTabs);
+
+ //remove cached results set
+ if (tab.type === constants.namingConventions.job) {
+ this.get('jobResults').clearCachedResultsSet(tab.id);
+ this.get('jobExplain').clearCachedExplainSet(tab.id);
+ }
+
+ if (goToNextTab) {
+ this.navigateToLastTab();
+ }
+ },
+
+ navigateToLastTab: function () {
+ var lastTab = this.get('queryTabs.lastObject');
+
+ if (lastTab) {
+ if (lastTab.type === constants.namingConventions.job) {
+ this.transitionToRoute(constants.namingConventions.subroutes.historyQuery, lastTab.id);
+ } else {
+ this.transitionToRoute(constants.namingConventions.subroutes.savedQuery, lastTab.id);
+ }
+ } else {
+ this.get('index').send('addQuery');
+ }
+ },
+
actions: {
removeQueryTab: function (tab) {
var self = this,
- defer,
- remainingTabs = this.get('queryTabs').without(tab),
- lastTab = remainingTabs.get('lastObject'),
- closeTab = function () {
- self.set('queryTabs', remainingTabs);
-
- //remove cached results set
- if (tab.type === constants.namingConventions.job) {
- self.get('jobResults').clearCachedResultsSet(tab.id);
- self.get('jobExplain').clearCachedExplainSet(tab.id);
- }
-
- if (lastTab.type === constants.namingConventions.job) {
- self.transitionToRoute(constants.namingConventions.subroutes.historyQuery, lastTab.id);
- } else {
- self.transitionToRoute(constants.namingConventions.subroutes.savedQuery, lastTab.id);
- }
- };
+ defer;
this.store.find(tab.type, tab.id).then(function (model) {
var query = self.getQueryForModel(model);
- if ((model.get('isNew') && !query.get('fileContent')) ||
- (!model.get('isNew') && !query.get('isDirty'))) {
- closeTab();
+ if (!self.isDirty(model)) {
+ self.closeTab(tab, true);
} else {
defer = Ember.RSVP.defer();
self.send('openModal',
@@ -300,11 +364,11 @@ export default Ember.ArrayController.extend({
defer.promise.then(function (text) {
model.set('title', text);
self.save(model, query).then(function () {
- closeTab();
+ self.closeTab(tab, true);
});
}, function () {
model.rollback();
- closeTab();
+ self.closeTab(tab, true);
});
}
});
http://git-wip-us.apache.org/repos/asf/ambari/blob/672eee34/contrib/views/hive/src/main/resources/ui/hive-web/app/controllers/queries.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/resources/ui/hive-web/app/controllers/queries.js b/contrib/views/hive/src/main/resources/ui/hive-web/app/controllers/queries.js
index 0195dc2..aec2273 100644
--- a/contrib/views/hive/src/main/resources/ui/hive-web/app/controllers/queries.js
+++ b/contrib/views/hive/src/main/resources/ui/hive-web/app/controllers/queries.js
@@ -21,7 +21,11 @@ import FilterableMixin from 'hive/mixins/filterable';
import constants from 'hive/utils/constants';
export default Ember.ArrayController.extend(FilterableMixin, {
- needs: [ constants.namingConventions.routes.history ],
+ 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: [],
@@ -68,9 +72,11 @@ export default Ember.ArrayController.extend(FilterableMixin, {
actions: {
executeAction: function (action, savedQuery) {
+ var self = this;
+
switch (action) {
case "buttons.history":
- this.get('controllers.' + constants.namingConventions.routes.history).filterBy('queryId', savedQuery.get('id'), true);
+ this.get('history').filterBy('queryId', savedQuery.get('id'), true);
this.transitionToRoute(constants.namingConventions.routes.history);
break;
case "buttons.delete":
@@ -85,6 +91,7 @@ export default Ember.ArrayController.extend(FilterableMixin, {
defer.promise.then(function () {
savedQuery.destroyRecord();
+ self.get('openQueries').updatedDeletedQueryTab(savedQuery);
});
break;
http://git-wip-us.apache.org/repos/asf/ambari/blob/672eee34/contrib/views/hive/src/main/resources/ui/hive-web/app/controllers/settings.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/resources/ui/hive-web/app/controllers/settings.js b/contrib/views/hive/src/main/resources/ui/hive-web/app/controllers/settings.js
index 6ac0828..ddc5b1e 100644
--- a/contrib/views/hive/src/main/resources/ui/hive-web/app/controllers/settings.js
+++ b/contrib/views/hive/src/main/resources/ui/hive-web/app/controllers/settings.js
@@ -27,9 +27,22 @@ export default Ember.ArrayController.extend({
index: Ember.computed.alias('controllers.' + constants.namingConventions.index),
openQueries: Ember.computed.alias('controllers.' + constants.namingConventions.openQueries),
+ sessionTag: Ember.computed.alias('index.model.sessionTag'),
+ sessionActive: Ember.computed.alias('index.model.sessionActive'),
+
+ canInvalidateSession: Ember.computed.and('sessionTag', 'sessionActive'),
predefinedSettings: constants.hiveParameters,
+ selectedSettings: function() {
+ var predefined = this.get('predefinedSettings');
+ var current = this.get('currentSettings.settings');
+
+ return predefined.filter(function(setting) {
+ return current.findBy('key.name', setting.name);
+ });
+ }.property('currentSettings.settings.@each.key'),
+
currentSettings: function () {
var currentId = this.get('index.model.id');
var targetSettings = this.findBy('id', currentId);
@@ -150,9 +163,14 @@ export default Ember.ArrayController.extend({
return;
}
+ if (!predefined.validate) {
+ setting.set('valid', true);
+ return;
+ }
+
setting.set('valid', false);
});
- }.observes('currentSettings.[]', 'currentSettings.settings.@each.value', 'currentSettings.settings.@each.key'),
+ }.observes('currentSettings.[]', 'currentSettings.settings.[]', 'currentSettings.settings.@each.value', 'currentSettings.settings.@each.key'),
currentSettingsAreValid: function() {
var currentSettings = this.get('currentSettings.settings');
@@ -161,6 +179,24 @@ export default Ember.ArrayController.extend({
return invalid.length ? false : true;
}.property('currentSettings.settings.@each.value', 'currentSettings.settings.@each.key'),
+ loadSessionStatus: function() {
+ var model = this.get('index.model');
+ var sessionActive = this.get('sessionActive');
+ var sessionTag = this.get('sessionTag');
+ var adapter = this.container.lookup('adapter:application');
+ var url = adapter.buildURL() + '/jobs/sessions/' + sessionTag;
+
+ if (sessionTag && sessionActive === undefined) {
+ adapter.ajax(url, 'GET')
+ .then(function(response) {
+ model.set('sessionActive', response.session.actual);
+ })
+ .catch(function() {
+ model.set('sessionActive', false);
+ });
+ }
+ }.observes('index.model', 'index.model.status'),
+
actions: {
add: function () {
var currentId = this.get('index.model.id'),
@@ -185,6 +221,31 @@ export default Ember.ArrayController.extend({
});
this.get('currentSettings.settings').findBy('key', null).set('key', newKey);
+ },
+
+ removeAll: function() {
+ var currentId = this.get('index.model.id'),
+ querySettings = this.findBy('id', currentId);
+
+ querySettings.set('settings', []);
+ },
+
+ invalidateSession: function() {
+ var self = this;
+ var sessionTag = this.get('sessionTag');
+ var adapter = this.container.lookup('adapter:application');
+ var url = adapter.buildURL() + '/jobs/sessions/' + sessionTag;
+ var model = this.get('index.model');
+
+ // @TODO: Split this into then/catch once the BE is fixed
+ adapter.ajax(url, 'DELETE').catch(function(response) {
+ if ([200, 404].contains(response.status)) {
+ model.set('sessionActive', false);
+ self.notify.success('alerts.success.sessions.deleted');
+ } else {
+ self.notify.error(response.responseJSON.message, response.responseJSON.trace);
+ }
+ });
}
}
});
http://git-wip-us.apache.org/repos/asf/ambari/blob/672eee34/contrib/views/hive/src/main/resources/ui/hive-web/app/controllers/udf.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/resources/ui/hive-web/app/controllers/udf.js b/contrib/views/hive/src/main/resources/ui/hive-web/app/controllers/udf.js
index 657743c..3f8d3ed 100644
--- a/contrib/views/hive/src/main/resources/ui/hive-web/app/controllers/udf.js
+++ b/contrib/views/hive/src/main/resources/ui/hive-web/app/controllers/udf.js
@@ -50,8 +50,8 @@ export default Ember.ObjectController.extend({
this.send('openModal',
'modal-delete',
{
- heading: Ember.I18n.translations.modals.delete.heading,
- text: Ember.I18n.translations.modals.delete.message,
+ heading: 'modals.delete.heading',
+ text: 'modals.delete.message',
defer: defer
});
http://git-wip-us.apache.org/repos/asf/ambari/blob/672eee34/contrib/views/hive/src/main/resources/ui/hive-web/app/helpers/all-uppercase.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/resources/ui/hive-web/app/helpers/all-uppercase.js b/contrib/views/hive/src/main/resources/ui/hive-web/app/helpers/all-uppercase.js
index e5ea321..f068ed0 100644
--- a/contrib/views/hive/src/main/resources/ui/hive-web/app/helpers/all-uppercase.js
+++ b/contrib/views/hive/src/main/resources/ui/hive-web/app/helpers/all-uppercase.js
@@ -19,7 +19,7 @@
import Ember from 'ember';
export function allUppercase(input) {
- return input.toUpperCase();
+ return input ? input.toUpperCase() : input;
};
export default Ember.Handlebars.makeBoundHelper(allUppercase);
http://git-wip-us.apache.org/repos/asf/ambari/blob/672eee34/contrib/views/hive/src/main/resources/ui/hive-web/app/helpers/preformatted-string.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/resources/ui/hive-web/app/helpers/preformatted-string.js b/contrib/views/hive/src/main/resources/ui/hive-web/app/helpers/preformatted-string.js
new file mode 100644
index 0000000..bb3d006
--- /dev/null
+++ b/contrib/views/hive/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/672eee34/contrib/views/hive/src/main/resources/ui/hive-web/app/index.html
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/resources/ui/hive-web/app/index.html b/contrib/views/hive/src/main/resources/ui/hive-web/app/index.html
index 4f609bd..2cbf9f0 100644
--- a/contrib/views/hive/src/main/resources/ui/hive-web/app/index.html
+++ b/contrib/views/hive/src/main/resources/ui/hive-web/app/index.html
@@ -28,11 +28,15 @@
<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/672eee34/contrib/views/hive/src/main/resources/ui/hive-web/app/initializers/i18n.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/resources/ui/hive-web/app/initializers/i18n.js b/contrib/views/hive/src/main/resources/ui/hive-web/app/initializers/i18n.js
index 8d60248..b637c5e 100644
--- a/contrib/views/hive/src/main/resources/ui/hive-web/app/initializers/i18n.js
+++ b/contrib/views/hive/src/main/resources/ui/hive-web/app/initializers/i18n.js
@@ -28,9 +28,13 @@ export default {
Ember.I18n.translations = TRANSLATIONS;
Ember.TextField.reopen(Ember.I18n.TranslateableAttributes);
}
-};
+}
TRANSLATIONS = {
+ tooltips: {
+ refresh: 'Refresh database',
+ loadSample: 'Load sample data'
+ },
alerts: {
errors: {
save: {
@@ -40,6 +44,17 @@ TRANSLATIONS = {
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'
}
}
},
@@ -53,7 +68,12 @@ TRANSLATIONS = {
save: {
heading: 'Saving item',
saveBeforeCloseHeading: "Save item before closing?",
- message: 'Enter name:'
+ message: 'Enter name:',
+ overwrite: 'Saving will overwrite previously saved query'
+ },
+
+ download: {
+ csv: 'Download results as CSV'
}
},
titles: {
@@ -62,13 +82,15 @@ TRANSLATIONS = {
results: 'Search Results',
settings: 'Database Settings',
query: {
+ tab: 'Worksheet',
editor: 'Query Editor',
process: 'Query Process Results',
parameters: 'Parameters',
visualExplain: 'Visual Explain',
tez: 'TEZ'
},
- download: 'Save results...'
+ download: 'Save results...',
+ tableSample: '{{tableName}} sample'
},
placeholders: {
search: {
@@ -130,7 +152,7 @@ TRANSLATIONS = {
explain: 'Explain',
saveAs: 'Save as...',
save: 'Save',
- newQuery: 'New Query',
+ newQuery: 'New Worksheet',
newUdf: 'New UDF',
history: 'History',
ok: 'OK',
@@ -147,9 +169,13 @@ TRANSLATIONS = {
runOnTez: 'Run on Tez'
},
labels: {
- noTablesMatches: 'No tables matches for'
+ noTablesMatch: 'No tables match',
+ table: 'Table '
},
popover: {
+ visualExplain: {
+ statistics: "Statistics"
+ },
queryEditorHelp: {
title: "Did you know?",
content: {
@@ -163,7 +189,10 @@ TRANSLATIONS = {
tez: {
errors: {
'not.deployed': "Tez View isn't deployed.",
- 'no.instance': "No instance of Tez View found."
+ 'no.instance': "No instance of Tez View found.",
+ 'no.dag': "No DAG available"
}
- }
+ },
+
+ generalError: 'Unexpected error'
};
http://git-wip-us.apache.org/repos/asf/ambari/blob/672eee34/contrib/views/hive/src/main/resources/ui/hive-web/app/initializers/notify.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/resources/ui/hive-web/app/initializers/notify.js b/contrib/views/hive/src/main/resources/ui/hive-web/app/initializers/notify.js
new file mode 100644
index 0000000..be9c359
--- /dev/null
+++ b/contrib/views/hive/src/main/resources/ui/hive-web/app/initializers/notify.js
@@ -0,0 +1,26 @@
+/**
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+export default {
+ name: 'notify',
+ initialize: function(container, app) {
+ app.inject('route', 'notify', 'service:notify');
+ app.inject('controller', 'notify', 'service:notify');
+ app.inject('component', 'notify', 'service:notify');
+ app.inject('views', 'notify', 'service:notify');
+ }
+};
http://git-wip-us.apache.org/repos/asf/ambari/blob/672eee34/contrib/views/hive/src/main/resources/ui/hive-web/app/models/file.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/resources/ui/hive-web/app/models/file.js b/contrib/views/hive/src/main/resources/ui/hive-web/app/models/file.js
index f8f1b9b..c13d4e1 100644
--- a/contrib/views/hive/src/main/resources/ui/hive-web/app/models/file.js
+++ b/contrib/views/hive/src/main/resources/ui/hive-web/app/models/file.js
@@ -21,6 +21,6 @@ import DS from 'ember-data';
export default DS.Model.extend({
fileContent: DS.attr(),
hasNext: DS.attr(),
- page: DS.attr,
+ page: DS.attr('number'),
pageCount: DS.attr()
});
http://git-wip-us.apache.org/repos/asf/ambari/blob/672eee34/contrib/views/hive/src/main/resources/ui/hive-web/app/models/job.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/resources/ui/hive-web/app/models/job.js b/contrib/views/hive/src/main/resources/ui/hive-web/app/models/job.js
index 06bdc2e..472f824 100644
--- a/contrib/views/hive/src/main/resources/ui/hive-web/app/models/job.js
+++ b/contrib/views/hive/src/main/resources/ui/hive-web/app/models/job.js
@@ -26,12 +26,17 @@ export default DS.Model.extend({
dataBase: DS.attr('string'),
duration: DS.attr(),
status: DS.attr('string'),
+ statusMessage: DS.attr('string'),
dateSubmitted: DS.attr('date'),
forcedContent: DS.attr('string'),
logFile: DS.attr('string'),
dagName: DS.attr('string'),
dagId: DS.attr('string'),
sessionTag: DS.attr('string'),
+ page: DS.attr(),
+ statusDir: DS.attr('string'),
+ applicationId: DS.attr(),
+ confFile: DS.attr('string'),
dateSubmittedTimestamp: function () {
var date = this.get('dateSubmitted');
http://git-wip-us.apache.org/repos/asf/ambari/blob/672eee34/contrib/views/hive/src/main/resources/ui/hive-web/app/routes/application.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/resources/ui/hive-web/app/routes/application.js b/contrib/views/hive/src/main/resources/ui/hive-web/app/routes/application.js
index 2f9a5ae..bf413a3 100644
--- a/contrib/views/hive/src/main/resources/ui/hive-web/app/routes/application.js
+++ b/contrib/views/hive/src/main/resources/ui/hive-web/app/routes/application.js
@@ -33,6 +33,8 @@ export default Ember.Route.extend({
actions: {
openModal: function (modalTemplate, options) {
this.controllerFor(modalTemplate).setProperties({
+ content: options.content || {},
+ message: options.message,
heading: options.heading,
text: options.text,
defer: options.defer
@@ -51,11 +53,16 @@ export default Ember.Route.extend({
});
},
- addAlert: function (type, message, title) {
- this.controllerFor(constants.namingConventions.alerts).pushObject({
- type: type,
- title: title,
- content: message
+ openOverlay: function(overlay) {
+ return this.render(overlay.template, {
+ outlet: overlay.outlet,
+ into: overlay.into
+ });
+ },
+ closeOverlay: function(overlay) {
+ return this.disconnectOutlet({
+ outlet: overlay.outlet,
+ parentView: overlay.into
});
}
}
http://git-wip-us.apache.org/repos/asf/ambari/blob/672eee34/contrib/views/hive/src/main/resources/ui/hive-web/app/routes/index/index.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/resources/ui/hive-web/app/routes/index/index.js b/contrib/views/hive/src/main/resources/ui/hive-web/app/routes/index/index.js
index f2be946..120a102 100644
--- a/contrib/views/hive/src/main/resources/ui/hive-web/app/routes/index/index.js
+++ b/contrib/views/hive/src/main/resources/ui/hive-web/app/routes/index/index.js
@@ -23,14 +23,14 @@ export default Ember.Route.extend({
beforeModel: function () {
var model = this.controllerFor(constants.namingConventions.routes.index).get('model');
- if (model) {
+ if (model && !model.get('isDeleted')) {
if (model.get('constructor.typeKey') === constants.namingConventions.job) {
this.transitionTo(constants.namingConventions.subroutes.historyQuery, model);
} else {
this.transitionTo(constants.namingConventions.subroutes.savedQuery, model);
}
} else {
- this.controllerFor(constants.namingConventions.routes.index).send('addQuery');
+ this.controllerFor(constants.namingConventions.openQueries).navigateToLastTab();
}
}
});
http://git-wip-us.apache.org/repos/asf/ambari/blob/672eee34/contrib/views/hive/src/main/resources/ui/hive-web/app/services/notify.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/resources/ui/hive-web/app/services/notify.js b/contrib/views/hive/src/main/resources/ui/hive-web/app/services/notify.js
new file mode 100644
index 0000000..fbd50cd
--- /dev/null
+++ b/contrib/views/hive/src/main/resources/ui/hive-web/app/services/notify.js
@@ -0,0 +1,88 @@
+/**
+* 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.Service.extend({
+ types: constants.notify,
+
+ messages : Ember.ArrayProxy.create({ content : [] }),
+ notifications : Ember.ArrayProxy.create({ content : [] }),
+
+ add: function(type, message, body) {
+ var formattedBody = this.formatMessageBody(body);
+
+ var notification = Ember.Object.create({
+ type : type,
+ message : message,
+ body : formattedBody
+ });
+
+ this.messages.pushObject(notification);
+ this.notifications.pushObject(notification);
+ },
+
+ info: function(message, body) {
+ this.add(this.types.INFO, message, body);
+ },
+
+ warn: function(message, body) {
+ this.add(this.types.WARN, message, body);
+ },
+
+ error: function(message, body) {
+ this.add(this.types.ERROR, message, body);
+ },
+
+ success: function(message, body) {
+ this.add(this.types.SUCCESS, message, body);
+ },
+
+ formatMessageBody: function(body) {
+ if (!body) {
+ return;
+ }
+
+ if (typeof body === "string") {
+ return body;
+ }
+
+ if (typeof body === "object") {
+ var formattedBody = "";
+ for (var key in body) {
+ formattedBody += "\n\n%@:\n%@".fmt(key, body[key]);
+ }
+
+ return formattedBody;
+ }
+ },
+
+ removeMessage: function(message) {
+ this.messages.removeObject(message);
+ this.notifications.removeObject(message);
+ },
+
+ removeNotification: function(notification) {
+ this.notifications.removeObject(notification);
+ },
+
+ removeAllMessages: function() {
+ this.messages.removeAt(0, this.messages.get('length'));
+ }
+
+});
http://git-wip-us.apache.org/repos/asf/ambari/blob/672eee34/contrib/views/hive/src/main/resources/ui/hive-web/app/styles/app.scss
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/resources/ui/hive-web/app/styles/app.scss b/contrib/views/hive/src/main/resources/ui/hive-web/app/styles/app.scss
index 3f49713..7fdf096 100644
--- a/contrib/views/hive/src/main/resources/ui/hive-web/app/styles/app.scss
+++ b/contrib/views/hive/src/main/resources/ui/hive-web/app/styles/app.scss
@@ -16,11 +16,15 @@
* limitations under the License.
*/
+@import 'vars';
@import 'dropdown-submenu';
+@import 'mixins';
+@import 'notifications';
+@import 'query-tabs';
-$panel-background: #f5f5f5;
-$placeholder-color: #aaa;
-$border-color: #ddd;
+a {
+ word-wrap: break-word;
+}
@-webkit-keyframes fadeIn {
0% {opacity: 0;}
@@ -60,6 +64,10 @@ $border-color: #ddd;
display: flex;
}
+#visual-explain {
+ white-space: nowrap;
+}
+
#visual-explain, #tez-ui {
position: absolute;
left: 0;
@@ -68,13 +76,6 @@ $border-color: #ddd;
background: white;
}
-#alerts-container {
- position: absolute;
- left: 15px;
- right: 15px;
- z-index: 1100;
-}
-
aside hr {
margin: 10px 0;
}
@@ -181,21 +182,10 @@ dropdown .fa-remove {
}
.main-content {
+ width: 90%;
flex-grow: 1;
}
-.query-menu {
- margin-top: 57px;
-
- span, popover {
- cursor: pointer;
- overflow: hidden;
- display: block;
- border-bottom: 1px solid $border-color;
- padding: 10px;
- }
-}
-
.queries-icon {
font-size: 20px;
@@ -209,11 +199,23 @@ dropdown .fa-remove {
}
}
+.query-context-tab {
+ background: #f1f1f1;
+
+ &.active {
+ background: white;
+ }
+}
+
.alert {
margin-bottom: 5px;
padding-bottom: 10px;
padding-top: 10px;
+ strong {
+ text-decoration: underline;
+ }
+
.alert-message {
max-height: 250px;
overflow-y: auto;
@@ -317,22 +319,8 @@ body {
}
.settings-container {
- width: 100%;
- overflow-y: scroll;
- height: calc(100% - 41px);
- top: 41px;
- left: 0;
- background-color: #fff;
- position: absolute;
- padding: 0 15px;
- z-index: 1000;
-
- border: 1px solid $border-color;
- -webkit-animation-duration: .5s;
- animation-duration: .5s;
- -webkit-animation-fill-mode: both;
- animation-fill-mode: both;
}
+
.settings-container .close-settings {
float: right;
font-size: 18px;
@@ -377,3 +365,77 @@ tree-view ul li {
height: 822px;
border: none;
}
+
+.edge {
+ text-align: center;
+ font-size: 10px;
+ font-weight: 800;
+
+ .edge-path {
+ height: 2px;
+ background-color: #dedede;
+ position: absolute;
+ }
+
+ .edge-arrow {
+ position: absolute;
+ width: 0;
+ height: 0;
+ border-top: 5px solid transparent;
+ border-bottom: 5px solid transparent;
+ border-right: 10px solid black;
+ }
+}
+
+.nodes {
+ width: 100%;
+ position: relative;
+
+ .node-container {
+ text-align: center;
+
+ .node {
+ border: 1px solid #bbb;
+ background: #fefefe;
+ font-size: 12px;
+ box-sizing: border-box;
+ text-align: left;
+ max-width: 200px;
+ margin: 0 25px 100px 0;
+ display: inline-block;
+ vertical-align: top;
+
+ @include box-shadow(1px, 1px, 15px, #888888);
+
+ &.table-node, &.output-node {
+ background-color: ghostwhite;
+ color: gray;
+ padding: 5px;
+ text-align: center;
+ min-width: 100px;
+ line-height: 8px;
+ vertical-align: bottom;
+ margin-bottom: 50px;
+ }
+
+ .node-heading {
+ padding: 5px;
+ text-align: center;
+ background-color: lightslategrey;
+ color: white;
+ }
+
+ .node-content {
+ max-height: 300px;
+ white-space: normal;
+ padding: 5px;
+ overflow-y: auto;
+ overflow-x: hidden;
+
+ .fa {
+ color: green;
+ }
+ }
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/ambari/blob/672eee34/contrib/views/hive/src/main/resources/ui/hive-web/app/styles/mixins.scss
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/resources/ui/hive-web/app/styles/mixins.scss b/contrib/views/hive/src/main/resources/ui/hive-web/app/styles/mixins.scss
new file mode 100644
index 0000000..95e4ae8
--- /dev/null
+++ b/contrib/views/hive/src/main/resources/ui/hive-web/app/styles/mixins.scss
@@ -0,0 +1,23 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+@mixin box-shadow($horizontal, $vertical, $blur, $color) {
+ -webkit-box-shadow: $horizontal $vertical $blur $color;
+ -moz-box-shadow: $horizontal $vertical $blur $color;
+ box-shadow: $horizontal $vertical $blur $color;
+}
http://git-wip-us.apache.org/repos/asf/ambari/blob/672eee34/contrib/views/hive/src/main/resources/ui/hive-web/app/styles/notifications.scss
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/resources/ui/hive-web/app/styles/notifications.scss b/contrib/views/hive/src/main/resources/ui/hive-web/app/styles/notifications.scss
new file mode 100644
index 0000000..c676e4e
--- /dev/null
+++ b/contrib/views/hive/src/main/resources/ui/hive-web/app/styles/notifications.scss
@@ -0,0 +1,36 @@
+/**
+* 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.
+*/
+.notifications-container {
+ position: absolute;
+ top: 4px;
+ right: 20px;
+ width: 600px;
+ z-index: 9999;
+}
+
+.notification > .fa {
+ width: 15px;
+ text-align: center;
+ margin-right: 10px;
+}
+
+.notifications-container .notification {
+ word-wrap: break-word;
+ max-height: 200px;
+ overflow-x: auto;
+}
http://git-wip-us.apache.org/repos/asf/ambari/blob/672eee34/contrib/views/hive/src/main/resources/ui/hive-web/app/styles/query-tabs.scss
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/resources/ui/hive-web/app/styles/query-tabs.scss b/contrib/views/hive/src/main/resources/ui/hive-web/app/styles/query-tabs.scss
new file mode 100644
index 0000000..d23a751
--- /dev/null
+++ b/contrib/views/hive/src/main/resources/ui/hive-web/app/styles/query-tabs.scss
@@ -0,0 +1,68 @@
+/**
+* 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.
+*/
+.query-menu {
+ margin-top: 57px;
+
+ span, popover {
+ cursor: pointer;
+ display: block;
+ border-bottom: 1px solid $border-color;
+ padding: 10px;
+ }
+}
+
+.fa.panel-action-icon {
+ line-height: 22px;
+ font-size: 16px;
+}
+
+.editor-overlay {
+ width: 100%;
+ overflow-y: scroll;
+ height: calc(100% - 41px);
+ top: 41px;
+ left: 0;
+ background-color: #fff;
+ position: absolute;
+ padding: 0 15px;
+ z-index: 1000;
+
+ border: 1px solid $border-color;
+ -webkit-animation-duration: .5s;
+ animation-duration: .5s;
+ -webkit-animation-fill-mode: both;
+ animation-fill-mode: both;
+}
+
+.message-body {
+ margin-top: 10px;
+}
+
+.query-menu-tab {
+ position: relative;
+}
+.query-menu-tab .badge {
+ position: absolute;
+ top: -4px;
+ left: -4px;
+ background-color: red;
+ color: #fff;
+ padding: 2px 4px;
+ font-weight: bold;
+ z-index: 9999;
+}
http://git-wip-us.apache.org/repos/asf/ambari/blob/672eee34/contrib/views/hive/src/main/resources/ui/hive-web/app/styles/vars.scss
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/resources/ui/hive-web/app/styles/vars.scss b/contrib/views/hive/src/main/resources/ui/hive-web/app/styles/vars.scss
new file mode 100644
index 0000000..eec2277
--- /dev/null
+++ b/contrib/views/hive/src/main/resources/ui/hive-web/app/styles/vars.scss
@@ -0,0 +1,20 @@
+/**
+* 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.
+*/
+$panel-background: #f5f5f5;
+$placeholder-color: #aaa;
+$border-color: #ddd;
http://git-wip-us.apache.org/repos/asf/ambari/blob/672eee34/contrib/views/hive/src/main/resources/ui/hive-web/app/templates/alerts.hbs
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/resources/ui/hive-web/app/templates/alerts.hbs b/contrib/views/hive/src/main/resources/ui/hive-web/app/templates/alerts.hbs
deleted file mode 100644
index 0fbf34a..0000000
--- a/contrib/views/hive/src/main/resources/ui/hive-web/app/templates/alerts.hbs
+++ /dev/null
@@ -1,23 +0,0 @@
-{{!
-* 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 id="alerts-container">
- {{#each alert in this}}
- {{alert-message-widget message=alert removeMessage="remove" removeLater="removeLater"}}
- {{/each}}
-</div>
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/ambari/blob/672eee34/contrib/views/hive/src/main/resources/ui/hive-web/app/templates/application.hbs
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/resources/ui/hive-web/app/templates/application.hbs b/contrib/views/hive/src/main/resources/ui/hive-web/app/templates/application.hbs
index 055a87b..99662dd 100644
--- a/contrib/views/hive/src/main/resources/ui/hive-web/app/templates/application.hbs
+++ b/contrib/views/hive/src/main/resources/ui/hive-web/app/templates/application.hbs
@@ -16,10 +16,11 @@
* limitations under the License.
}}
+{{notify-widget}}
{{render 'navbar'}}
<div id="content">
{{outlet}}
{{outlet "modal"}}
-</div>
\ No newline at end of file
+</div>