From f1c9cafefc1940211b9fa0b77d2997ddb589af4e Mon Sep 17 00:00:00 2001 From: Sunil G Date: Wed, 22 Feb 2017 11:54:32 +0530 Subject: [PATCH] YARN-6184. Introduce loading icon in each page of new YARN UI. Contributed by Akhil PB. --- .../webapp/app/components/tree-selector.js | 8 +- .../main/webapp/app/controllers/yarn-queue.js | 17 +++- .../webapp/app/controllers/yarn-queues.js | 1 + .../src/main/webapp/app/router.js | 6 +- .../webapp/app/routes/cluster-overview.js | 4 +- .../webapp/app/routes/yarn-app-attempt.js | 12 +-- .../src/main/webapp/app/routes/yarn-apps.js | 4 +- .../src/main/webapp/app/routes/yarn-node.js | 4 +- .../src/main/webapp/app/routes/yarn-nodes.js | 4 +- .../src/main/webapp/app/routes/yarn-queue.js | 3 +- .../yarn-queue/apps.js} | 26 +----- .../info.js} | 22 +---- .../src/main/webapp/app/routes/yarn-queues.js | 35 +++++++- .../src/main/webapp/app/styles/app.css | 8 ++ .../src/main/webapp/app/templates/loading.hbs | 23 +++++ .../app/templates/yarn-apps/loading.hbs | 23 +++++ .../webapp/app/templates/yarn-queue-apps.hbs | 64 ------------- .../main/webapp/app/templates/yarn-queue.hbs | 69 ++------------ .../webapp/app/templates/yarn-queue/apps.hbs | 28 ++++++ .../webapp/app/templates/yarn-queue/info.hbs | 84 ++++++++++++++++++ .../main/webapp/app/templates/yarn-queues.hbs | 8 +- .../webapp/public/assets/images/spinner.gif | Bin 0 -> 33076 bytes .../apps-test.js} | 2 +- .../yarn-queue/info-test.js} | 7 +- 24 files changed, 251 insertions(+), 211 deletions(-) rename hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/{controllers/yarn-queue-apps.js => routes/yarn-queue/apps.js} (62%) rename hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/routes/{yarn-queue-apps.js => yarn-queue/info.js} (60%) create mode 100644 hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/templates/loading.hbs create mode 100644 hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/templates/yarn-apps/loading.hbs delete mode 100644 hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/templates/yarn-queue-apps.hbs create mode 100644 hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/templates/yarn-queue/apps.hbs create mode 100644 hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/templates/yarn-queue/info.hbs create mode 100644 hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/public/assets/images/spinner.gif rename hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/tests/unit/routes/{yarn-queue-apps-test.js => yarn-queue/apps-test.js} (94%) rename hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/tests/unit/{controllers/yarn-queue-apps-test.js => routes/yarn-queue/info-test.js} (84%) diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/components/tree-selector.js b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/components/tree-selector.js index c9e735dee5d..3d72b2fbbf7 100644 --- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/components/tree-selector.js +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/components/tree-selector.js @@ -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") @@ -190,7 +190,7 @@ export default Ember.Component.extend({ nodeUpdate.select("circle") .attr("r", 30) - .attr("href", + .attr("href", function(d) { return "#/yarn-queues/" + d.queueData.get("name"); }) @@ -294,4 +294,4 @@ export default Ember.Component.extend({ didInsertElement: function() { this.reDraw(); } -}); \ No newline at end of file +}); diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/controllers/yarn-queue.js b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/controllers/yarn-queue.js index 0b4150fce46..3a72b606fef 100644 --- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/controllers/yarn-queue.js +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/controllers/yarn-queue.js @@ -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; + }) }); diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/controllers/yarn-queues.js b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/controllers/yarn-queues.js index 941e150121b..9658ded0ca2 100644 --- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/controllers/yarn-queues.js +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/controllers/yarn-queues.js @@ -21,6 +21,7 @@ import Ember from 'ember'; export default Ember.Controller.extend({ needReload: true, selectedQueue: undefined, + showLoading: true, breadcrumbs: [{ text: "Home", diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/router.js b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/router.js index 87a018d38e5..03ec7808424 100644 --- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/router.js +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/router.js @@ -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; diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/routes/cluster-overview.js b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/routes/cluster-overview.js index 10681265b84..b5db17db051 100644 --- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/routes/cluster-overview.js +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/routes/cluster-overview.js @@ -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" @@ -41,4 +41,4 @@ export default AbstractRoute.extend({ this.store.unloadAll('yarn-app'); this.store.unloadAll('yarn-queue'); } -}); \ No newline at end of file +}); diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/routes/yarn-app-attempt.js b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/routes/yarn-app-attempt.js index 762fb2908bb..d449adf2ade 100644 --- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/routes/yarn-app-attempt.js +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/routes/yarn-app-attempt.js @@ -23,15 +23,15 @@ 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), - - rmContainers: this.store.query('yarn-container', + attempt: this.store.findRecord('yarn-app-attempt', param.app_attempt_id, {reload: true}), + + rmContainers: this.store.query('yarn-container', { app_attempt_id: param.app_attempt_id, is_rm: true }), - - tsContainers: this.store.query('yarn-container', + + tsContainers: this.store.query('yarn-container', { app_attempt_id: param.app_attempt_id, is_rm: false @@ -47,4 +47,4 @@ export default AbstractRoute.extend({ this.store.unloadAll('yarn-app-attempt'); this.store.unloadAll('yarn-container'); } -}); \ No newline at end of file +}); diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/routes/yarn-apps.js b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/routes/yarn-apps.js index 0ac503cd6d2..1b671dae742 100644 --- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/routes/yarn-apps.js +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/routes/yarn-apps.js @@ -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}), }); }, diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/routes/yarn-node.js b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/routes/yarn-node.js index 967d007ef95..3d548460d4f 100644 --- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/routes/yarn-node.js +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/routes/yarn-node.js @@ -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}) }); }, diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/routes/yarn-nodes.js b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/routes/yarn-nodes.js index 4439569c3df..d31eb5c6bfc 100644 --- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/routes/yarn-nodes.js +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/routes/yarn-nodes.js @@ -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}), }); }, diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/routes/yarn-queue.js b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/routes/yarn-queue.js index 534291333a0..faae8b12fa5 100644 --- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/routes/yarn-queue.js +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/routes/yarn-queue.js @@ -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() { diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/controllers/yarn-queue-apps.js b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/routes/yarn-queue/apps.js similarity index 62% rename from hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/controllers/yarn-queue-apps.js rename to hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/routes/yarn-queue/apps.js index e7bedd64390..871917068fd 100644 --- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/controllers/yarn-queue-apps.js +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/routes/yarn-queue/apps.js @@ -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({ }); diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/routes/yarn-queue-apps.js b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/routes/yarn-queue/info.js similarity index 60% rename from hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/routes/yarn-queue-apps.js rename to hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/routes/yarn-queue/info.js index 373e1bebc0d..871917068fd 100644 --- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/routes/yarn-queue-apps.js +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/routes/yarn-queue/info.js @@ -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({ }); diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/routes/yarn-queues.js b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/routes/yarn-queues.js index 534291333a0..7ef7ac358f9 100644 --- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/routes/yarn-queues.js +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/routes/yarn-queues.js @@ -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; + } } }); diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/styles/app.css b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/styles/app.css index eb5fe613744..7ac21bcfe68 100644 --- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/styles/app.css +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/styles/app.css @@ -137,6 +137,14 @@ div.tooltip { pointer-events: none; } +/* + * Loading icon styles + */ +.loading-mask > img { + display: block; + margin: 0 auto; +} + /* * Data table */ diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/templates/loading.hbs b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/templates/loading.hbs new file mode 100644 index 00000000000..a95af2bdb39 --- /dev/null +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/templates/loading.hbs @@ -0,0 +1,23 @@ +{{! + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. +}} + +
+
+ Loading... +
+
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/templates/yarn-apps/loading.hbs b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/templates/yarn-apps/loading.hbs new file mode 100644 index 00000000000..a95af2bdb39 --- /dev/null +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/templates/yarn-apps/loading.hbs @@ -0,0 +1,23 @@ +{{! + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. +}} + +
+
+ Loading... +
+
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/templates/yarn-queue-apps.hbs b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/templates/yarn-queue-apps.hbs deleted file mode 100644 index d5329f26205..00000000000 --- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/templates/yarn-queue-apps.hbs +++ /dev/null @@ -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}} - -
-
- -
-
-
-

