YARN-6184. Introduce loading icon in each page of new YARN UI. Contributed by Akhil PB.

This commit is contained in:
Sunil G 2017-02-22 11:54:32 +05:30
parent 003ae00693
commit f1c9cafefc
24 changed files with 251 additions and 211 deletions

View File

@ -128,7 +128,7 @@ export default Ember.Component.extend({
.attr("transform", function() { return "translate(" + source.y0 + "," + source.x0 + ")"; })
.on("mouseover", function(d){
if (d.queueData.get("name") !== this.get("selected")) {
document.location.href = "#/yarn-queues/" + d.queueData.get("name");
document.location.href = "#/yarn-queues/" + d.queueData.get("name") + "!";
}
Ember.run.later(this, function () {
@ -143,7 +143,7 @@ export default Ember.Component.extend({
}.bind(this))
.on("click", function (d) {
document.location.href = "#/yarn-queue/" + d.queueData.get("name");
document.location.href = "#/yarn-queue/" + d.queueData.get("name") + "/info";
});
nodeEnter.append("circle")

View File

@ -22,10 +22,11 @@ export default Ember.Controller.extend({
needReload: true,
selectedQueue: undefined,
breadcrumbs: Ember.computed("model.selected", function () {
breadcrumbs: Ember.computed("model.selected", "target.currentPath", function () {
var queueName = this.get("model.selected");
var path = this.get("target.currentPath");
return [{
var crumbs = [{
text: "Home",
routeName: 'application'
}, {
@ -34,11 +35,19 @@ export default Ember.Controller.extend({
model: 'root'
}, {
text: `Queue [ ${queueName} ]`,
routeName: 'yarn-queue',
routeName: 'yarn-queue.info',
model: queueName
}];
}),
if (path && path === "yarn-queue.apps") {
crumbs.push({
text: "Applications",
routeName: 'yarn-queue.apps',
model: queueName
});
}
return crumbs;
})
});

View File

@ -21,6 +21,7 @@ import Ember from 'ember';
export default Ember.Controller.extend({
needReload: true,
selectedQueue: undefined,
showLoading: true,
breadcrumbs: [{
text: "Home",

View File

@ -32,6 +32,10 @@ Router.map(function() {
this.route('table');
this.route('heatmap');
});
this.route('yarn-queue', {path: '/yarn-queue/:queue_name'}, function() {
this.route('info');
this.route('apps');
});
this.route('yarn-nodes-heatmap');
this.route('yarn-node', { path: '/yarn-node/:node_id/:node_addr' });
this.route('yarn-node-apps', { path: '/yarn-node-apps/:node_id/:node_addr' });
@ -43,7 +47,6 @@ Router.map(function() {
{ path: '/yarn-node-container/:node_id/:node_addr/:container_id' });
this.route('yarn-container-log', { path:
'/yarn-container-log/:node_id/:node_addr/:container_id/:filename' });
this.route('yarn-queue', { path: '/yarn-queue/:queue_name' });
this.route('cluster-overview');
this.route('yarn-app', { path: '/yarn-app/:app_id' });
@ -52,7 +55,6 @@ Router.map(function() {
this.route('notfound', { path: '*:' });
this.route('yarn-app-attempts', { path: '/yarn-app-attempts/:app_id' });
this.route('yarn-queues', { path: '/yarn-queues/:queue_name' });
this.route('yarn-queue-apps', { path: '/yarn-queue-apps/:queue_name' });
});
export default Router;

View File

@ -23,7 +23,7 @@ import AbstractRoute from './abstract';
export default AbstractRoute.extend({
model() {
return Ember.RSVP.hash({
clusterMetrics: this.store.findAll('ClusterMetric'),
clusterMetrics: this.store.findAll('ClusterMetric', {reload: true}),
apps: this.store.query('yarn-app',
{
state: "RUNNING"

View File

@ -23,7 +23,7 @@ import AbstractRoute from './abstract';
export default AbstractRoute.extend({
model(param) {
return Ember.RSVP.hash({
attempt: this.store.findRecord('yarn-app-attempt', param.app_attempt_id),
attempt: this.store.findRecord('yarn-app-attempt', param.app_attempt_id, {reload: true}),
rmContainers: this.store.query('yarn-container',
{

View File

@ -23,8 +23,8 @@ import AbstractRoute from './abstract';
export default AbstractRoute.extend({
model() {
return Ember.RSVP.hash({
apps: this.store.findAll('yarn-app'),
clusterMetrics: this.store.findAll('ClusterMetric'),
apps: this.store.findAll('yarn-app', {reload: true}),
clusterMetrics: this.store.findAll('ClusterMetric', {reload: true}),
});
},

View File

@ -25,8 +25,8 @@ export default AbstractRoute.extend({
// Fetches data from both NM and RM. RM is queried to get node usage info.
return Ember.RSVP.hash({
nodeInfo: { id: param.node_id, addr: param.node_addr },
node: this.store.findRecord('yarn-node', param.node_addr),
rmNode: this.store.findRecord('yarn-rm-node', param.node_id)
node: this.store.findRecord('yarn-node', param.node_addr, {reload: true}),
rmNode: this.store.findRecord('yarn-rm-node', param.node_id, {reload: true})
});
},

View File

@ -23,8 +23,8 @@ import AbstractRoute from './abstract';
export default AbstractRoute.extend({
model() {
return Ember.RSVP.hash({
nodes: this.store.findAll('yarn-rm-node'),
clusterMetrics: this.store.findAll('ClusterMetric'),
nodes: this.store.findAll('yarn-rm-node', {reload: true}),
clusterMetrics: this.store.findAll('ClusterMetric', {reload: true}),
});
},

View File

@ -26,13 +26,12 @@ export default AbstractRoute.extend({
selected : param.queue_name,
queues: this.store.query('yarn-queue', {}),
selectedQueue : undefined,
apps: undefined, // apps of selected queue
apps: this.store.findAll('yarn-app', {reload: true})
});
},
afterModel(model) {
model.selectedQueue = this.store.peekRecord('yarn-queue', model.selected);
model.apps = this.store.findAll('yarn-app');
},
unloadAll() {

View File

@ -18,29 +18,5 @@
import Ember from 'ember';
export default Ember.Controller.extend({
needReload: true,
selectedQueue: undefined,
breadcrumbs: Ember.computed("model.selected", function () {
var queueName = this.get("model.selected");
return [{
text: "Home",
routeName: 'application'
}, {
text: "Queues",
routeName: 'yarn-queues',
model: 'root'
}, {
text: `Queue [ ${queueName} ]`,
routeName: 'yarn-queue',
model: queueName
}, {
text: "Applications",
}];
}),
export default Ember.Route.extend({
});

View File

@ -18,25 +18,5 @@
import Ember from 'ember';
import AbstractRoute from './abstract';
export default AbstractRoute.extend({
model(param) {
return Ember.RSVP.hash({
selected : param.queue_name,
queues: this.store.findAll('yarn-queue'),
selectedQueue : undefined,
apps: undefined, // apps of selected queue
});
},
afterModel(model) {
model.selectedQueue = this.store.peekRecord('yarn-queue', model.selected);
model.apps = this.store.findAll('yarn-app');
},
unloadAll() {
this.store.unloadAll('yarn-queue');
this.store.unloadAll('yarn-app');
}
export default Ember.Route.extend({
});

View File

@ -22,21 +22,50 @@ import AbstractRoute from './abstract';
export default AbstractRoute.extend({
model(param) {
var queueName = param.queue_name? param.queue_name.split('!')[0] : 'root';
if (param.queue_name && param.queue_name.split('!').length > 1) {
this.controllerFor('yarn-queues').set('showLoading', false);
} else {
this.controllerFor('yarn-queues').set('showLoading', true);
}
return Ember.RSVP.hash({
selected : param.queue_name,
selected : queueName,
queues: this.store.query('yarn-queue', {}),
selectedQueue : undefined,
apps: undefined, // apps of selected queue
apps: this.store.findAll('yarn-app', {reload: true})
});
},
afterModel(model) {
model.selectedQueue = this.store.peekRecord('yarn-queue', model.selected);
model.apps = this.store.findAll('yarn-app');
},
unloadAll() {
this.store.unloadAll('yarn-queue');
this.store.unloadAll('yarn-app');
},
refreshModel() {
var param = this.paramsFor('yarn-queues');
var queueName = param.queue_name? param.queue_name.split('!')[0] : 'root';
if (queueName !== param.queue_name) {
this.transitionTo('yarn-queues', queueName);
} else {
this.refresh();
}
},
actions: {
refresh: function () {
this.unloadAll();
this.refreshModel();
},
loading() {
if (!this.controllerFor('yarn-queues').get('showLoading')) {
return false;
}
return true;
}
}
});

View File

@ -137,6 +137,14 @@ div.tooltip {
pointer-events: none;
}
/*
* Loading icon styles
*/
.loading-mask > img {
display: block;
margin: 0 auto;
}
/*
* Data table
*/

View File

@ -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.
}}
<div class="col-md-12 container-fluid">
<div class="loading-mask">
<img src="assets/images/spinner.gif" alt="Loading...">
</div>
</div>

View File

@ -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.
}}
<div class="col-md-12 container-fluid">
<div class="loading-mask">
<img src="assets/images/spinner.gif" alt="Loading...">
</div>
</div>

View File

@ -1,64 +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.
}}
{{breadcrumb-bar breadcrumbs=breadcrumbs}}
<div class="col-md-12 container-fluid">
<div class="row">
<div class="col-md-2 container-fluid">
<div class="panel panel-default">
<div class="panel-heading">
<h4>Application</h4>
</div>
<div class="panel-body">
<ul class="nav nav-pills nav-stacked" id="stacked-menu">
<ul class="nav nav-pills nav-stacked collapse in">
{{#link-to 'yarn-queue' tagName="li"}}
{{#link-to 'yarn-queue' model.selected}}Information
{{/link-to}}
{{/link-to}}
{{#link-to 'yarn-queue-apps' tagName="li"}}
{{#link-to 'yarn-queue-apps' model.selected}}Applications List
{{/link-to}}
{{/link-to}}
</ul>
</ul>
</div>
</div>
</div>
<div class="col-md-10 container-fluid">
<!-- timeline view of children -->
<div class="row">
<div class="col-lg-12 container-fluid">
{{#if model.apps}}
{{app-table table-id="apps-table" arr=model.apps}}
{{simple-table table-id="apps-table" bFilter=true colTypes="elapsed-time" colTargets="7"}}
{{else}}
<h4 align = "center">Could not find any applications from this cluster</h4>
{{/if}}
</div>
</div>
</div>
</div>
</div>
{{outlet}}

View File

@ -24,17 +24,17 @@
<div class="col-md-2 container-fluid">
<div class="panel panel-default">
<div class="panel-heading">
<h4>Application</h4>
<h4>Queue</h4>
</div>
<div class="panel-body">
<ul class="nav nav-pills nav-stacked" id="stacked-menu">
<ul class="nav nav-pills nav-stacked collapse in">
{{#link-to 'yarn-queue' tagName="li"}}
{{#link-to 'yarn-queue' model.selected}}Information
{{#link-to 'yarn-queue.info' tagName="li"}}
{{#link-to 'yarn-queue.info' model.selected}}Information
{{/link-to}}
{{/link-to}}
{{#link-to 'yarn-queue-apps' tagName="li"}}
{{#link-to 'yarn-queue-apps' model.selected}}Applications List
{{#link-to 'yarn-queue.apps' tagName="li"}}
{{#link-to 'yarn-queue.apps' model.selected}}Applications List
{{/link-to}}
{{/link-to}}
</ul>
@ -44,65 +44,8 @@
</div>
<div class="col-md-10 container-fluid">
<!-- timeline view of children -->
<div class="row">
<div class="col-lg-4 container-fluid">
<div class="panel panel-default">
<div class="panel-heading">
Queue Information
</div>
{{queue-configuration-table queue=model.selectedQueue}}
</div>
</div>
<div class="col-lg-4 container-fluid">
<div class="panel panel-default">
<div class="panel-heading">
Queue Capacities
</div>
<div class="container-fluid" id="capacity-bar-chart">
<br/>
{{bar-chart data=model.selectedQueue.capacitiesBarChartData
title=""
parentId="capacity-bar-chart"
textWidth=170
ratio=0.55
maxHeight=350}}
</div>
</div>
</div>
{{#if model.selectedQueue.hasUserUsages}}
<div class="col-lg-4 container-fluid" id="userusage-donut-chart">
{{donut-chart data=model.selectedQueue.userUsagesDonutChartData
title="User Usages"
showLabels=true
parentId="userusage-donut-chart"
type="memory"
ratio=0.6
maxHeight=350}}
</div>
{{/if}}
<div class="col-lg-4 container-fluid">
<div class="panel panel-default">
<div class="panel-heading">
Running Apps
</div>
<div class="container-fluid" id="numapplications-donut-chart">
{{donut-chart data=model.selectedQueue.numOfApplicationsDonutChartData
showLabels=true
parentId="numapplications-donut-chart"
ratio=0.6
maxHeight=350}}
</div>
</div>
</div>
</div>
{{outlet}}
</div>
</div>
</div>
{{outlet}}

View File

@ -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.
}}
<div class="row">
<div class="col-lg-12 container-fluid">
{{#if model.apps}}
{{app-table table-id="apps-table" arr=model.apps}}
{{simple-table table-id="apps-table" bFilter=true colTypes="elapsed-time" colTargets="7"}}
{{else}}
<h4 align = "center">Could not find any applications from this cluster</h4>
{{/if}}
</div>
</div>

View File

@ -0,0 +1,84 @@
{{!
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
}}
<div class="row">
<div class="col-lg-6 container-fluid">
<div class="panel panel-default">
<div class="panel-heading">
Queue Capacities: {{model.selected}}
</div>
<div class="container-fluid" id="capacity-bar-chart">
<br/>
{{bar-chart data=model.selectedQueue.capacitiesBarChartData
title=""
parentId="capacity-bar-chart"
textWidth=170
ratio=0.55
maxHeight=350}}
</div>
</div>
</div>
<div class="col-lg-6 container-fluid">
<div class="panel panel-default">
<div class="panel-heading">
Queue Information: {{model.selected}}
</div>
{{queue-configuration-table queue=model.selectedQueue}}
</div>
</div>
</div>
<div class="row">
<div class="col-lg-6 container-fluid">
<div class="panel panel-default">
<div class="panel-heading">
Running Apps: {{model.selected}}
</div>
<div class="container-fluid" id="numapplications-donut-chart">
{{donut-chart data=model.selectedQueue.numOfApplicationsDonutChartData
showLabels=true
parentId="numapplications-donut-chart"
ratio=0.6
maxHeight=350}}
</div>
</div>
</div>
{{#if model.selectedQueue.hasUserUsages}}
<div class="col-lg-6 container-fluid">
<div class="panel panel-default">
<div class="panel-heading">
User Usages: {{model.selected}}
</div>
<div class="container-fluid" id="userusage-donut-chart">
{{donut-chart data=model.selectedQueue.userUsagesDonutChartData
showLabels=true
parentId="userusage-donut-chart"
type="memory"
ratio=0.6
maxHeight=350}}
</div>
</div>
</div>
{{/if}}
</div>

View File

@ -26,7 +26,7 @@
<div class="col-lg-4 container-fluid">
<div class="panel panel-default">
<div class="panel-heading">
Queue Information
Queue Information: {{model.selected}}
</div>
{{queue-configuration-table queue=model.selectedQueue}}
</div>
@ -35,7 +35,7 @@
<div class="col-lg-4 container-fluid">
<div class="panel panel-default">
<div class="panel-heading">
Queue Capacities
Queue Capacities: {{model.selected}}
</div>
<div class="container-fluid" id="capacity-bar-chart">
<br/>
@ -52,7 +52,7 @@
<div class="col-lg-4 container-fluid">
<div class="panel panel-default">
<div class="panel-heading">
Running Apps
Running Apps: {{model.selected}}
</div>
<div class="container-fluid" id="numapplications-donut-chart">
{{donut-chart data=model.selectedQueue.numOfApplicationsDonutChartData

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

View File

@ -18,7 +18,7 @@
import { moduleFor, test } from 'ember-qunit';
moduleFor('route:yarn-queue-apps', 'Unit | Route | yarn queue apps', {
moduleFor('route:yarn-queue/apps', 'Unit | Route | yarn queue/apps', {
// Specify the other units that are required for this test.
// needs: ['controller:foo']
});

View File

@ -18,13 +18,12 @@
import { moduleFor, test } from 'ember-qunit';
moduleFor('controller:yarn-queue-apps', 'Unit | Controller | yarn queue apps', {
moduleFor('route:yarn-queue/info', 'Unit | Route | yarn queue/info', {
// Specify the other units that are required for this test.
// needs: ['controller:foo']
});
// Replace this with your real tests.
test('it exists', function(assert) {
let controller = this.subject();
assert.ok(controller);
let route = this.subject();
assert.ok(route);
});