Application

-
-
- -
-
-
- -
- -
- -
- {{#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}} -

Could not find any applications from this cluster

- {{/if}} -
- -
-
- -
-
-{{outlet}} diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/templates/yarn-queue.hbs b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/templates/yarn-queue.hbs index 11c527c06bd..ef2d285de8a 100644 --- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/templates/yarn-queue.hbs +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/templates/yarn-queue.hbs @@ -24,17 +24,17 @@
-

Application

+

Queue

- -
- -
-
-
- Queue Information -
- {{queue-configuration-table queue=model.selectedQueue}} -
-
- -
-
-
- Queue Capacities -
-
-
- {{bar-chart data=model.selectedQueue.capacitiesBarChartData - title="" - parentId="capacity-bar-chart" - textWidth=170 - ratio=0.55 - maxHeight=350}} -
-
-
- - {{#if model.selectedQueue.hasUserUsages}} -
- {{donut-chart data=model.selectedQueue.userUsagesDonutChartData - title="User Usages" - showLabels=true - parentId="userusage-donut-chart" - type="memory" - ratio=0.6 - maxHeight=350}} -
- {{/if}} - -
-
-
- Running Apps -
-
- {{donut-chart data=model.selectedQueue.numOfApplicationsDonutChartData - showLabels=true - parentId="numapplications-donut-chart" - ratio=0.6 - maxHeight=350}} -
-
-
- -
+ {{outlet}}
-{{outlet}} diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/templates/yarn-queue/apps.hbs b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/templates/yarn-queue/apps.hbs new file mode 100644 index 00000000000..6d6488fb886 --- /dev/null +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/templates/yarn-queue/apps.hbs @@ -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. +}} + +
+
+ {{#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}} +

Could not find any applications from this cluster

+ {{/if}} +
+
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/templates/yarn-queue/info.hbs b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/templates/yarn-queue/info.hbs new file mode 100644 index 00000000000..c112ef9b3df --- /dev/null +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/templates/yarn-queue/info.hbs @@ -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. +}} + +
+ +
+
+
+ Queue Capacities: {{model.selected}} +
+
+
+ {{bar-chart data=model.selectedQueue.capacitiesBarChartData + title="" + parentId="capacity-bar-chart" + textWidth=170 + ratio=0.55 + maxHeight=350}} +
+
+
+ +
+
+
+ Queue Information: {{model.selected}} +
+ {{queue-configuration-table queue=model.selectedQueue}} +
+
+ +
+ +
+ +
+
+
+ Running Apps: {{model.selected}} +
+
+ {{donut-chart data=model.selectedQueue.numOfApplicationsDonutChartData + showLabels=true + parentId="numapplications-donut-chart" + ratio=0.6 + maxHeight=350}} +
+
+
+ + {{#if model.selectedQueue.hasUserUsages}} +
+
+
+ User Usages: {{model.selected}} +
+
+ {{donut-chart data=model.selectedQueue.userUsagesDonutChartData + showLabels=true + parentId="userusage-donut-chart" + type="memory" + ratio=0.6 + maxHeight=350}} +
+
+
+ {{/if}} + +
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/templates/yarn-queues.hbs b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/templates/yarn-queues.hbs index ea9338cce4d..6dfb22014eb 100644 --- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/templates/yarn-queues.hbs +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/templates/yarn-queues.hbs @@ -26,7 +26,7 @@
- Queue Information + Queue Information: {{model.selected}}
{{queue-configuration-table queue=model.selectedQueue}}
@@ -35,7 +35,7 @@
- Queue Capacities + Queue Capacities: {{model.selected}}

@@ -52,7 +52,7 @@
- Running Apps + Running Apps: {{model.selected}}
{{donut-chart data=model.selectedQueue.numOfApplicationsDonutChartData @@ -67,4 +67,4 @@
-{{outlet}} \ No newline at end of file +{{outlet}} diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/public/assets/images/spinner.gif b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/public/assets/images/spinner.gif new file mode 100644 index 0000000000000000000000000000000000000000..727b91d1761e22e0d5191097e4ea6610ee60a2cc GIT binary patch literal 33076 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 KFd72GI|Kj(^~e